Branch data Line data Source code
1 : : // $Id: PktSrc.cc 6951 2009-12-04 22:23:28Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include <errno.h>
6 : : #include <sys/stat.h>
7 : :
8 : : #include "config.h"
9 : :
10 : : #include "util.h"
11 : : #include "PktSrc.h"
12 : : #include "Hash.h"
13 : : #include "Net.h"
14 : : #include "Sessions.h"
15 : :
16 : :
17 : : // ### This needs auto-confing.
18 : : #ifdef HAVE_PCAP_INT_H
19 : : #include <pcap-int.h>
20 : : #endif
21 : :
22 : : int snaplen = 8192; // really want "capture entire packet"
23 : :
24 : :
25 : 1 : PktSrc::PktSrc()
26 : : {
27 : 1 : interface = readfile = 0;
28 : 1 : data = last_data = 0;
29 : 1 : hdr_size = 0;
30 : 1 : datalink = 0;
31 : 1 : netmask = 0xffffff00;
32 : 1 : pd = 0;
33 : 1 : idle = false;
34 : :
35 : 1 : next_sync_point = 0;
36 : 1 : first_timestamp = current_timestamp = next_timestamp = 0.0;
37 : 1 : first_wallclock = current_wallclock = 0;
38 : :
39 : 1 : stats.received = stats.dropped = stats.link = 0;
40 : 1 : }
41 : :
42 : 0 : PktSrc::~PktSrc()
43 : : {
44 : 0 : Close();
45 : :
46 [ # # ][ # # ]: 0 : loop_over_list(program_list, i)
[ # # ]
47 [ # # ][ # # ]: 0 : delete program_list[i];
[ # # ]
48 : :
49 : : BPF_Program* code;
50 : 0 : IterCookie* cookie = filters.InitForIteration();
51 [ # # ][ # # ]: 0 : while ( (code = filters.NextEntry(cookie)) )
[ # # ]
52 [ # # ][ # # ]: 0 : delete code;
[ # # ]
53 : :
54 [ # # ][ # # ]: 0 : delete [] interface;
[ # # ]
55 [ # # ][ # # ]: 0 : delete [] readfile;
[ # # ]
56 [ # # ][ # # ]: 0 : }
[ # # ]
57 : :
58 : 1 : void PktSrc::GetFds(int* read, int* write, int* except)
59 : : {
60 [ - + ]: 1 : if ( pseudo_realtime )
61 : : {
62 : : // Select would give erroneous results. But we simulate it
63 : : // by setting idle accordingly.
64 : 0 : idle = CheckPseudoTime() == 0;
65 : 0 : return;
66 : : }
67 : :
68 [ + - ]: 1 : if ( selectable_fd >= 0 )
69 : 1 : *read = selectable_fd;
70 : : }
71 : :
72 : 21349 : int PktSrc::ExtractNextPacket()
73 : : {
74 : : // Don't return any packets if processing is suspended (except for the
75 : : // very first packet which we need to set up times).
76 [ - + ][ # # ]: 21349 : if ( net_is_processing_suspended() && first_timestamp )
[ - + ]
77 : : {
78 : 0 : idle = true;
79 : 0 : return 0;
80 : : }
81 : :
82 : 21349 : data = last_data = pcap_next(pd, &hdr);
83 : 21349 : next_timestamp = hdr.ts.tv_sec + double(hdr.ts.tv_usec) / 1e6;
84 : :
85 [ - + ]: 21349 : if ( pseudo_realtime )
86 : 0 : current_wallclock = current_time(true);
87 : :
88 [ + + ]: 21349 : if ( ! first_timestamp )
89 : 1 : first_timestamp = next_timestamp;
90 : :
91 : 21349 : idle = (data == 0);
92 : :
93 [ + + ]: 21349 : if ( data )
94 : 21347 : ++stats.received;
95 : :
96 : : // Source has gone dry. If it's a network interface, this just means
97 : : // it's timed out. If it's a file, though, then the file has been
98 : : // exhausted.
99 [ + + ][ + - ]: 21349 : if ( ! data && ! IsLive() )
[ + + ]
100 : : {
101 : 2 : closed = true;
102 : :
103 [ - + ][ # # ]: 2 : if ( pseudo_realtime && using_communication )
104 : : {
105 [ # # ]: 0 : if ( remote_trace_sync_interval )
106 : 0 : remote_serializer->SendFinalSyncPoint();
107 : : else
108 : 0 : remote_serializer->Terminate();
109 : : }
110 : : }
111 : :
112 : 21349 : return data != 0;
113 : : }
114 : :
115 : 21349 : double PktSrc::NextTimestamp(double* local_network_time)
116 : : {
117 [ + - ][ + + ]: 21349 : if ( ! data && ! ExtractNextPacket() )
[ + + ]
118 : 2 : return -1.0;
119 : :
120 [ - + ]: 21347 : if ( pseudo_realtime )
121 : : {
122 : : // Delay packet if necessary.
123 : 0 : double packet_time = CheckPseudoTime();
124 [ # # ]: 0 : if ( packet_time )
125 : 0 : return packet_time;
126 : :
127 : 0 : idle = true;
128 : 0 : return -1.0;
129 : : }
130 : :
131 : 21349 : return next_timestamp;
132 : : }
133 : :
134 : 0 : void PktSrc::ContinueAfterSuspend()
135 : : {
136 : 0 : current_wallclock = current_time(true);
137 : 0 : }
138 : :
139 : 0 : double PktSrc::CurrentPacketWallClock()
140 : : {
141 : : // We stop time when we are suspended.
142 [ # # ]: 0 : if ( net_is_processing_suspended() )
143 : 0 : current_wallclock = current_time(true);
144 : :
145 : 0 : return current_wallclock;
146 : : }
147 : :
148 : 0 : double PktSrc::CheckPseudoTime()
149 : : {
150 [ # # ][ # # ]: 0 : if ( ! data && ! ExtractNextPacket() )
[ # # ]
151 : 0 : return 0;
152 : :
153 [ # # ]: 0 : if ( ! current_timestamp )
154 : 0 : return bro_start_time;
155 : :
156 [ # # ]: 0 : if ( remote_trace_sync_interval )
157 : : {
158 [ # # ][ # # ]: 0 : if ( next_sync_point == 0 || next_timestamp >= next_sync_point )
159 : : {
160 : 0 : int n = remote_serializer->SendSyncPoint();
161 : : next_sync_point = first_timestamp +
162 : 0 : n * remote_trace_sync_interval;
163 : : remote_serializer->Log(RemoteSerializer::LogInfo,
164 : : fmt("stopping at packet %.6f, next sync-point at %.6f",
165 : 0 : current_timestamp, next_sync_point));
166 : :
167 : 0 : return 0;
168 : : }
169 : : }
170 : :
171 : 0 : double pseudo_time = next_timestamp - first_timestamp;
172 : 0 : double ct = (current_time(true) - first_wallclock) * pseudo_realtime;
173 : :
174 [ # # ]: 0 : return pseudo_time <= ct ? bro_start_time + pseudo_time : 0;
175 : : }
176 : :
177 : 21347 : void PktSrc::Process()
178 : : {
179 [ - + ][ # # ]: 21347 : if ( ! data && ! ExtractNextPacket() )
[ - + ]
180 : 0 : return;
181 : :
182 : 21347 : current_timestamp = next_timestamp;
183 : :
184 [ - + ]: 21347 : if ( pseudo_realtime )
185 : : {
186 : 0 : current_pseudo = CheckPseudoTime();
187 : 0 : net_packet_arrival(current_pseudo, &hdr, data, hdr_size, this);
188 [ # # ]: 0 : if ( ! first_wallclock )
189 : 0 : first_wallclock = current_time(true);
190 : : }
191 : :
192 : : else
193 : 21347 : net_packet_arrival(current_timestamp, &hdr, data, hdr_size, this);
194 : :
195 : 21347 : data = 0;
196 : : }
197 : :
198 : : bool PktSrc::GetCurrentPacket(const struct pcap_pkthdr** arg_hdr,
199 : 0 : const u_char** arg_pkt)
200 : : {
201 [ # # ]: 0 : if ( ! last_data )
202 : 0 : return false;
203 : :
204 : 0 : *arg_hdr = &hdr;
205 : 0 : *arg_pkt = last_data;
206 : 0 : return true;
207 : : }
208 : :
209 : 2 : int PktSrc::PrecompileFilter(int index, const char* filter)
210 : : {
211 : : // Compile filter.
212 : 2 : BPF_Program* code = new BPF_Program();
213 : :
214 [ - + ]: 2 : if ( ! code->Compile(pd, filter, netmask, errbuf, sizeof(errbuf)) )
215 : : {
216 [ # # ]: 0 : delete code;
217 : 0 : return 0;
218 : : }
219 : :
220 : : // Store it in hash.
221 : 2 : HashKey* hash = new HashKey(HashKey(bro_int_t(index)));
222 : 2 : BPF_Program* oldcode = filters.Lookup(hash);
223 [ - + ]: 2 : if ( oldcode )
224 [ # # ]: 0 : delete oldcode;
225 : :
226 : 2 : filters.Insert(hash, code);
227 [ + - ]: 2 : delete hash;
228 : :
229 : 2 : return 1;
230 : : }
231 : :
232 : 1 : int PktSrc::SetFilter(int index)
233 : : {
234 : : // We don't want load-level filters for the secondary path.
235 [ - + ][ # # ]: 1 : if ( filter_type == TYPE_FILTER_SECONDARY && index > 0 )
236 : 0 : return 1;
237 : :
238 : 1 : HashKey* hash = new HashKey(HashKey(bro_int_t(index)));
239 : 1 : BPF_Program* code = filters.Lookup(hash);
240 [ + - ]: 1 : delete hash;
241 : :
242 [ - + ]: 1 : if ( ! code )
243 : : {
244 : : safe_snprintf(errbuf, sizeof(errbuf),
245 : : "No precompiled pcap filter for index %d",
246 : 0 : index);
247 : 0 : return 0;
248 : : }
249 : :
250 [ - + ]: 1 : if ( pcap_setfilter(pd, code->GetProgram()) < 0 )
251 : : {
252 : : safe_snprintf(errbuf, sizeof(errbuf),
253 : : "pcap_setfilter(%d): %s",
254 : 0 : index, pcap_geterr(pd));
255 : 0 : return 0;
256 : : }
257 : :
258 : : #ifndef HAVE_LINUX
259 : : // Linux doesn't clear counters when resetting filter.
260 : 1 : stats.received = stats.dropped = stats.link = 0;
261 : : #endif
262 : :
263 : 1 : return 1;
264 : : }
265 : :
266 : 1 : void PktSrc::SetHdrSize()
267 : : {
268 : 1 : int dl = pcap_datalink(pd);
269 : 1 : hdr_size = get_link_header_size(dl);
270 : :
271 [ - + ]: 1 : if ( hdr_size < 0 )
272 : : {
273 : : safe_snprintf(errbuf, sizeof(errbuf),
274 : 0 : "unknown data link type 0x%x", dl);
275 : 0 : Close();
276 : : }
277 : :
278 : 1 : datalink = dl;
279 : 1 : }
280 : :
281 : 0 : void PktSrc::Close()
282 : : {
283 [ # # ]: 0 : if ( pd )
284 : : {
285 : 0 : pcap_close(pd);
286 : 0 : pd = 0;
287 : 0 : closed = true;
288 : : }
289 : 0 : }
290 : :
291 : 0 : void PktSrc::AddSecondaryTablePrograms()
292 : : {
293 : : BPF_Program* program;
294 : :
295 [ # # ]: 0 : loop_over_list(secondary_path->EventTable(), i)
296 : : {
297 : 0 : SecondaryEvent* se = secondary_path->EventTable()[i];
298 : 0 : program = new BPF_Program();
299 : :
300 [ # # ]: 0 : if ( ! program->Compile(snaplen, datalink, se->Filter(),
301 : : netmask, errbuf, sizeof(errbuf)) )
302 : : {
303 [ # # ]: 0 : delete program;
304 : 0 : Close();
305 : : }
306 : :
307 : 0 : SecondaryProgram* sp = new SecondaryProgram(program, se);
308 : 0 : program_list.append(sp);
309 : : }
310 : 0 : }
311 : :
312 : 0 : void PktSrc::Statistics(Stats* s)
313 : : {
314 : : struct pcap_stat pstat;
315 : :
316 [ # # ]: 0 : if ( reading_traces )
317 : 0 : s->received = s->dropped = s->link = 0;
318 : :
319 [ # # ]: 0 : else if ( pcap_stats(pd, &pstat) < 0 )
320 : : {
321 : : run_time("problem getting packet filter statistics: %s",
322 : 0 : ErrorMsg());
323 : 0 : s->received = s->dropped = s->link = 0;
324 : : }
325 : :
326 : 0 : s->received = stats.received;
327 : 0 : s->dropped = pstat.ps_drop;
328 : 0 : s->link = pstat.ps_recv;
329 : :
330 [ # # ]: 0 : if ( pseudo_realtime )
331 : 0 : s->dropped = 0;
332 : :
333 : 0 : stats.dropped = s->dropped;
334 : 0 : }
335 : :
336 : : PktInterfaceSrc::PktInterfaceSrc(const char* arg_interface, const char* filter,
337 : 0 : PktSrc_Filter_Type ft)
338 : 0 : : PktSrc()
339 : : {
340 : : char tmp_errbuf[PCAP_ERRBUF_SIZE];
341 : 0 : filter_type = ft;
342 : :
343 : : // Determine interface if not specified.
344 [ # # # # ]: 0 : if ( ! arg_interface && ! (arg_interface = pcap_lookupdev(tmp_errbuf)) )
[ # # # # ]
[ # # ][ # # ]
345 : : {
346 : : safe_snprintf(errbuf, sizeof(errbuf),
347 : 0 : "pcap_lookupdev: %s", tmp_errbuf);
348 : 0 : return;
349 : : }
350 : :
351 : 0 : interface = copy_string(arg_interface);
352 : :
353 : : // Determine network and netmask.
354 : : uint32 net;
355 [ # # # # ]: 0 : if ( pcap_lookupnet(interface, &net, &netmask, tmp_errbuf) < 0 )
356 : : {
357 : : // ### The lookup can fail if no address is assigned to
358 : : // the interface; and libpcap doesn't have any useful notion
359 : : // of error codes, just error strings - how bogus - so we
360 : : // just kludge around the error :-(.
361 : : // sprintf(errbuf, "pcap_lookupnet %s", tmp_errbuf);
362 : : // return;
363 : 0 : net = 0;
364 : 0 : netmask = 0xffffff00;
365 : : }
366 : :
367 : : // We use the smallest time-out possible to return almost immediately if
368 : : // no packets are available. (We can't use set_nonblocking() as it's
369 : : // broken on FreeBSD: even when select() indicates that we can read
370 : : // something, we may get nothing if the store buffer hasn't filled up
371 : : // yet.)
372 : 0 : pd = pcap_open_live(interface, snaplen, 1, 1, tmp_errbuf);
373 : :
374 [ # # # # ]: 0 : if ( ! pd )
375 : : {
376 : : safe_snprintf(errbuf, sizeof(errbuf),
377 : 0 : "pcap_open_live: %s", tmp_errbuf);
378 : 0 : closed = true;
379 : 0 : return;
380 : : }
381 : :
382 : : // ### This needs autoconf'ing.
383 : : #ifdef HAVE_PCAP_INT_H
384 : : fprintf(stderr, "pcap bufsize = %d\n", ((struct pcap *) pd)->bufsize);
385 : : #endif
386 : :
387 : : #ifdef HAVE_LINUX
388 : : if ( pcap_setnonblock(pd, 1, tmp_errbuf) < 0 )
389 : : {
390 : : safe_snprintf(errbuf, sizeof(errbuf),
391 : : "pcap_setnonblock: %s", tmp_errbuf);
392 : : pcap_close(pd);
393 : : closed = true;
394 : : return;
395 : : }
396 : : #endif
397 : 0 : selectable_fd = pcap_fileno(pd);
398 : :
399 [ # # # # ]: 0 : if ( PrecompileFilter(0, filter) && SetFilter(0) )
[ # # # # ]
[ # # ][ # # ]
400 : : {
401 : 0 : SetHdrSize();
402 : 0 : fprintf(stderr, "listening on %s\n", interface);
403 : : }
404 : : else
405 : 0 : closed = true;
406 : 0 : }
407 : :
408 : :
409 : : PktFileSrc::PktFileSrc(const char* arg_readfile, const char* filter,
410 : 1 : PktSrc_Filter_Type ft)
411 : 1 : : PktSrc()
412 : : {
413 : 1 : readfile = copy_string(arg_readfile);
414 : :
415 : 1 : filter_type = ft;
416 : :
417 : 1 : pd = pcap_open_offline((char*) readfile, errbuf);
418 : :
419 [ + - + - ]: 1 : if ( pd && PrecompileFilter(0, filter) && SetFilter(0) )
[ + - ]
[ + - # # ]
[ # # ][ # # ]
[ # # ]
420 : : {
421 : 1 : SetHdrSize();
422 : :
423 [ + - # # ]: 1 : if ( closed )
424 : : // Unknown link layer type.
425 : 1 : return;
426 : :
427 : : // We don't put file sources into non-blocking mode as
428 : : // otherwise we would not be able to identify the EOF
429 : : // via next_packet().
430 : :
431 : 1 : selectable_fd = fileno(pcap_file(pd));
432 : :
433 [ - + # # ]: 1 : if ( selectable_fd < 0 )
434 : 1 : internal_error("OS does not support selectable pcap fd");
435 : : }
436 : : else
437 : 1 : closed = true;
438 : 0 : }
439 : :
440 : :
441 : 1 : SecondaryPath::SecondaryPath()
442 : : {
443 : 1 : filter = 0;
444 : :
445 : : // Glue together the secondary filter, if exists.
446 : 1 : Val* secondary_fv = internal_val("secondary_filters");
447 [ - + # # ]: 1 : if ( secondary_fv->AsTableVal()->Size() == 0 )
448 : 1 : return;
449 : :
450 : 0 : int did_first = 0;
451 : 0 : const TableEntryValPDict* v = secondary_fv->AsTable();
452 : 0 : IterCookie* c = v->InitForIteration();
453 : : TableEntryVal* tv;
454 : : HashKey* h;
455 : :
456 [ # # ][ # # ]: 0 : while ( (tv = v->NextEntry(h, c)) )
457 : : {
458 : : // Get the index values.
459 : : ListVal* index =
460 : 0 : secondary_fv->AsTableVal()->RecoverIndex(h);
461 : :
462 : : const char* str =
463 : 0 : index->Index(0)->Ref()->AsString()->CheckString();
464 : :
465 [ # # # # ]: 0 : if ( ++did_first == 1 )
466 : : {
467 : 0 : filter = copy_string(str);
468 : : }
469 : : else
470 : : {
471 [ # # ][ # # ]: 0 : if ( strlen(filter) > 0 )
472 : : {
473 : 0 : char* tmp_f = new char[strlen(str) + strlen(filter) + 32];
474 [ # # # # ]: 0 : if ( strlen(str) == 0 )
475 : 0 : sprintf(tmp_f, "%s", filter);
476 : : else
477 : 0 : sprintf(tmp_f, "(%s) or (%s)", filter, str);
478 [ # # ][ # # ]: 0 : delete [] filter;
479 : 0 : filter = tmp_f;
480 : : }
481 : : }
482 : :
483 : : // Build secondary_path event table item and link it.
484 : : SecondaryEvent* se =
485 : : new SecondaryEvent(index->Index(0)->Ref()->AsString()->CheckString(),
486 : 0 : tv->Value()->AsFunc() );
487 : :
488 : 0 : event_list.append(se);
489 : :
490 [ # # # # ]: 0 : delete h;
491 : : }
492 : 0 : }
493 : :
494 : 1 : SecondaryPath::~SecondaryPath()
495 : : {
496 [ - + ][ # # ]: 1 : loop_over_list(event_list, i)
497 : 0 : delete event_list[i];
498 : :
499 [ - + ][ # # ]: 1 : delete [] filter;
500 : 1 : }
501 : :
502 : :
503 : 0 : SecondaryProgram::~SecondaryProgram()
504 : : {
505 [ # # ][ # # ]: 0 : delete program;
506 : 0 : }
507 : :
508 : 0 : PktDumper::PktDumper(const char* arg_filename, bool arg_append)
509 : : {
510 : 0 : filename[0] = '\0';
511 : 0 : is_error = false;
512 : 0 : append = arg_append;
513 : 0 : dumper = 0;
514 : :
515 : : // We need a pcap_t with a reasonable link-layer type. We try to get it
516 : : // from the packet sources. If not available, we fall back to Ethernet.
517 : : // FIXME: Perhaps we should make this configurable?
518 : 0 : int linktype = -1;
519 : :
520 [ # # ][ # # ]: 0 : if ( pkt_srcs.length() )
521 : 0 : linktype = pkt_srcs[0]->LinkType();
522 : :
523 [ # # ][ # # ]: 0 : if ( linktype < 0 )
524 : 0 : linktype = DLT_EN10MB;
525 : :
526 : 0 : pd = pcap_open_dead(linktype, 8192);
527 [ # # # # ]: 0 : if ( ! pd )
528 : : {
529 : 0 : Error("error for pcap_open_dead");
530 : 0 : return;
531 : : }
532 : :
533 [ # # ][ # # ]: 0 : if ( arg_filename )
534 : 0 : Open(arg_filename);
535 : : }
536 : :
537 : 0 : bool PktDumper::Open(const char* arg_filename)
538 : : {
539 [ # # ][ # # ]: 0 : if ( ! arg_filename && ! *filename )
540 : : {
541 : 0 : Error("no filename given");
542 : 0 : return false;
543 : : }
544 : :
545 [ # # ]: 0 : if ( arg_filename )
546 : : {
547 [ # # ][ # # ]: 0 : if ( dumper && streq(arg_filename, filename) )
[ # # ]
548 : : // Already open.
549 : 0 : return true;
550 : :
551 : 0 : safe_strncpy(filename, arg_filename, FNBUF_LEN);
552 : : }
553 : :
554 [ # # ]: 0 : if ( dumper )
555 : 0 : Close();
556 : :
557 : : struct stat s;
558 : 0 : int exists = 0;
559 : :
560 [ # # ]: 0 : if ( append )
561 : : {
562 : : // See if output file already exists (and is non-empty).
563 : 0 : exists = stat(filename, &s); ;
564 : :
565 [ # # # # ]: 0 : if ( exists < 0 && errno != ENOENT )
[ # # ]
566 : : {
567 : 0 : Error(fmt("can't stat file %s: %s", filename, strerror(errno)));
568 : 0 : return false;
569 : : }
570 : : }
571 : :
572 [ # # ][ # # ]: 0 : if ( ! append || exists < 0 || s.st_size == 0 )
[ # # ]
573 : : {
574 : : // Open new file.
575 : 0 : dumper = pcap_dump_open(pd, filename);
576 [ # # ]: 0 : if ( ! dumper )
577 : : {
578 : 0 : Error(pcap_geterr(pd));
579 : 0 : return false;
580 : : }
581 : : }
582 : :
583 : : else
584 : : {
585 : : // Old file and we need to append, which, unfortunately,
586 : : // is not supported by libpcap. So, we have to hack a
587 : : // little bit, knowing that pcap_dumpter_t is, in fact,
588 : : // a FILE ... :-(
589 : 0 : dumper = (pcap_dumper_t*) fopen(filename, "a");
590 [ # # ]: 0 : if ( ! dumper )
591 : : {
592 : 0 : Error(fmt("can't open dump %s: %s", filename, strerror(errno)));
593 : 0 : return false;
594 : : }
595 : : }
596 : :
597 : 0 : open_time = network_time;
598 : 0 : is_error = false;
599 : 0 : return true;
600 : : }
601 : :
602 : 0 : bool PktDumper::Close()
603 : : {
604 [ # # ]: 0 : if ( dumper )
605 : : {
606 : 0 : pcap_dump_close(dumper);
607 : 0 : dumper = 0;
608 : 0 : is_error = false;
609 : : }
610 : :
611 : 0 : return true;
612 : : }
613 : :
614 : 0 : bool PktDumper::Dump(const struct pcap_pkthdr* hdr, const u_char* pkt)
615 : : {
616 [ # # ]: 0 : if ( ! dumper )
617 : 0 : return false;
618 : :
619 [ # # ]: 0 : if ( ! open_time )
620 : 0 : open_time = network_time;
621 : :
622 : 0 : pcap_dump((u_char*) dumper, hdr, pkt);
623 : :
624 : 0 : return true;
625 : : }
626 : :
627 : 0 : void PktDumper::Error(const char* errstr)
628 : : {
629 : 0 : safe_strncpy(errbuf, errstr, sizeof(errbuf));
630 : 0 : is_error = true;
631 : 0 : }
632 : :
633 : 1 : int get_link_header_size(int dl)
634 : : {
635 [ - + - - - : 1 : switch ( dl ) {
- ]
636 : : case DLT_NULL:
637 : 0 : return 4;
638 : :
639 : : case DLT_EN10MB:
640 : 1 : return 14;
641 : :
642 : : case DLT_FDDI:
643 : 0 : return 13 + 8; // fddi_header + LLC
644 : :
645 : : #ifdef DLT_LINUX_SLL
646 : : case DLT_LINUX_SLL:
647 : 0 : return 16;
648 : : #endif
649 : :
650 : : case DLT_RAW:
651 : 0 : return 0;
652 : : }
653 : :
654 : 1 : return -1;
655 [ + - ][ + - ]: 6 : }
|