Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 348 lines (304 sloc) 8.786 kb
b11ddf8 Initial revision
mcr authored
1 /*
2 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
3 * The Regents of the University of California. 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
30e89f1 @yuguy Add _U_ to "rcsid[]" definitions, to eliminate "unused variable"
yuguy authored
22 static const char rcsid[] _U_ =
2527d1a @yuguy Turn close_op into cleanup_op; the routine that handles it can also be
yuguy authored
23 "@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.62 2008-04-14 20:40:58 guy Exp $ (LBL)";
0e2f8c8 add config.h, remove gnuc.h. remove __dead
assar authored
24 #endif
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
b11ddf8 Initial revision
mcr authored
28 #endif
29
30 #include <sys/types.h>
31 #include <sys/time.h>
32 #include <sys/timeb.h>
33 #include <sys/file.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36
37 #include <net/if.h>
38 #include <net/nit.h>
39
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
50 #include <ctype.h>
51 #include <errno.h>
52 #include <stdio.h>
53
54 #include "pcap-int.h"
55
56 #ifdef HAVE_OS_PROTO_H
57 #include "os-proto.h"
58 #endif
59
60 /*
61 * The chunk size for NIT. This is the amount of buffering
62 * done for read calls.
63 */
64 #define CHUNKSIZE (2*1024)
65
66 /*
67 * The total buffer space used by NIT.
68 */
69 #define BUFSPACE (4*CHUNKSIZE)
70
71 /* Forwards */
72 static int nit_setflags(int, int, int, char *);
73
9792990 @yuguy Add a "stats" function pointer to the pcap_t structure, which handles
yuguy authored
74 static int
75 pcap_stats_nit(pcap_t *p, struct pcap_stat *ps)
b11ddf8 Initial revision
mcr authored
76 {
77
11c1cf8 @yuguy Add comments to "pcap_stats()" indicating what the counters mean on the
yuguy authored
78 /*
79 * "ps_recv" counts packets handed to the filter, not packets
efc02fd @yuguy Put more information into the comments for "pcap_stats()".
yuguy authored
80 * that passed the filter. As filtering is done in userland,
81 * this does not include packets dropped because we ran out
82 * of buffer space.
11c1cf8 @yuguy Add comments to "pcap_stats()" indicating what the counters mean on the
yuguy authored
83 *
84 * "ps_drop" presumably counts packets dropped by the socket
85 * because of flow control requirements or resource exhaustion;
86 * it doesn't count packets dropped by the interface driver.
87 * As filtering is done in userland, it counts packets regardless
88 * of whether they would've passed the filter.
efc02fd @yuguy Put more information into the comments for "pcap_stats()".
yuguy authored
89 *
90 * These statistics don't include packets not yet read from the
91 * kernel by libpcap or packets not yet read from libpcap by the
92 * application.
11c1cf8 @yuguy Add comments to "pcap_stats()" indicating what the counters mean on the
yuguy authored
93 */
b11ddf8 Initial revision
mcr authored
94 *ps = p->md.stat;
95 return (0);
96 }
97
cd0d893 @yuguy Add a "read" function pointer to the pcap_t structure, which handles
yuguy authored
98 static int
99 pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
b11ddf8 Initial revision
mcr authored
100 {
101 register int cc, n;
102 register u_char *bp, *cp, *ep;
103 register struct nit_hdr *nh;
104 register int caplen;
105
106 cc = p->cc;
107 if (cc == 0) {
108 cc = read(p->fd, (char *)p->buffer, p->bufsize);
109 if (cc < 0) {
110 if (errno == EWOULDBLOCK)
111 return (0);
20d9e08 do not use sprintf(). always use snprintf().
itojun authored
112 snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s",
b11ddf8 Initial revision
mcr authored
113 pcap_strerror(errno));
114 return (-1);
115 }
116 bp = p->buffer;
117 } else
118 bp = p->bp;
119
120 /*
121 * Loop through each packet. The increment expression
122 * rounds up to the next int boundary past the end of
123 * the previous packet.
124 */
125 n = 0;
126 ep = bp + cc;
127 while (bp < ep) {
991d444 @yuguy Add a "pcap_breakloop()" API to break out of the loop in
yuguy authored
128 /*
129 * Has "pcap_breakloop()" been called?
130 * If so, return immediately - if we haven't read any
131 * packets, clear the flag and return -2 to indicate
132 * that we were told to break out of the loop, otherwise
133 * leave the flag set, so that the *next* call will break
134 * out of the loop without having read any packets, and
135 * return the number of packets we've processed so far.
136 */
137 if (p->break_loop) {
138 if (n == 0) {
139 p->break_loop = 0;
140 return (-2);
141 } else {
142 p->cc = ep - bp;
143 p->bp = bp;
144 return (n);
145 }
146 }
147
b11ddf8 Initial revision
mcr authored
148 nh = (struct nit_hdr *)bp;
149 cp = bp + sizeof(*nh);
150
151 switch (nh->nh_state) {
152
153 case NIT_CATCH:
154 break;
155
156 case NIT_NOMBUF:
157 case NIT_NOCLUSTER:
158 case NIT_NOSPACE:
159 p->md.stat.ps_drop = nh->nh_dropped;
160 continue;
161
162 case NIT_SEQNO:
163 continue;
164
165 default:
20d9e08 do not use sprintf(). always use snprintf().
itojun authored
166 snprintf(p->errbuf, sizeof(p->errbuf),
167 "bad nit state %d", nh->nh_state);
b11ddf8 Initial revision
mcr authored
168 return (-1);
169 }
170 ++p->md.stat.ps_recv;
171 bp += ((sizeof(struct nit_hdr) + nh->nh_datalen +
172 sizeof(int) - 1) & ~(sizeof(int) - 1));
173
174 caplen = nh->nh_wirelen;
175 if (caplen > p->snapshot)
176 caplen = p->snapshot;
91326ea @yuguy Don't assume that p->fcode.bpf_insns remains unchanged while processing
yuguy authored
177 if (bpf_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) {
b11ddf8 Initial revision
mcr authored
178 struct pcap_pkthdr h;
179 h.ts = nh->nh_timestamp;
180 h.len = nh->nh_wirelen;
181 h.caplen = caplen;
182 (*callback)(user, &h, cp);
ee4fa22 @yuguy As is done in the loop in pcap-bpf.c, check for non-positive values of
yuguy authored
183 if (++n >= cnt && cnt > 0) {
b11ddf8 Initial revision
mcr authored
184 p->cc = ep - bp;
185 p->bp = bp;
186 return (n);
187 }
188 }
189 }
190 p->cc = 0;
191 return (n);
192 }
193
194 static int
2d2890d @yuguy Add support for sending packets; includes contributions from Mark
yuguy authored
195 pcap_inject_nit(pcap_t *p, const void *buf, size_t size)
196 {
197 struct sockaddr sa;
198 int ret;
199
200 memset(&sa, 0, sizeof(sa));
201 strncpy(sa.sa_data, device, sizeof(sa.sa_data));
202 ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa));
203 if (ret == -1) {
204 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
205 pcap_strerror(errno));
206 return (-1);
207 }
208 return (ret);
209 }
210
211 static int
b11ddf8 Initial revision
mcr authored
212 nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
213 {
214 struct nit_ioc nioc;
215
6dc5bf2 replace bzero with memset
assar authored
216 memset(&nioc, 0, sizeof(nioc));
b11ddf8 Initial revision
mcr authored
217 nioc.nioc_bufspace = BUFSPACE;
218 nioc.nioc_chunksize = CHUNKSIZE;
219 nioc.nioc_typetomatch = NT_ALLTYPES;
220 nioc.nioc_snaplen = p->snapshot;
221 nioc.nioc_bufalign = sizeof(int);
222 nioc.nioc_bufoffset = 0;
223
224 if (to_ms != 0) {
225 nioc.nioc_flags |= NF_TIMEOUT;
226 nioc.nioc_timeout.tv_sec = to_ms / 1000;
227 nioc.nioc_timeout.tv_usec = (to_ms * 1000) % 1000000;
228 }
229 if (promisc)
230 nioc.nioc_flags |= NF_PROMISC;
231
232 if (ioctl(fd, SIOCSNIT, &nioc) < 0) {
466c37a s/PCAP_ERRBUFF_SIZE/PCAP_ERRBUF_SIZE/ (fatal typo)
itojun authored
233 snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNIT: %s",
20d9e08 do not use sprintf(). always use snprintf().
itojun authored
234 pcap_strerror(errno));
b11ddf8 Initial revision
mcr authored
235 return (-1);
236 }
237 return (0);
238 }
239
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
240 static int
241 pcap_activate_nit(pcap_t *p)
b11ddf8 Initial revision
mcr authored
242 {
243 int fd;
244 struct sockaddr_nit snit;
245
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
246 if (p->opt.rfmon) {
247 /*
248 * No monitor mode on SunOS 3.x or earlier (no
249 * Wi-Fi *devices* for the hardware that supported
250 * them!).
251 */
252 return (PCAP_ERROR_RFMON_NOTSUP);
b11ddf8 Initial revision
mcr authored
253 }
254
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
255 if (p->snapshot < 96)
b11ddf8 Initial revision
mcr authored
256 /*
257 * NIT requires a snapshot length of at least 96.
258 */
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
259 p->snapshot = 96;
b11ddf8 Initial revision
mcr authored
260
6dc5bf2 replace bzero with memset
assar authored
261 memset(p, 0, sizeof(*p));
b11ddf8 Initial revision
mcr authored
262 p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
263 if (fd < 0) {
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
264 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
20d9e08 do not use sprintf(). always use snprintf().
itojun authored
265 "socket: %s", pcap_strerror(errno));
b11ddf8 Initial revision
mcr authored
266 goto bad;
267 }
268 snit.snit_family = AF_NIT;
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
269 (void)strncpy(snit.snit_ifname, p->opt.source, NITIFSIZ);
b11ddf8 Initial revision
mcr authored
270
271 if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
272 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
20d9e08 do not use sprintf(). always use snprintf().
itojun authored
273 "bind: %s: %s", snit.snit_ifname, pcap_strerror(errno));
b11ddf8 Initial revision
mcr authored
274 goto bad;
275 }
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
276 nit_setflags(p->fd, p->opt.promisc, p->md.timeout, p->errbuf);
b11ddf8 Initial revision
mcr authored
277
278 /*
279 * NIT supports only ethernets.
280 */
2c961ff @yuguy Get rid of the PCAP_ENCAP_ values - if an application uses them, that
yuguy authored
281 p->linktype = DLT_EN10MB;
b11ddf8 Initial revision
mcr authored
282
283 p->bufsize = BUFSPACE;
284 p->buffer = (u_char *)malloc(p->bufsize);
285 if (p->buffer == NULL) {
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
286 strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
2d2890d @yuguy Add support for sending packets; includes contributions from Mark
yuguy authored
287 goto bad;
288 }
289
290 /*
3380fa1 @yuguy Fix cut-and-pasteos; thanks to Darren Reed for finding them.
yuguy authored
291 * "p->fd" is a socket, so "select()" should work on it.
c98ffbc @yuguy Add a "pcap_get_selectable_fd()" API to get an FD on which you can do a
yuguy authored
292 */
293 p->selectable_fd = p->fd;
294
619a9fe @yuguy For devices that we have some reason to believe are real live Ethernet
yuguy authored
295 /*
296 * This is (presumably) a real Ethernet capture; give it a
297 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
298 * that an application can let you choose it, in case you're
299 * capturing DOCSIS traffic that a Cisco Cable Modem
300 * Termination System is putting out onto an Ethernet (it
301 * doesn't put an Ethernet header onto the wire, it puts raw
302 * DOCSIS frames out on the wire inside the low-level
303 * Ethernet framing).
304 */
305 p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
306 /*
307 * If that fails, just leave the list empty.
308 */
309 if (p->dlt_list != NULL) {
310 p->dlt_list[0] = DLT_EN10MB;
311 p->dlt_list[1] = DLT_DOCSIS;
312 p->dlt_count = 2;
313 }
314
cd0d893 @yuguy Add a "read" function pointer to the pcap_t structure, which handles
yuguy authored
315 p->read_op = pcap_read_nit;
2d2890d @yuguy Add support for sending packets; includes contributions from Mark
yuguy authored
316 p->inject_op = pcap_inject_nit;
cd2807e @yuguy Add a "setfilter" function pointer to the pcap_t structure, which
yuguy authored
317 p->setfilter_op = install_bpf_program; /* no kernel filtering */
e987a61 @yuguy From Pawel Pokrywka: add support for requesting that only received
yuguy authored
318 p->setdirection_op = NULL; /* Not implemented. */
08658f1 @yuguy Add a "set_datalink" function pointer to the pcap_t structure, whichhand...
yuguy authored
319 p->set_datalink_op = NULL; /* can't change data link type */
2c618b9 @yuguy Add "getnonblock" and "setnonblock" operations, and set the function
yuguy authored
320 p->getnonblock_op = pcap_getnonblock_fd;
321 p->setnonblock_op = pcap_setnonblock_fd;
9792990 @yuguy Add a "stats" function pointer to the pcap_t structure, which handles
yuguy authored
322 p->stats_op = pcap_stats_nit;
e648c9e @yuguy Add a "close" function pointer to the pcap_t structure, which handles
yuguy authored
323
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
324 return (0);
b11ddf8 Initial revision
mcr authored
325 bad:
71dac45 @guyharris If an activate routine fails, it needs to clean up the pcap_t, close
guyharris authored
326 pcap_cleanup_live_common(p);
d9b4202 @yuguy From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
yuguy authored
327 return (PCAP_ERROR);
328 }
329
330 pcap_t *
331 pcap_create(const char *device, char *ebuf)
332 {
333 pcap_t *p;
334
335 p = pcap_create_common(device, ebuf);
336 if (p == NULL)
337 return (NULL);
338
339 p->activate_op = pcap_activate_nit;
340 return (p);
b11ddf8 Initial revision
mcr authored
341 }
342
343 int
243b20e @yuguy Add SunATM support, based on code from Yen Yen Lim at North Dakota State
yuguy authored
344 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
345 {
346 return (0);
347 }
Something went wrong with that request. Please try again.