1
use std::ffi::CString;
2
use std::mem;
3

            
4
use crate::{
5
    Error,
6
    capture::{Active, Capture, Inactive, Warning},
7
    device::Device,
8
    raw,
9
};
10

            
11
#[cfg(libpcap_1_5_0)]
12
use crate::capture::Precision;
13

            
14
impl Capture<Inactive> {
15
    /// Opens a capture handle for a device. You can pass a `Device` or an `&str` device
16
    /// name here. The handle is inactive, but can be activated via `.open()`.
17
    ///
18
    /// # Example
19
    /// ```
20
    /// use pcap::*;
21
    ///
22
    /// // Usage 1: Capture from a single owned device
23
    /// let dev: Device = pcap::Device::lookup()
24
    ///     .expect("device lookup failed")
25
    ///     .expect("no device available");
26
    /// let cap1 = Capture::from_device(dev);
27
    ///
28
    /// // Usage 2: Capture from an element of device list.
29
    /// let list: Vec<Device> = pcap::Device::list().unwrap();
30
    /// let cap2 = Capture::from_device(list[0].clone());
31
    ///
32
    /// // Usage 3: Capture from `&str` device name
33
    /// let cap3 = Capture::from_device("eth0");
34
    /// ```
35
3
    pub fn from_device<D: Into<Device>>(device: D) -> Result<Capture<Inactive>, Error> {
36
3
        let device: Device = device.into();
37
3
        let name = CString::new(device.name)?;
38
3
        Capture::new_raw(Some(name), |library, name, err| unsafe {
39
3
            raw::pcap_create(library, name, err)
40
3
        })
41
3
    }
42

            
43
    /// Activates an inactive capture created from `Capture::from_device()` or returns an error.
44
    ///
45
    /// libpcap activates the capture but warns about it when it cannot honor every request,
46
    /// such as on a device with no promiscuous mode. The capture is usable, so a warning is not
47
    /// an error; [`Capture::warning`] is where it can be read.
48
5
    pub fn open(self) -> Result<Capture<Active>, Error> {
49
5
        let status = unsafe { raw::pcap_activate(self.handle.as_ptr()) };
50
5
        if status < 0 {
51
2
            return Err(self.status_err(status));
52
3
        }
53

            
54
3
        let mut capture = unsafe { mem::transmute::<Capture<Inactive>, Capture<Active>>(self) };
55

            
56
        // A warning leaves a message of its own, and no call between pcap_create and here
57
        // writes the error buffer, so its contents belong to this warning.
58
3
        if status > 0 {
59
1
            capture.warning = Some(unsafe {
60
1
                Warning::from_status(status, raw::pcap_geterr(capture.handle.as_ptr()))
61
1
            });
62
2
        }
63

            
64
        // Now that the handle is active, `pcap_setmintocopy` will take the value that
65
        // `immediate_mode` left behind.
66
        #[cfg(windows)]
67
        if let Some(size) = capture.min_to_copy {
68
            capture
69
                .check_err(unsafe { raw::pcap_setmintocopy(capture.handle.as_ptr(), size) == 0 })?;
70
        }
71

            
72
3
        Ok(capture)
73
5
    }
74

            
75
    /// Set the read timeout for the Capture. By default, this is 0, so it will block indefinitely.
76
1
    pub fn timeout(self, ms: i32) -> Capture<Inactive> {
77
1
        unsafe { raw::pcap_set_timeout(self.handle.as_ptr(), ms) };
78
1
        self
79
1
    }
80

            
81
    /// Set the timestamp type to be used by a capture device.
82
    ///
83
    /// # Errors
84
    ///
85
    /// If the capture device does not support the timestamp type, an error will be returned.
86
    #[cfg(libpcap_1_2_1)]
87
2
    pub fn tstamp_type(self, tstamp_type: TimestampType) -> Result<Capture<Inactive>, Error> {
88
        #[cfg(windows)]
89
        if !raw::has_tstamp_type() {
90
            return Err(Error::EntrypointNotFound("pcap_set_tstamp_type"));
91
        }
92

            
93
        // libpcap leaves the error buffer alone here. All it reports is whether the device
94
        // claims to support the type, so there is no message to pass on.
95
2
        if unsafe { raw::pcap_set_tstamp_type(self.handle.as_ptr(), tstamp_type as _) } != 0 {
96
1
            return Err(Error::UnsupportedTimestampType);
97
1
        }
98

            
99
1
        Ok(self)
100
2
    }
101

            
102
    /// Set promiscuous mode on or off. By default, this is off.
103
1
    pub fn promisc(self, to: bool) -> Capture<Inactive> {
104
1
        unsafe { raw::pcap_set_promisc(self.handle.as_ptr(), to as _) };
105
1
        self
106
1
    }
107

            
108
    /// Set immediate mode on or off. By default, this is off.
109
    ///
110
    /// Note that in WinPcap, immediate mode is set by passing a 0 argument to `min_to_copy`.
111
    /// Immediate mode will be unset if `min_to_copy` is later called with a non-zero argument.
112
    /// Immediate mode is unset by resetting `min_to_copy` to the WinPcap default possibly changing
113
    /// a previously set value. When using `min_to_copy`, it is best to avoid `immediate_mode`.
114
    #[cfg(any(libpcap_1_5_0, windows))]
115
2
    pub fn immediate_mode(self, to: bool) -> Capture<Inactive> {
116
        // Prior to 1.5.0 when `pcap_set_immediate_mode` was introduced, the necessary steps to set
117
        // immediate mode were more complicated, depended on the OS, and in some configurations had
118
        // to be set on an active capture. See
119
        // https://www.tcpdump.org/manpages/pcap_set_immediate_mode.3pcap.html. Since we do not
120
        // expect pre-1.5.0 version on unix systems in the wild, those cases are simply ignored.
121
        // Without `pcap_set_immediate_mode`, immediate mode is a `pcap_setmintocopy` of 0,
122
        // which pcap takes only once the handle has been activated, so leave the value for
123
        // `open`.
124
        #[cfg(windows)]
125
        if !raw::has_immediate_mode() || !cfg!(libpcap_1_5_0) {
126
            let mut capture = self;
127
            capture.min_to_copy = Some(if to {
128
                0
129
            } else {
130
                raw::WINPCAP_MINTOCOPY_DEFAULT
131
            });
132

            
133
            return capture;
134
        }
135

            
136
        #[cfg(libpcap_1_5_0)]
137
        unsafe {
138
2
            raw::pcap_set_immediate_mode(self.handle.as_ptr(), to as _)
139
        };
140

            
141
2
        self
142
2
    }
143

            
144
    /// Set want_pktap to true or false. The default is maintained by libpcap.
145
    #[cfg(all(libpcap_1_5_3, target_os = "macos"))]
146
    pub fn want_pktap(self, to: bool) -> Capture<Inactive> {
147
        unsafe { raw::pcap_set_want_pktap(self.handle.as_ptr(), to as _) };
148

            
149
        self
150
    }
151

            
152
    /// Set rfmon mode on or off. The default is maintained by pcap.
153
    #[cfg(not(windows))]
154
1
    pub fn rfmon(self, to: bool) -> Capture<Inactive> {
155
1
        unsafe { raw::pcap_set_rfmon(self.handle.as_ptr(), to as _) };
156
1
        self
157
1
    }
158

            
159
    /// Set the buffer size for incoming packet data.
160
    ///
161
    /// The default is 1000000. This should always be larger than the snaplen.
162
1
    pub fn buffer_size(self, to: i32) -> Capture<Inactive> {
163
1
        unsafe { raw::pcap_set_buffer_size(self.handle.as_ptr(), to) };
164
1
        self
165
1
    }
166

            
167
    /// Set the timestamp precision returned in captures.
168
    ///
169
    /// # Errors
170
    ///
171
    /// If the capture device does not support the timestamp precision, an error will be returned.
172
    #[cfg(libpcap_1_5_0)]
173
2
    pub fn precision(self, precision: Precision) -> Result<Capture<Inactive>, Error> {
174
        #[cfg(windows)]
175
        if !raw::has_tstamp_precision() {
176
            return Err(Error::EntrypointNotFound("pcap_set_tstamp_precision"));
177
        }
178

            
179
        // libpcap leaves the error buffer alone here. All it reports is whether the device
180
        // claims to support the precision, so there is no message to pass on.
181
2
        if unsafe { raw::pcap_set_tstamp_precision(self.handle.as_ptr(), precision as _) } != 0 {
182
1
            return Err(Error::UnsupportedTimestampPrecision);
183
1
        }
184

            
185
1
        Ok(self)
186
2
    }
187

            
188
    /// Set the snaplen size (the maximum length of a packet captured into the buffer).
189
    /// Useful if you only want certain headers, but not the entire packet.
190
    ///
191
    /// The default is 65535.
192
1
    pub fn snaplen(self, to: i32) -> Capture<Inactive> {
193
1
        unsafe { raw::pcap_set_snaplen(self.handle.as_ptr(), to) };
194
1
        self
195
1
    }
196
}
197

            
198
#[repr(i32)]
199
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
200
/// Timestamp types
201
///
202
/// Not all systems and interfaces will necessarily support all of these. They are described in
203
/// more detail in [pcap-tstamp(7)](https://www.tcpdump.org/manpages/pcap-tstamp.7.html).
204
///
205
/// Note that timestamps synchronized with the system clock can go backwards, as the system clock
206
/// can go backwards.  If a clock is not in sync with the system clock, that could be because the
207
/// system clock isn't keeping accurate time, because the other clock isn't keeping accurate time,
208
/// or both.
209
///
210
/// Note that host-provided timestamps generally correspond to the time when the timestamping
211
/// code sees the packet; this could be some unknown amount of time after the first or last bit of
212
/// the packet is received by the network adapter, due to batching of interrupts for packet
213
/// arrival, queueing delays, etc..
214
pub enum TimestampType {
215
    /// Timestamps are provided by the host machine, rather than by the capture device.
216
    ///
217
    /// The characteristics of the timestamp are unknown.
218
    Host = 0,
219
    /// A timestamp provided by the host machine that is low precision but relatively cheap to
220
    /// fetch.
221
    ///
222
    /// It is taken from the system clock, so it is synchronized with the times you would fetch
223
    /// from system calls.
224
    HostLowPrec = 1,
225
    /// A timestamp provided by the host machine that is high precision. It might be more expensive
226
    /// to fetch than [`TimestampType::HostLowPrec`].
227
    ///
228
    /// From libpcap 1.10.0 on it is synchronized with the system clock. Before that it might or
229
    /// might not have been.
230
    HostHighPrec = 2,
231
    /// A high-precision timestamp supplied by the capture device.
232
    ///
233
    /// The timestamp is synchronized with the system clock.
234
    Adapter = 3,
235
    /// A high-precision timestamp supplied by the capture device.
236
    ///
237
    /// The timestamp is not synchronized with the system clock.
238
    AdapterUnsynced = 4,
239
    /// A timestamp provided by the host machine that is high precision. It might be more expensive
240
    /// to fetch than [`TimestampType::HostLowPrec`].
241
    ///
242
    /// The timestamp is not synchronized with the system clock.
243
    #[cfg(libpcap_1_10_0)]
244
    HostHighPrecUnsynced = 5,
245
}
246

            
247
#[cfg(test)]
248
mod tests {
249
    use crate::{
250
        capture::testmod::test_capture,
251
        raw::testmod::{RAWMTX, as_pcap_t, geterr_expect},
252
    };
253

            
254
    use super::*;
255

            
256
    #[test]
257
    fn test_from_device() {
258
        let _m = RAWMTX.lock();
259

            
260
        let mut dummy: isize = 777;
261
        let pcap = as_pcap_t(&mut dummy);
262

            
263
        let ctx = raw::pcap_create_context();
264
        ctx.expect().return_once_st(move |_, _, _| pcap);
265

            
266
        let ctx = raw::pcap_close_context();
267
        ctx.expect()
268
            .withf_st(move |ptr| *ptr == pcap)
269
            .return_once(|_| {});
270

            
271
        let result = Capture::from_device("some_device");
272
        assert!(result.is_ok());
273
    }
274

            
275
    #[test]
276
    fn test_from_device_error() {
277
        let _m = RAWMTX.lock();
278

            
279
        let ctx = raw::pcap_create_context();
280
        ctx.expect().return_once_st(|_, _, _| std::ptr::null_mut());
281

            
282
        let result = Capture::from_device("some_device");
283
        assert!(result.is_err());
284
    }
285

            
286
    #[test]
287
    fn test_open() {
288
        let _m = RAWMTX.lock();
289

            
290
        let mut dummy: isize = 777;
291
        let pcap = as_pcap_t(&mut dummy);
292

            
293
        let test_capture = test_capture::<Inactive>(pcap);
294
        let capture = test_capture.capture;
295

            
296
        let ctx = raw::pcap_activate_context();
297
        ctx.expect()
298
            .withf_st(move |arg1| *arg1 == pcap)
299
            .return_once(|_| 0);
300

            
301
        let capture = capture.open().unwrap();
302
        assert_eq!(capture.warning(), None);
303
    }
304

            
305
    #[test]
306
    fn test_open_warning() {
307
        let _m = RAWMTX.lock();
308

            
309
        let mut dummy: isize = 777;
310
        let pcap = as_pcap_t(&mut dummy);
311

            
312
        let test_capture = test_capture::<Inactive>(pcap);
313
        let capture = test_capture.capture;
314

            
315
        // A device with no promiscuous mode is activated all the same.
316
        let ctx = raw::pcap_activate_context();
317
        ctx.expect()
318
            .withf_st(move |arg1| *arg1 == pcap)
319
            .return_once(|_| raw::PCAP_WARNING_PROMISC_NOTSUP);
320

            
321
        let _err = geterr_expect(pcap);
322

            
323
        let capture = capture.open().unwrap();
324
        assert_eq!(
325
            capture.warning(),
326
            Some(&Warning {
327
                code: crate::WarningCode::PromiscuousModeNotSupported,
328
                message: "oh oh".to_string(),
329
            })
330
        );
331
    }
332

            
333
    #[test]
334
    fn test_open_status_error() {
335
        let _m = RAWMTX.lock();
336

            
337
        let mut dummy: isize = 777;
338
        let pcap = as_pcap_t(&mut dummy);
339

            
340
        let test_capture = test_capture::<Inactive>(pcap);
341
        let capture = test_capture.capture;
342

            
343
        let ctx = raw::pcap_activate_context();
344
        ctx.expect()
345
            .withf_st(move |arg1| *arg1 == pcap)
346
            .return_once(|_| raw::PCAP_ERROR_PERM_DENIED);
347

            
348
        let _err = geterr_expect(pcap);
349

            
350
        let error = capture.open().err().unwrap();
351
        assert_eq!(
352
            error,
353
            Error::PcapErrorCode(crate::ErrorCode::PermissionDenied, "oh oh".to_string())
354
        );
355
    }
356

            
357
    #[test]
358
    fn test_open_error() {
359
        let _m = RAWMTX.lock();
360

            
361
        let mut dummy: isize = 777;
362
        let pcap = as_pcap_t(&mut dummy);
363

            
364
        let test_capture = test_capture::<Inactive>(pcap);
365
        let capture = test_capture.capture;
366

            
367
        let ctx = raw::pcap_activate_context();
368
        ctx.expect()
369
            .withf_st(move |arg1| *arg1 == pcap)
370
            .return_once(|_| -1);
371

            
372
        let _err = geterr_expect(pcap);
373

            
374
        let result = capture.open();
375
        assert!(result.is_err());
376
    }
377

            
378
    #[test]
379
    fn test_timeout() {
380
        let _m = RAWMTX.lock();
381

            
382
        let mut dummy: isize = 777;
383
        let pcap = as_pcap_t(&mut dummy);
384

            
385
        let test_capture = test_capture::<Inactive>(pcap);
386
        let capture = test_capture.capture;
387

            
388
        let ctx = raw::pcap_set_timeout_context();
389
        ctx.expect()
390
            .withf_st(move |arg1, _| *arg1 == pcap)
391
            .return_once(|_, _| 0);
392

            
393
        let _capture = capture.timeout(5);
394
    }
395

            
396
    #[test]
397
    #[cfg(libpcap_1_2_1)]
398
    fn test_timstamp_type() {
399
        let _m = RAWMTX.lock();
400

            
401
        let mut dummy: isize = 777;
402
        let pcap = as_pcap_t(&mut dummy);
403

            
404
        let test_capture = test_capture::<Inactive>(pcap);
405
        let capture = test_capture.capture;
406

            
407
        #[cfg(windows)]
408
        let has_ctx = raw::has_tstamp_type_context();
409
        #[cfg(windows)]
410
        has_ctx.expect().times(2).returning(|| true);
411

            
412
        let ctx = raw::pcap_set_tstamp_type_context();
413
        ctx.expect()
414
            .withf_st(move |arg1, _| *arg1 == pcap)
415
            .return_once(|_, _| 0);
416

            
417
        let capture = capture.tstamp_type(TimestampType::Host).unwrap();
418

            
419
        let ctx = raw::pcap_set_tstamp_type_context();
420
        ctx.checkpoint();
421
        ctx.expect()
422
            .withf_st(move |arg1, _| *arg1 == pcap)
423
            .return_once(|_, _| raw::PCAP_WARNING_TSTAMP_TYPE_NOTSUP);
424

            
425
        assert_eq!(
426
            capture.tstamp_type(TimestampType::Adapter).err().unwrap(),
427
            Error::UnsupportedTimestampType
428
        );
429

            
430
        // For code coverage of the derive line.
431
        assert_ne!(TimestampType::Host, TimestampType::HostLowPrec);
432
        assert_ne!(TimestampType::Host, TimestampType::HostHighPrec);
433
        #[cfg(libpcap_1_10_0)]
434
        assert_ne!(
435
            TimestampType::HostHighPrec,
436
            TimestampType::HostHighPrecUnsynced
437
        );
438
    }
439

            
440
    #[test]
441
    #[cfg(all(windows, libpcap_1_2_1))]
442
    fn test_timestamp_type_missing() {
443
        let _m = RAWMTX.lock();
444

            
445
        let mut dummy: isize = 777;
446
        let pcap = as_pcap_t(&mut dummy);
447

            
448
        let test_capture = test_capture::<Inactive>(pcap);
449
        let capture = test_capture.capture;
450

            
451
        let ctx = raw::has_tstamp_type_context();
452
        ctx.expect().return_once(|| false);
453

            
454
        let result = capture.tstamp_type(TimestampType::Host);
455
        assert!(matches!(
456
            result,
457
            Err(Error::EntrypointNotFound("pcap_set_tstamp_type"))
458
        ));
459
    }
460

            
461
    #[test]
462
    fn test_promisc() {
463
        let _m = RAWMTX.lock();
464

            
465
        let mut dummy: isize = 777;
466
        let pcap = as_pcap_t(&mut dummy);
467

            
468
        let test_capture = test_capture::<Inactive>(pcap);
469
        let capture = test_capture.capture;
470

            
471
        let ctx = raw::pcap_set_promisc_context();
472
        ctx.expect()
473
            .withf_st(move |arg1, _| *arg1 == pcap)
474
            .return_once(|_, _| 0);
475

            
476
        let _capture = capture.promisc(true);
477
    }
478

            
479
    #[cfg(all(libpcap_1_5_0, windows))]
480
    struct ImmediateModeExpect(
481
        raw::__pcap_set_immediate_mode::Context,
482
        raw::__has_immediate_mode::Context,
483
    );
484

            
485
    #[cfg(all(libpcap_1_5_0, not(windows)))]
486
    struct ImmediateModeExpect(raw::__pcap_set_immediate_mode::Context);
487

            
488
    #[cfg(libpcap_1_5_0)]
489
    fn immediate_mode_expect(pcap: *mut raw::pcap_t) -> ImmediateModeExpect {
490
        let ctx = raw::pcap_set_immediate_mode_context();
491
        ctx.checkpoint();
492
        ctx.expect()
493
            .withf_st(move |arg1, _| *arg1 == pcap)
494
            .return_once(|_, _| 0);
495

            
496
        #[cfg(windows)]
497
        {
498
            let has_ctx = raw::has_immediate_mode_context();
499
            has_ctx.checkpoint();
500
            has_ctx.expect().return_once(|| true);
501
            ImmediateModeExpect(ctx, has_ctx)
502
        }
503
        #[cfg(not(windows))]
504
        ImmediateModeExpect(ctx)
505
    }
506

            
507
    #[test]
508
    #[cfg(libpcap_1_5_0)]
509
    fn test_immediate_mode() {
510
        let _m = RAWMTX.lock();
511

            
512
        let mut dummy: isize = 777;
513
        let pcap = as_pcap_t(&mut dummy);
514

            
515
        let test_capture = test_capture::<Inactive>(pcap);
516
        let capture = test_capture.capture;
517

            
518
        let _ctx = immediate_mode_expect(pcap);
519
        let capture = capture.immediate_mode(true);
520

            
521
        let _ctx = immediate_mode_expect(pcap);
522
        let _capture = capture.immediate_mode(false);
523
    }
524

            
525
    // A library without pcap_set_immediate_mode takes the value through pcap_setmintocopy
526
    // instead, and only once the handle is active.
527
    #[cfg(windows)]
528
    fn winpcap_open_expect(
529
        pcap: *mut raw::pcap_t,
530
        size: i32,
531
        ret: libc::c_int,
532
    ) -> (
533
        raw::__pcap_activate::Context,
534
        raw::__pcap_setmintocopy::Context,
535
    ) {
536
        let activate = raw::pcap_activate_context();
537
        activate.checkpoint();
538
        activate
539
            .expect()
540
            .withf_st(move |arg1| *arg1 == pcap)
541
            .return_once(|_| 0);
542

            
543
        let mintocopy = raw::pcap_setmintocopy_context();
544
        mintocopy.checkpoint();
545
        mintocopy
546
            .expect()
547
            .withf_st(move |arg1, arg2| *arg1 == pcap && *arg2 == size)
548
            .return_once(move |_, _| ret);
549

            
550
        (activate, mintocopy)
551
    }
552

            
553
    #[test]
554
    #[cfg(windows)]
555
    fn test_immediate_mode_winpcap() {
556
        let _m = RAWMTX.lock();
557

            
558
        let mut dummy: isize = 777;
559
        let pcap = as_pcap_t(&mut dummy);
560

            
561
        let test_capture = test_capture::<Inactive>(pcap);
562
        let capture = test_capture.capture;
563

            
564
        let has_ctx = raw::has_immediate_mode_context();
565
        has_ctx.expect().times(2).returning(|| false);
566

            
567
        let capture = capture.immediate_mode(false).immediate_mode(true);
568

            
569
        let _ctx = winpcap_open_expect(pcap, 0, 0);
570
        assert!(capture.open().is_ok());
571
    }
572

            
573
    #[test]
574
    #[cfg(windows)]
575
    fn test_immediate_mode_winpcap_off() {
576
        let _m = RAWMTX.lock();
577

            
578
        let mut dummy: isize = 777;
579
        let pcap = as_pcap_t(&mut dummy);
580

            
581
        let test_capture = test_capture::<Inactive>(pcap);
582
        let capture = test_capture.capture;
583

            
584
        let has_ctx = raw::has_immediate_mode_context();
585
        has_ctx.expect().return_once(|| false);
586

            
587
        let capture = capture.immediate_mode(false);
588

            
589
        let _ctx = winpcap_open_expect(pcap, raw::WINPCAP_MINTOCOPY_DEFAULT, 0);
590
        assert!(capture.open().is_ok());
591
    }
592

            
593
    #[test]
594
    #[cfg(windows)]
595
    fn test_immediate_mode_winpcap_error() {
596
        let _m = RAWMTX.lock();
597

            
598
        let mut dummy: isize = 777;
599
        let pcap = as_pcap_t(&mut dummy);
600

            
601
        let test_capture = test_capture::<Inactive>(pcap);
602
        let capture = test_capture.capture;
603

            
604
        let has_ctx = raw::has_immediate_mode_context();
605
        has_ctx.expect().return_once(|| false);
606

            
607
        let capture = capture.immediate_mode(true);
608

            
609
        let _ctx = winpcap_open_expect(pcap, 0, -1);
610
        let _err = geterr_expect(pcap);
611

            
612
        assert!(capture.open().is_err());
613
    }
614

            
615
    #[test]
616
    #[cfg(all(libpcap_1_5_3, target_os = "macos"))]
617
    fn test_want_pktap() {
618
        let _m = RAWMTX.lock();
619

            
620
        let mut dummy: isize = 777;
621
        let pcap = as_pcap_t(&mut dummy);
622

            
623
        let test_capture = test_capture::<Inactive>(pcap);
624
        let capture = test_capture.capture;
625

            
626
        let ctx = raw::pcap_set_want_pktap_context();
627
        ctx.expect()
628
            .withf_st(move |arg1, _| *arg1 == pcap)
629
            .return_once(|_, _| 0);
630
        let _capture = capture.want_pktap(true);
631
    }
632

            
633
    #[test]
634
    #[cfg(not(windows))]
635
    fn test_rfmon() {
636
        let _m = RAWMTX.lock();
637

            
638
        let mut dummy: isize = 777;
639
        let pcap = as_pcap_t(&mut dummy);
640

            
641
        let test_capture = test_capture::<Inactive>(pcap);
642
        let capture = test_capture.capture;
643

            
644
        let ctx = raw::pcap_set_rfmon_context();
645
        ctx.expect()
646
            .withf_st(move |arg1, _| *arg1 == pcap)
647
            .return_once(|_, _| 0);
648

            
649
        let _capture = capture.rfmon(true);
650
    }
651

            
652
    #[test]
653
    fn test_buffer_size() {
654
        let _m = RAWMTX.lock();
655

            
656
        let mut dummy: isize = 777;
657
        let pcap = as_pcap_t(&mut dummy);
658

            
659
        let test_capture = test_capture::<Inactive>(pcap);
660
        let capture = test_capture.capture;
661

            
662
        let ctx = raw::pcap_set_buffer_size_context();
663
        ctx.expect()
664
            .withf_st(move |arg1, _| *arg1 == pcap)
665
            .return_once(|_, _| 0);
666

            
667
        let _capture = capture.buffer_size(10);
668
    }
669

            
670
    #[test]
671
    #[cfg(libpcap_1_5_0)]
672
    fn test_precision() {
673
        let _m = RAWMTX.lock();
674

            
675
        let mut dummy: isize = 777;
676
        let pcap = as_pcap_t(&mut dummy);
677

            
678
        let test_capture = test_capture::<Inactive>(pcap);
679
        let capture = test_capture.capture;
680

            
681
        #[cfg(windows)]
682
        let has_ctx = raw::has_tstamp_precision_context();
683
        #[cfg(windows)]
684
        has_ctx.expect().times(2).returning(|| true);
685

            
686
        let ctx = raw::pcap_set_tstamp_precision_context();
687
        ctx.expect()
688
            .withf_st(move |arg1, _| *arg1 == pcap)
689
            .return_once(|_, _| 0);
690

            
691
        let capture = capture.precision(Precision::Nano).unwrap();
692

            
693
        let ctx = raw::pcap_set_tstamp_precision_context();
694
        ctx.checkpoint();
695
        ctx.expect()
696
            .withf_st(move |arg1, _| *arg1 == pcap)
697
            .return_once(|_, _| raw::PCAP_ERROR_TSTAMP_PRECISION_NOTSUP);
698

            
699
        assert_eq!(
700
            capture.precision(Precision::Nano).err().unwrap(),
701
            Error::UnsupportedTimestampPrecision
702
        );
703
    }
704

            
705
    #[test]
706
    #[cfg(all(windows, libpcap_1_5_0))]
707
    fn test_precision_missing() {
708
        let _m = RAWMTX.lock();
709

            
710
        let mut dummy: isize = 777;
711
        let pcap = as_pcap_t(&mut dummy);
712

            
713
        let test_capture = test_capture::<Inactive>(pcap);
714
        let capture = test_capture.capture;
715

            
716
        let ctx = raw::has_tstamp_precision_context();
717
        ctx.expect().return_once(|| false);
718

            
719
        let result = capture.precision(Precision::Nano);
720
        assert!(matches!(
721
            result,
722
            Err(Error::EntrypointNotFound("pcap_set_tstamp_precision"))
723
        ));
724
    }
725

            
726
    #[test]
727
    fn test_snaplen() {
728
        let _m = RAWMTX.lock();
729

            
730
        let mut dummy: isize = 777;
731
        let pcap = as_pcap_t(&mut dummy);
732

            
733
        let test_capture = test_capture::<Inactive>(pcap);
734
        let capture = test_capture.capture;
735

            
736
        let ctx = raw::pcap_set_snaplen_context();
737
        ctx.expect()
738
            .withf_st(move |arg1, _| *arg1 == pcap)
739
            .return_once(|_, _| 0);
740

            
741
        let _capture = capture.snaplen(10);
742
    }
743
}