@@ -65,6 +65,44 @@ macro_rules! check {
65
65
}
66
66
use check;
67
67
68
+ /// Result returned by [`Interface::poll`].
69
+ ///
70
+ /// This contains information on whether socket states might have changed.
71
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
72
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
73
+ pub enum PollResult {
74
+ /// Socket state is guaranteed to not have changed.
75
+ None ,
76
+ /// You should check the state of sockets again for received data or completion of operations.
77
+ SocketStateChanged ,
78
+ }
79
+
80
+ /// Result returned by [`Interface::poll_ingress_single`].
81
+ ///
82
+ /// This contains information on whether a packet was processed or not,
83
+ /// and whether it might've affected socket states.
84
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
85
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
86
+ pub enum PollIngressSingleResult {
87
+ /// No packet was processed. You don't need to call [`Interface::poll_ingress_single`]
88
+ /// again, until more packets arrive.
89
+ ///
90
+ /// Socket state is guaranteed to not have changed.
91
+ None ,
92
+ /// A packet was processed.
93
+ ///
94
+ /// There may be more packets in the device's RX queue, so you should call [`Interface::poll_ingress_single`] again.
95
+ ///
96
+ /// Socket state is guaranteed to not have changed.
97
+ PacketProcessed ,
98
+ /// A packet was processed, which might have caused socket state to change.
99
+ ///
100
+ /// There may be more packets in the device's RX queue, so you should call [`Interface::poll_ingress_single`] again.
101
+ ///
102
+ /// You should check the state of sockets again for received data or completion of operations.
103
+ SocketStateChanged ,
104
+ }
105
+
68
106
/// A network interface.
69
107
///
70
108
/// The network interface logically owns a number of other data structures; to avoid
@@ -150,10 +188,7 @@ impl Interface {
150
188
/// # Panics
151
189
/// This function panics if the [`Config::hardware_address`] does not match
152
190
/// the medium of the device.
153
- pub fn new < D > ( config : Config , device : & mut D , now : Instant ) -> Self
154
- where
155
- D : Device + ?Sized ,
156
- {
191
+ pub fn new ( config : Config , device : & mut ( impl Device + ?Sized ) , now : Instant ) -> Self {
157
192
let caps = device. capabilities ( ) ;
158
193
assert_eq ! (
159
194
config. hardware_addr. medium( ) ,
@@ -375,59 +410,107 @@ impl Interface {
375
410
self . fragments . reassembly_timeout = timeout;
376
411
}
377
412
378
- /// Transmit packets queued in the given sockets, and receive packets queued
413
+ /// Transmit packets queued in the sockets, and receive packets queued
379
414
/// in the device.
380
415
///
381
- /// This function returns a boolean value indicating whether any packets were
382
- /// processed or emitted, and thus, whether the readiness of any socket might
383
- /// have changed.
416
+ /// This function returns a value indicating whether the state of any socket
417
+ /// might have changed.
418
+ ///
419
+ /// ## DoS warning
384
420
///
385
- /// # Note
386
- /// This function performs a bounded amount of work per call to avoid
387
- /// starving other tasks of CPU time. If it returns true, there may still be
388
- /// packets to be received or transmitted. Depending on system design,
389
- /// calling this function in a loop may cause a denial of service if
390
- /// packets cannot be processed faster than they arrive.
391
- pub fn poll < D > (
421
+ /// This function processes all packets in the device's queue. This can
422
+ /// be an unbounded amount of work if packets arrive faster than they're
423
+ /// processed.
424
+ ///
425
+ /// If this is a concern for your application (i.e. your environment doesn't
426
+ /// have preemptive scheduling, or `poll()` is called from a main loop where
427
+ /// other important things are processed), you may use the lower-level methods
428
+ /// [`poll_egress()`](Self::poll_egress) and [`poll_ingress_single()`](Self::poll_ingress_single).
429
+ /// This allows you to insert yields or process other events between processing
430
+ /// individual ingress packets.
431
+ pub fn poll (
392
432
& mut self ,
393
433
timestamp : Instant ,
394
- device : & mut D ,
434
+ device : & mut ( impl Device + ? Sized ) ,
395
435
sockets : & mut SocketSet < ' _ > ,
396
- ) -> bool
397
- where
398
- D : Device + ?Sized ,
399
- {
436
+ ) -> PollResult {
400
437
self . inner . now = timestamp;
401
438
439
+ let mut res = PollResult :: None ;
440
+
402
441
#[ cfg( feature = "_proto-fragmentation" ) ]
403
442
self . fragments . assembler . remove_expired ( timestamp) ;
404
443
444
+ // Process ingress while there's packets available.
445
+ loop {
446
+ match self . socket_ingress ( device, sockets) {
447
+ PollIngressSingleResult :: None => break ,
448
+ PollIngressSingleResult :: PacketProcessed => { }
449
+ PollIngressSingleResult :: SocketStateChanged => res = PollResult :: SocketStateChanged ,
450
+ }
451
+ }
452
+
453
+ // Process egress.
454
+ match self . poll_egress ( timestamp, device, sockets) {
455
+ PollResult :: None => { }
456
+ PollResult :: SocketStateChanged => res = PollResult :: SocketStateChanged ,
457
+ }
458
+
459
+ res
460
+ }
461
+
462
+ /// Transmit packets queued in the sockets.
463
+ ///
464
+ /// This function returns a value indicating whether the state of any socket
465
+ /// might have changed.
466
+ ///
467
+ /// This is guaranteed to always perform a bounded amount of work.
468
+ pub fn poll_egress (
469
+ & mut self ,
470
+ timestamp : Instant ,
471
+ device : & mut ( impl Device + ?Sized ) ,
472
+ sockets : & mut SocketSet < ' _ > ,
473
+ ) -> PollResult {
474
+ self . inner . now = timestamp;
475
+
405
476
match self . inner . caps . medium {
406
477
#[ cfg( feature = "medium-ieee802154" ) ]
407
- Medium :: Ieee802154 =>
408
- {
478
+ Medium :: Ieee802154 => {
409
479
#[ cfg( feature = "proto-sixlowpan-fragmentation" ) ]
410
- if self . sixlowpan_egress ( device) {
411
- return true ;
412
- }
480
+ self . sixlowpan_egress ( device) ;
413
481
}
414
482
#[ cfg( any( feature = "medium-ethernet" , feature = "medium-ip" ) ) ]
415
- _ =>
416
- {
483
+ _ => {
417
484
#[ cfg( feature = "proto-ipv4-fragmentation" ) ]
418
- if self . ipv4_egress ( device) {
419
- return true ;
420
- }
485
+ self . ipv4_egress ( device) ;
421
486
}
422
487
}
423
488
424
- let mut readiness_may_have_changed = self . socket_ingress ( device, sockets) ;
425
- readiness_may_have_changed |= self . socket_egress ( device, sockets) ;
426
-
427
489
#[ cfg( feature = "multicast" ) ]
428
490
self . multicast_egress ( device) ;
429
491
430
- readiness_may_have_changed
492
+ self . socket_egress ( device, sockets)
493
+ }
494
+
495
+ /// Process one incoming packet queued in the device.
496
+ ///
497
+ /// Returns a value indicating:
498
+ /// - whether a packet was processed, in which case you have to call this method again in case there's more packets queued.
499
+ /// - whether the state of any socket might have changed.
500
+ ///
501
+ /// Since it processes at most one packet, this is guaranteed to always perform a bounded amount of work.
502
+ pub fn poll_ingress_single (
503
+ & mut self ,
504
+ timestamp : Instant ,
505
+ device : & mut ( impl Device + ?Sized ) ,
506
+ sockets : & mut SocketSet < ' _ > ,
507
+ ) -> PollIngressSingleResult {
508
+ self . inner . now = timestamp;
509
+
510
+ #[ cfg( feature = "_proto-fragmentation" ) ]
511
+ self . fragments . assembler . remove_expired ( timestamp) ;
512
+
513
+ self . socket_ingress ( device, sockets)
431
514
}
432
515
433
516
/// Return a _soft deadline_ for calling [poll] the next time.
@@ -480,20 +563,19 @@ impl Interface {
480
563
}
481
564
}
482
565
483
- fn socket_ingress < D > ( & mut self , device : & mut D , sockets : & mut SocketSet < ' _ > ) -> bool
484
- where
485
- D : Device + ?Sized ,
486
- {
487
- let mut processed_any = false ;
488
-
566
+ fn socket_ingress (
567
+ & mut self ,
568
+ device : & mut ( impl Device + ?Sized ) ,
569
+ sockets : & mut SocketSet < ' _ > ,
570
+ ) -> PollIngressSingleResult {
489
571
let Some ( ( rx_token, tx_token) ) = device. receive ( self . inner . now ) else {
490
- return processed_any ;
572
+ return PollIngressSingleResult :: None ;
491
573
} ;
492
574
493
575
let rx_meta = rx_token. meta ( ) ;
494
576
rx_token. consume ( |frame| {
495
577
if frame. is_empty ( ) {
496
- return ;
578
+ return PollIngressSingleResult :: PacketProcessed ;
497
579
}
498
580
499
581
match self . inner . caps . medium {
@@ -543,24 +625,30 @@ impl Interface {
543
625
}
544
626
}
545
627
}
546
- processed_any = true ;
547
- } ) ;
548
628
549
- processed_any
629
+ // TODO: Propagate the PollIngressSingleResult from deeper.
630
+ // There's many received packets that we process but can't cause sockets
631
+ // to change state. For example IP fragments, multicast stuff, ICMP pings
632
+ // if they dont't match any raw socket...
633
+ // We should return `PacketProcessed` for these to save the user from
634
+ // doing useless socket polls.
635
+ PollIngressSingleResult :: SocketStateChanged
636
+ } )
550
637
}
551
638
552
- fn socket_egress < D > ( & mut self , device : & mut D , sockets : & mut SocketSet < ' _ > ) -> bool
553
- where
554
- D : Device + ?Sized ,
555
- {
639
+ fn socket_egress (
640
+ & mut self ,
641
+ device : & mut ( impl Device + ?Sized ) ,
642
+ sockets : & mut SocketSet < ' _ > ,
643
+ ) -> PollResult {
556
644
let _caps = device. capabilities ( ) ;
557
645
558
646
enum EgressError {
559
647
Exhausted ,
560
648
Dispatch ,
561
649
}
562
650
563
- let mut emitted_any = false ;
651
+ let mut result = PollResult :: None ;
564
652
for item in sockets. items_mut ( ) {
565
653
if !item
566
654
. meta
@@ -581,7 +669,7 @@ impl Interface {
581
669
. dispatch_ip ( t, meta, response, & mut self . fragmenter )
582
670
. map_err ( |_| EgressError :: Dispatch ) ?;
583
671
584
- emitted_any = true ;
672
+ result = PollResult :: SocketStateChanged ;
585
673
586
674
Ok ( ( ) )
587
675
} ;
@@ -663,7 +751,7 @@ impl Interface {
663
751
Ok ( ( ) ) => { }
664
752
}
665
753
}
666
- emitted_any
754
+ result
667
755
}
668
756
}
669
757
0 commit comments