nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * This code is derived from code formerly in pcap-dlpi.c, originally |
||
3 | * contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), University College |
||
4 | * London, and subsequently modified by Guy Harris (guy@alum.mit.edu), |
||
5 | * Mark Pizzolato <List-tcpdump-workers@subscriptions.pizzolato.net>, |
||
6 | * Mark C. Brown (mbrown@hp.com), and Sagun Shakya <Sagun.Shakya@Sun.COM>. |
||
7 | */ |
||
8 | |||
9 | /* |
||
10 | * This file contains dlpi/libdlpi related common functions used |
||
11 | * by pcap-[dlpi,libdlpi].c. |
||
12 | */ |
||
13 | |||
14 | #ifdef HAVE_CONFIG_H |
||
15 | #include "config.h" |
||
16 | #endif |
||
17 | |||
18 | #ifndef DL_IPATM |
||
19 | #define DL_IPATM 0x12 /* ATM Classical IP interface */ |
||
20 | #endif |
||
21 | |||
22 | #ifdef HAVE_SYS_BUFMOD_H |
||
23 | /* |
||
24 | * Size of a bufmod chunk to pass upstream; that appears to be the |
||
25 | * biggest value to which you can set it, and setting it to that value |
||
26 | * (which is bigger than what appears to be the Solaris default of 8192) |
||
27 | * reduces the number of packet drops. |
||
28 | */ |
||
29 | #define CHUNKSIZE 65536 |
||
30 | |||
31 | /* |
||
32 | * Size of the buffer to allocate for packet data we read; it must be |
||
33 | * large enough to hold a chunk. |
||
34 | */ |
||
35 | #define PKTBUFSIZE CHUNKSIZE |
||
36 | |||
37 | #else /* HAVE_SYS_BUFMOD_H */ |
||
38 | |||
39 | /* |
||
40 | * Size of the buffer to allocate for packet data we read; this is |
||
41 | * what the value used to be - there's no particular reason why it |
||
42 | * should be tied to MAXDLBUF, but we'll leave it as this for now. |
||
43 | */ |
||
44 | #define MAXDLBUF 8192 |
||
45 | #define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) |
||
46 | |||
47 | #endif |
||
48 | |||
49 | #include <sys/types.h> |
||
50 | #include <sys/time.h> |
||
51 | #ifdef HAVE_SYS_BUFMOD_H |
||
52 | #include <sys/bufmod.h> |
||
53 | #endif |
||
54 | #include <sys/dlpi.h> |
||
55 | #include <sys/stream.h> |
||
56 | |||
57 | #include <errno.h> |
||
58 | #include <memory.h> |
||
59 | #include <stdio.h> |
||
60 | #include <stdlib.h> |
||
61 | #include <string.h> |
||
62 | #include <stropts.h> |
||
63 | #include <unistd.h> |
||
64 | |||
65 | #ifdef HAVE_LIBDLPI |
||
66 | #include <libdlpi.h> |
||
67 | #endif |
||
68 | |||
69 | #include "pcap-int.h" |
||
70 | #include "dlpisubs.h" |
||
71 | |||
72 | #ifdef HAVE_SYS_BUFMOD_H |
||
73 | static void pcap_stream_err(const char *, int, char *); |
||
74 | #endif |
||
75 | |||
76 | /* |
||
77 | * Get the packet statistics. |
||
78 | */ |
||
79 | int |
||
80 | pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) |
||
81 | { |
||
82 | struct pcap_dlpi *pd = p->priv; |
||
83 | |||
84 | /* |
||
85 | * "ps_recv" counts packets handed to the filter, not packets |
||
86 | * that passed the filter. As filtering is done in userland, |
||
87 | * this would not include packets dropped because we ran out |
||
88 | * of buffer space; in order to make this more like other |
||
89 | * platforms (Linux 2.4 and later, BSDs with BPF), where the |
||
90 | * "packets received" count includes packets received but dropped |
||
91 | * due to running out of buffer space, and to keep from confusing |
||
92 | * applications that, for example, compute packet drop percentages, |
||
93 | * we also make it count packets dropped by "bufmod" (otherwise we |
||
94 | * might run the risk of the packet drop count being bigger than |
||
95 | * the received-packet count). |
||
96 | * |
||
97 | * "ps_drop" counts packets dropped by "bufmod" because of |
||
98 | * flow control requirements or resource exhaustion; it doesn't |
||
99 | * count packets dropped by the interface driver, or packets |
||
100 | * dropped upstream. As filtering is done in userland, it counts |
||
101 | * packets regardless of whether they would've passed the filter. |
||
102 | * |
||
103 | * These statistics don't include packets not yet read from |
||
104 | * the kernel by libpcap, but they may include packets not |
||
105 | * yet read from libpcap by the application. |
||
106 | */ |
||
107 | *ps = pd->stat; |
||
108 | |||
109 | /* |
||
110 | * Add in the drop count, as per the above comment. |
||
111 | */ |
||
112 | ps->ps_recv += ps->ps_drop; |
||
113 | return (0); |
||
114 | } |
||
115 | |||
116 | /* |
||
117 | * Loop through the packets and call the callback for each packet. |
||
118 | * Return the number of packets read. |
||
119 | */ |
||
120 | int |
||
121 | pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, |
||
122 | int count, u_char *bufp, int len) |
||
123 | { |
||
124 | struct pcap_dlpi *pd = p->priv; |
||
125 | int n, caplen, origlen; |
||
126 | u_char *ep, *pk; |
||
127 | struct pcap_pkthdr pkthdr; |
||
128 | #ifdef HAVE_SYS_BUFMOD_H |
||
129 | struct sb_hdr *sbp; |
||
130 | #ifdef LBL_ALIGN |
||
131 | struct sb_hdr sbhdr; |
||
132 | #endif |
||
133 | #endif |
||
134 | |||
135 | /* Loop through packets */ |
||
136 | ep = bufp + len; |
||
137 | n = 0; |
||
138 | |||
139 | #ifdef HAVE_SYS_BUFMOD_H |
||
140 | while (bufp < ep) { |
||
141 | /* |
||
142 | * Has "pcap_breakloop()" been called? |
||
143 | * If so, return immediately - if we haven't read any |
||
144 | * packets, clear the flag and return -2 to indicate |
||
145 | * that we were told to break out of the loop, otherwise |
||
146 | * leave the flag set, so that the *next* call will break |
||
147 | * out of the loop without having read any packets, and |
||
148 | * return the number of packets we've processed so far. |
||
149 | */ |
||
150 | if (p->break_loop) { |
||
151 | if (n == 0) { |
||
152 | p->break_loop = 0; |
||
153 | return (-2); |
||
154 | } else { |
||
155 | p->bp = bufp; |
||
156 | p->cc = ep - bufp; |
||
157 | return (n); |
||
158 | } |
||
159 | } |
||
160 | #ifdef LBL_ALIGN |
||
161 | if ((long)bufp & 3) { |
||
162 | sbp = &sbhdr; |
||
163 | memcpy(sbp, bufp, sizeof(*sbp)); |
||
164 | } else |
||
165 | #endif |
||
166 | sbp = (struct sb_hdr *)bufp; |
||
167 | pd->stat.ps_drop = sbp->sbh_drops; |
||
168 | pk = bufp + sizeof(*sbp); |
||
169 | bufp += sbp->sbh_totlen; |
||
170 | origlen = sbp->sbh_origlen; |
||
171 | caplen = sbp->sbh_msglen; |
||
172 | #else |
||
173 | origlen = len; |
||
174 | caplen = min(p->snapshot, len); |
||
175 | pk = bufp; |
||
176 | bufp += caplen; |
||
177 | #endif |
||
178 | ++pd->stat.ps_recv; |
||
179 | if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) { |
||
180 | #ifdef HAVE_SYS_BUFMOD_H |
||
181 | pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; |
||
182 | pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; |
||
183 | #else |
||
184 | (void) gettimeofday(&pkthdr.ts, NULL); |
||
185 | #endif |
||
186 | pkthdr.len = origlen; |
||
187 | pkthdr.caplen = caplen; |
||
188 | /* Insure caplen does not exceed snapshot */ |
||
189 | if (pkthdr.caplen > p->snapshot) |
||
190 | pkthdr.caplen = p->snapshot; |
||
191 | (*callback)(user, &pkthdr, pk); |
||
192 | if (++n >= count && !PACKET_COUNT_IS_UNLIMITED(count)) { |
||
193 | p->cc = ep - bufp; |
||
194 | p->bp = bufp; |
||
195 | return (n); |
||
196 | } |
||
197 | } |
||
198 | #ifdef HAVE_SYS_BUFMOD_H |
||
199 | } |
||
200 | #endif |
||
201 | p->cc = 0; |
||
202 | return (n); |
||
203 | } |
||
204 | |||
205 | /* |
||
206 | * Process the mac type. Returns -1 if no matching mac type found, otherwise 0. |
||
207 | */ |
||
208 | int |
||
209 | pcap_process_mactype(pcap_t *p, u_int mactype) |
||
210 | { |
||
211 | int retv = 0; |
||
212 | |||
213 | switch (mactype) { |
||
214 | |||
215 | case DL_CSMACD: |
||
216 | case DL_ETHER: |
||
217 | p->linktype = DLT_EN10MB; |
||
218 | p->offset = 2; |
||
219 | /* |
||
220 | * This is (presumably) a real Ethernet capture; give it a |
||
221 | * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so |
||
222 | * that an application can let you choose it, in case you're |
||
223 | * capturing DOCSIS traffic that a Cisco Cable Modem |
||
224 | * Termination System is putting out onto an Ethernet (it |
||
225 | * doesn't put an Ethernet header onto the wire, it puts raw |
||
226 | * DOCSIS frames out on the wire inside the low-level |
||
227 | * Ethernet framing). |
||
228 | */ |
||
229 | p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2); |
||
230 | /* |
||
231 | * If that fails, just leave the list empty. |
||
232 | */ |
||
233 | if (p->dlt_list != NULL) { |
||
234 | p->dlt_list[0] = DLT_EN10MB; |
||
235 | p->dlt_list[1] = DLT_DOCSIS; |
||
236 | p->dlt_count = 2; |
||
237 | } |
||
238 | break; |
||
239 | |||
240 | case DL_FDDI: |
||
241 | p->linktype = DLT_FDDI; |
||
242 | p->offset = 3; |
||
243 | break; |
||
244 | |||
245 | case DL_TPR: |
||
246 | /* XXX - what about DL_TPB? Is that Token Bus? */ |
||
247 | p->linktype = DLT_IEEE802; |
||
248 | p->offset = 2; |
||
249 | break; |
||
250 | |||
251 | #ifdef HAVE_SOLARIS |
||
252 | case DL_IPATM: |
||
253 | p->linktype = DLT_SUNATM; |
||
254 | p->offset = 0; /* works for LANE and LLC encapsulation */ |
||
255 | break; |
||
256 | #endif |
||
257 | |||
258 | default: |
||
259 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype %u", |
||
260 | mactype); |
||
261 | retv = -1; |
||
262 | } |
||
263 | |||
264 | return (retv); |
||
265 | } |
||
266 | |||
267 | #ifdef HAVE_SYS_BUFMOD_H |
||
268 | /* |
||
269 | * Push and configure the buffer module. Returns -1 for error, otherwise 0. |
||
270 | */ |
||
271 | int |
||
272 | pcap_conf_bufmod(pcap_t *p, int snaplen) |
||
273 | { |
||
274 | struct timeval to; |
||
275 | bpf_u_int32 ss, chunksize; |
||
276 | |||
277 | /* Non-standard call to get the data nicely buffered. */ |
||
278 | if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { |
||
279 | pcap_stream_err("I_PUSH bufmod", errno, p->errbuf); |
||
280 | return (-1); |
||
281 | } |
||
282 | |||
283 | ss = snaplen; |
||
284 | if (ss > 0 && |
||
285 | strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { |
||
286 | pcap_stream_err("SBIOCSSNAP", errno, p->errbuf); |
||
287 | return (-1); |
||
288 | } |
||
289 | |||
290 | if (p->opt.immediate) { |
||
291 | /* Set the timeout to zero, for immediate delivery. */ |
||
292 | to.tv_sec = 0; |
||
293 | to.tv_usec = 0; |
||
294 | if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { |
||
295 | pcap_stream_err("SBIOCSTIME", errno, p->errbuf); |
||
296 | return (-1); |
||
297 | } |
||
298 | } else { |
||
299 | /* Set up the bufmod timeout. */ |
||
300 | if (p->opt.timeout != 0) { |
||
301 | to.tv_sec = p->opt.timeout / 1000; |
||
302 | to.tv_usec = (p->opt.timeout * 1000) % 1000000; |
||
303 | if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { |
||
304 | pcap_stream_err("SBIOCSTIME", errno, p->errbuf); |
||
305 | return (-1); |
||
306 | } |
||
307 | } |
||
308 | |||
309 | /* Set the chunk length. */ |
||
310 | chunksize = CHUNKSIZE; |
||
311 | if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) |
||
312 | != 0) { |
||
313 | pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf); |
||
314 | return (-1); |
||
315 | } |
||
316 | } |
||
317 | |||
318 | return (0); |
||
319 | } |
||
320 | #endif /* HAVE_SYS_BUFMOD_H */ |
||
321 | |||
322 | /* |
||
323 | * Allocate data buffer. Returns -1 if memory allocation fails, else 0. |
||
324 | */ |
||
325 | int |
||
326 | pcap_alloc_databuf(pcap_t *p) |
||
327 | { |
||
328 | p->bufsize = PKTBUFSIZE; |
||
329 | p->buffer = (u_char *)malloc(p->bufsize + p->offset); |
||
330 | if (p->buffer == NULL) { |
||
331 | strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); |
||
332 | return (-1); |
||
333 | } |
||
334 | |||
335 | return (0); |
||
336 | } |
||
337 | |||
338 | /* |
||
339 | * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise |
||
340 | * length of returned data on success. |
||
341 | */ |
||
342 | int |
||
343 | strioctl(int fd, int cmd, int len, char *dp) |
||
344 | { |
||
345 | struct strioctl str; |
||
346 | int retv; |
||
347 | |||
348 | str.ic_cmd = cmd; |
||
349 | str.ic_timout = -1; |
||
350 | str.ic_len = len; |
||
351 | str.ic_dp = dp; |
||
352 | if ((retv = ioctl(fd, I_STR, &str)) < 0) |
||
353 | return (retv); |
||
354 | |||
355 | return (str.ic_len); |
||
356 | } |
||
357 | |||
358 | #ifdef HAVE_SYS_BUFMOD_H |
||
359 | /* |
||
360 | * Write stream error message to errbuf. |
||
361 | */ |
||
362 | static void |
||
363 | pcap_stream_err(const char *func, int err, char *errbuf) |
||
364 | { |
||
365 | snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", func, pcap_strerror(err)); |
||
366 | } |
||
367 | #endif |