1use crate::iface::Context;
2use crate::time::{Duration, Instant};
3use crate::wire::dhcpv4::field as dhcpv4_field;
4use crate::wire::HardwareAddress;
5use crate::wire::{
6 DhcpMessageType, DhcpPacket, DhcpRepr, IpAddress, IpProtocol, Ipv4Address, Ipv4Cidr, Ipv4Repr,
7 UdpRepr, DHCP_CLIENT_PORT, DHCP_MAX_DNS_SERVER_COUNT, DHCP_SERVER_PORT, UDP_HEADER_LEN,
8};
9use crate::{Error, Result};
10
11use super::PollAt;
12
13const DISCOVER_TIMEOUT: Duration = Duration::from_secs(10);
14
15const REQUEST_TIMEOUT: Duration = Duration::from_secs(5);
18const REQUEST_RETRIES: u16 = 5;
19
20const MIN_RENEW_TIMEOUT: Duration = Duration::from_secs(60);
21
22const DEFAULT_LEASE_DURATION: Duration = Duration::from_secs(120);
23
24const PARAMETER_REQUEST_LIST: &[u8] = &[
25 dhcpv4_field::OPT_SUBNET_MASK,
26 dhcpv4_field::OPT_ROUTER,
27 dhcpv4_field::OPT_DOMAIN_NAME_SERVER,
28];
29
30#[derive(Debug, Eq, PartialEq, Clone, Copy)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33pub struct Config {
34 pub address: Ipv4Cidr,
36 pub router: Option<Ipv4Address>,
39 pub dns_servers: [Option<Ipv4Address>; DHCP_MAX_DNS_SERVER_COUNT],
41}
42
43#[derive(Debug, Clone, Copy)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46struct ServerInfo {
47 address: Ipv4Address,
49 identifier: Ipv4Address,
52}
53
54#[derive(Debug)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56struct DiscoverState {
57 retry_at: Instant,
59}
60
61#[derive(Debug)]
62#[cfg_attr(feature = "defmt", derive(defmt::Format))]
63struct RequestState {
64 retry_at: Instant,
66 retry: u16,
68 server: ServerInfo,
70 requested_ip: Ipv4Address,
72}
73
74#[derive(Debug)]
75#[cfg_attr(feature = "defmt", derive(defmt::Format))]
76struct RenewState {
77 server: ServerInfo,
79 config: Config,
81
82 renew_at: Instant,
86 expires_at: Instant,
89}
90
91#[derive(Debug)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93enum ClientState {
94 Discovering(DiscoverState),
96 Requesting(RequestState),
98 Renewing(RenewState),
100}
101
102#[derive(Debug, PartialEq, Eq)]
104#[cfg_attr(feature = "defmt", derive(defmt::Format))]
105pub enum Event {
106 Deconfigured,
108 Configured(Config),
110}
111
112#[derive(Debug)]
113pub struct Dhcpv4Socket {
114 state: ClientState,
116 config_changed: bool,
118 transaction_id: u32,
120
121 max_lease_duration: Option<Duration>,
124
125 ignore_naks: bool,
127}
128
129impl Dhcpv4Socket {
135 #[allow(clippy::new_without_default)]
137 pub fn new() -> Self {
138 Dhcpv4Socket {
139 state: ClientState::Discovering(DiscoverState {
140 retry_at: Instant::from_millis(0),
141 }),
142 config_changed: true,
143 transaction_id: 1,
144 max_lease_duration: None,
145 ignore_naks: false,
146 }
147 }
148
149 pub fn max_lease_duration(&self) -> Option<Duration> {
153 self.max_lease_duration
154 }
155
156 pub fn set_max_lease_duration(&mut self, max_lease_duration: Option<Duration>) {
164 self.max_lease_duration = max_lease_duration;
165 }
166
167 pub fn ignore_naks(&self) -> bool {
171 self.ignore_naks
172 }
173
174 pub fn set_ignore_naks(&mut self, ignore_naks: bool) {
181 self.ignore_naks = ignore_naks;
182 }
183
184 pub(crate) fn poll_at(&self, _cx: &mut Context) -> PollAt {
185 let t = match &self.state {
186 ClientState::Discovering(state) => state.retry_at,
187 ClientState::Requesting(state) => state.retry_at,
188 ClientState::Renewing(state) => state.renew_at.min(state.expires_at),
189 };
190 PollAt::Time(t)
191 }
192
193 pub(crate) fn process(
194 &mut self,
195 cx: &mut Context,
196 ip_repr: &Ipv4Repr,
197 repr: &UdpRepr,
198 payload: &[u8],
199 ) -> Result<()> {
200 let src_ip = ip_repr.src_addr;
201
202 assert!(repr.src_port == DHCP_SERVER_PORT && repr.dst_port == DHCP_CLIENT_PORT);
204
205 let dhcp_packet = match DhcpPacket::new_checked(payload) {
206 Ok(dhcp_packet) => dhcp_packet,
207 Err(e) => {
208 net_debug!("DHCP invalid pkt from {}: {:?}", src_ip, e);
209 return Ok(());
210 }
211 };
212 let dhcp_repr = match DhcpRepr::parse(&dhcp_packet) {
213 Ok(dhcp_repr) => dhcp_repr,
214 Err(e) => {
215 net_debug!("DHCP error parsing pkt from {}: {:?}", src_ip, e);
216 return Ok(());
217 }
218 };
219 let hardware_addr = if let Some(HardwareAddress::Ethernet(addr)) = cx.hardware_addr() {
220 addr
221 } else {
222 return Err(Error::Malformed);
223 };
224
225 if dhcp_repr.client_hardware_address != hardware_addr {
226 return Ok(());
227 }
228 if dhcp_repr.transaction_id != self.transaction_id {
229 return Ok(());
230 }
231 let server_identifier = match dhcp_repr.server_identifier {
232 Some(server_identifier) => server_identifier,
233 None => {
234 net_debug!(
235 "DHCP ignoring {:?} because missing server_identifier",
236 dhcp_repr.message_type
237 );
238 return Ok(());
239 }
240 };
241
242 net_debug!(
243 "DHCP recv {:?} from {}: {:?}",
244 dhcp_repr.message_type,
245 src_ip,
246 dhcp_repr
247 );
248
249 match (&mut self.state, dhcp_repr.message_type) {
250 (ClientState::Discovering(_state), DhcpMessageType::Offer) => {
251 if !dhcp_repr.your_ip.is_unicast() {
252 net_debug!("DHCP ignoring OFFER because your_ip is not unicast");
253 return Ok(());
254 }
255
256 self.state = ClientState::Requesting(RequestState {
257 retry_at: cx.now(),
258 retry: 0,
259 server: ServerInfo {
260 address: src_ip,
261 identifier: server_identifier,
262 },
263 requested_ip: dhcp_repr.your_ip, });
265 }
266 (ClientState::Requesting(state), DhcpMessageType::Ack) => {
267 if let Some((config, renew_at, expires_at)) =
268 Self::parse_ack(cx.now(), &dhcp_repr, self.max_lease_duration)
269 {
270 self.config_changed = true;
271 self.state = ClientState::Renewing(RenewState {
272 server: state.server,
273 config,
274 renew_at,
275 expires_at,
276 });
277 }
278 }
279 (ClientState::Requesting(_), DhcpMessageType::Nak) => {
280 if !self.ignore_naks {
281 self.reset();
282 }
283 }
284 (ClientState::Renewing(state), DhcpMessageType::Ack) => {
285 if let Some((config, renew_at, expires_at)) =
286 Self::parse_ack(cx.now(), &dhcp_repr, self.max_lease_duration)
287 {
288 state.renew_at = renew_at;
289 state.expires_at = expires_at;
290 if state.config != config {
291 self.config_changed = true;
292 state.config = config;
293 }
294 }
295 }
296 (ClientState::Renewing(_), DhcpMessageType::Nak) => {
297 if !self.ignore_naks {
298 self.reset();
299 }
300 }
301 _ => {
302 net_debug!(
303 "DHCP ignoring {:?}: unexpected in current state",
304 dhcp_repr.message_type
305 );
306 }
307 }
308
309 Ok(())
310 }
311
312 fn parse_ack(
313 now: Instant,
314 dhcp_repr: &DhcpRepr,
315 max_lease_duration: Option<Duration>,
316 ) -> Option<(Config, Instant, Instant)> {
317 let subnet_mask = match dhcp_repr.subnet_mask {
318 Some(subnet_mask) => subnet_mask,
319 None => {
320 net_debug!("DHCP ignoring ACK because missing subnet_mask");
321 return None;
322 }
323 };
324
325 let prefix_len = match IpAddress::Ipv4(subnet_mask).prefix_len() {
326 Some(prefix_len) => prefix_len,
327 None => {
328 net_debug!("DHCP ignoring ACK because subnet_mask is not a valid mask");
329 return None;
330 }
331 };
332
333 if !dhcp_repr.your_ip.is_unicast() {
334 net_debug!("DHCP ignoring ACK because your_ip is not unicast");
335 return None;
336 }
337
338 let mut lease_duration = dhcp_repr
339 .lease_duration
340 .map(|d| Duration::from_secs(d as _))
341 .unwrap_or(DEFAULT_LEASE_DURATION);
342 if let Some(max_lease_duration) = max_lease_duration {
343 lease_duration = lease_duration.min(max_lease_duration);
344 }
345
346 let mut dns_servers = [None; DHCP_MAX_DNS_SERVER_COUNT];
349 if let Some(received) = dhcp_repr.dns_servers {
350 let mut i = 0;
351 for addr in received.iter().flatten() {
352 if addr.is_unicast() {
353 dns_servers[i] = Some(*addr);
355 i += 1;
356 }
357 }
358 }
359 let config = Config {
360 address: Ipv4Cidr::new(dhcp_repr.your_ip, prefix_len),
361 router: dhcp_repr.router,
362 dns_servers: dns_servers,
363 };
364
365 let renew_at = now + lease_duration / 2;
367 let expires_at = now + lease_duration;
368
369 Some((config, renew_at, expires_at))
370 }
371
372 #[cfg(not(test))]
373 fn random_transaction_id(cx: &mut Context) -> u32 {
374 cx.rand().rand_u32()
375 }
376
377 #[cfg(test)]
378 fn random_transaction_id(_cx: &mut Context) -> u32 {
379 0x12345678
380 }
381
382 pub(crate) fn dispatch<F>(&mut self, cx: &mut Context, emit: F) -> Result<()>
383 where
384 F: FnOnce(&mut Context, (Ipv4Repr, UdpRepr, DhcpRepr)) -> Result<()>,
385 {
386 let ethernet_addr = if let Some(HardwareAddress::Ethernet(addr)) = cx.hardware_addr() {
389 addr
390 } else {
391 return Err(Error::Malformed);
392 };
393
394 const MAX_IPV4_HEADER_LEN: usize = 60;
397
398 let next_transaction_id = Self::random_transaction_id(cx);
401
402 let mut dhcp_repr = DhcpRepr {
403 message_type: DhcpMessageType::Discover,
404 transaction_id: next_transaction_id,
405 client_hardware_address: ethernet_addr,
406 client_ip: Ipv4Address::UNSPECIFIED,
407 your_ip: Ipv4Address::UNSPECIFIED,
408 server_ip: Ipv4Address::UNSPECIFIED,
409 router: None,
410 subnet_mask: None,
411 relay_agent_ip: Ipv4Address::UNSPECIFIED,
412 broadcast: false,
413 requested_ip: None,
414 client_identifier: Some(ethernet_addr),
415 server_identifier: None,
416 parameter_request_list: Some(PARAMETER_REQUEST_LIST),
417 max_size: Some((cx.ip_mtu() - MAX_IPV4_HEADER_LEN - UDP_HEADER_LEN) as u16),
418 lease_duration: None,
419 dns_servers: None,
420 };
421
422 let udp_repr = UdpRepr {
423 src_port: DHCP_CLIENT_PORT,
424 dst_port: DHCP_SERVER_PORT,
425 };
426
427 let mut ipv4_repr = Ipv4Repr {
428 src_addr: Ipv4Address::UNSPECIFIED,
429 dst_addr: Ipv4Address::BROADCAST,
430 protocol: IpProtocol::Udp,
431 payload_len: 0, hop_limit: 64,
433 };
434
435 match &mut self.state {
436 ClientState::Discovering(state) => {
437 if cx.now() < state.retry_at {
438 return Err(Error::Exhausted);
439 }
440
441 net_debug!(
443 "DHCP send DISCOVER to {}: {:?}",
444 ipv4_repr.dst_addr,
445 dhcp_repr
446 );
447 ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len();
448 emit(cx, (ipv4_repr, udp_repr, dhcp_repr))?;
449
450 state.retry_at = cx.now() + DISCOVER_TIMEOUT;
452 self.transaction_id = next_transaction_id;
453 Ok(())
454 }
455 ClientState::Requesting(state) => {
456 if cx.now() < state.retry_at {
457 return Err(Error::Exhausted);
458 }
459
460 if state.retry >= REQUEST_RETRIES {
461 net_debug!("DHCP request retries exceeded, restarting discovery");
462 self.reset();
463 return Ok(());
465 }
466
467 dhcp_repr.message_type = DhcpMessageType::Request;
468 dhcp_repr.requested_ip = Some(state.requested_ip);
469 dhcp_repr.server_identifier = Some(state.server.identifier);
470
471 net_debug!(
472 "DHCP send request to {}: {:?}",
473 ipv4_repr.dst_addr,
474 dhcp_repr
475 );
476 ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len();
477 emit(cx, (ipv4_repr, udp_repr, dhcp_repr))?;
478
479 state.retry_at = cx.now() + (REQUEST_TIMEOUT << (state.retry as u32 / 2));
481 state.retry += 1;
482
483 self.transaction_id = next_transaction_id;
484 Ok(())
485 }
486 ClientState::Renewing(state) => {
487 if state.expires_at <= cx.now() {
488 net_debug!("DHCP lease expired");
489 self.reset();
490 return Ok(());
492 }
493
494 if cx.now() < state.renew_at {
495 return Err(Error::Exhausted);
496 }
497
498 ipv4_repr.src_addr = state.config.address.address();
499 ipv4_repr.dst_addr = state.server.address;
500 dhcp_repr.message_type = DhcpMessageType::Request;
501 dhcp_repr.client_ip = state.config.address.address();
502
503 net_debug!("DHCP send renew to {}: {:?}", ipv4_repr.dst_addr, dhcp_repr);
504 ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len();
505 emit(cx, (ipv4_repr, udp_repr, dhcp_repr))?;
506
507 state.renew_at =
513 cx.now() + MIN_RENEW_TIMEOUT.max((state.expires_at - cx.now()) / 2);
514
515 self.transaction_id = next_transaction_id;
516 Ok(())
517 }
518 }
519 }
520
521 pub fn reset(&mut self) {
526 net_trace!("DHCP reset");
527 if let ClientState::Renewing(_) = &self.state {
528 self.config_changed = true;
529 }
530 self.state = ClientState::Discovering(DiscoverState {
531 retry_at: Instant::from_millis(0),
532 });
533 }
534
535 pub fn poll(&mut self) -> Option<Event> {
540 if !self.config_changed {
541 None
542 } else if let ClientState::Renewing(state) = &self.state {
543 self.config_changed = false;
544 Some(Event::Configured(state.config))
545 } else {
546 self.config_changed = false;
547 Some(Event::Deconfigured)
548 }
549 }
550}
551
552#[cfg(test)]
553mod test {
554
555 use std::ops::{Deref, DerefMut};
556
557 use super::*;
558 use crate::wire::EthernetAddress;
559
560 struct TestSocket {
564 socket: Dhcpv4Socket,
565 cx: Context<'static>,
566 }
567
568 impl Deref for TestSocket {
569 type Target = Dhcpv4Socket;
570 fn deref(&self) -> &Self::Target {
571 &self.socket
572 }
573 }
574
575 impl DerefMut for TestSocket {
576 fn deref_mut(&mut self) -> &mut Self::Target {
577 &mut self.socket
578 }
579 }
580
581 fn send(
582 s: &mut TestSocket,
583 timestamp: Instant,
584 (ip_repr, udp_repr, dhcp_repr): (Ipv4Repr, UdpRepr, DhcpRepr),
585 ) -> Result<()> {
586 s.cx.set_now(timestamp);
587
588 net_trace!("send: {:?}", ip_repr);
589 net_trace!(" {:?}", udp_repr);
590 net_trace!(" {:?}", dhcp_repr);
591
592 let mut payload = vec![0; dhcp_repr.buffer_len()];
593 dhcp_repr
594 .emit(&mut DhcpPacket::new_unchecked(&mut payload))
595 .unwrap();
596
597 s.socket.process(&mut s.cx, &ip_repr, &udp_repr, &payload)
598 }
599
600 fn recv(s: &mut TestSocket, timestamp: Instant, reprs: &[(Ipv4Repr, UdpRepr, DhcpRepr)]) {
601 s.cx.set_now(timestamp);
602
603 let mut i = 0;
604
605 while s.socket.poll_at(&mut s.cx) <= PollAt::Time(timestamp) {
606 let _ = s
607 .socket
608 .dispatch(&mut s.cx, |_, (mut ip_repr, udp_repr, dhcp_repr)| {
609 assert_eq!(ip_repr.protocol, IpProtocol::Udp);
610 assert_eq!(
611 ip_repr.payload_len,
612 udp_repr.header_len() + dhcp_repr.buffer_len()
613 );
614
615 ip_repr.payload_len = 0;
617
618 net_trace!("recv: {:?}", ip_repr);
619 net_trace!(" {:?}", udp_repr);
620 net_trace!(" {:?}", dhcp_repr);
621
622 let got_repr = (ip_repr, udp_repr, dhcp_repr);
623 match reprs.get(i) {
624 Some(want_repr) => assert_eq!(want_repr, &got_repr),
625 None => panic!("Too many reprs emitted"),
626 }
627 i += 1;
628 Ok(())
629 });
630 }
631
632 assert_eq!(i, reprs.len());
633 }
634
635 macro_rules! send {
636 ($socket:ident, $repr:expr) =>
637 (send!($socket, time 0, $repr));
638 ($socket:ident, $repr:expr, $result:expr) =>
639 (send!($socket, time 0, $repr, $result));
640 ($socket:ident, time $time:expr, $repr:expr) =>
641 (send!($socket, time $time, $repr, Ok(( ))));
642 ($socket:ident, time $time:expr, $repr:expr, $result:expr) =>
643 (assert_eq!(send(&mut $socket, Instant::from_millis($time), $repr), $result));
644 }
645
646 macro_rules! recv {
647 ($socket:ident, $reprs:expr) => ({
648 recv!($socket, time 0, $reprs);
649 });
650 ($socket:ident, time $time:expr, $reprs:expr) => ({
651 recv(&mut $socket, Instant::from_millis($time), &$reprs);
652 });
653 }
654
655 const TXID: u32 = 0x12345678;
659
660 const MY_IP: Ipv4Address = Ipv4Address([192, 168, 1, 42]);
661 const SERVER_IP: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
662 const DNS_IP_1: Ipv4Address = Ipv4Address([1, 1, 1, 1]);
663 const DNS_IP_2: Ipv4Address = Ipv4Address([1, 1, 1, 2]);
664 const DNS_IP_3: Ipv4Address = Ipv4Address([1, 1, 1, 3]);
665 const DNS_IPS: [Option<Ipv4Address>; DHCP_MAX_DNS_SERVER_COUNT] =
666 [Some(DNS_IP_1), Some(DNS_IP_2), Some(DNS_IP_3)];
667 const MASK_24: Ipv4Address = Ipv4Address([255, 255, 255, 0]);
668
669 const MY_MAC: EthernetAddress = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
670
671 const IP_BROADCAST: Ipv4Repr = Ipv4Repr {
672 src_addr: Ipv4Address::UNSPECIFIED,
673 dst_addr: Ipv4Address::BROADCAST,
674 protocol: IpProtocol::Udp,
675 payload_len: 0,
676 hop_limit: 64,
677 };
678
679 const IP_SERVER_BROADCAST: Ipv4Repr = Ipv4Repr {
680 src_addr: SERVER_IP,
681 dst_addr: Ipv4Address::BROADCAST,
682 protocol: IpProtocol::Udp,
683 payload_len: 0,
684 hop_limit: 64,
685 };
686
687 const IP_RECV: Ipv4Repr = Ipv4Repr {
688 src_addr: SERVER_IP,
689 dst_addr: MY_IP,
690 protocol: IpProtocol::Udp,
691 payload_len: 0,
692 hop_limit: 64,
693 };
694
695 const IP_SEND: Ipv4Repr = Ipv4Repr {
696 src_addr: MY_IP,
697 dst_addr: SERVER_IP,
698 protocol: IpProtocol::Udp,
699 payload_len: 0,
700 hop_limit: 64,
701 };
702
703 const UDP_SEND: UdpRepr = UdpRepr {
704 src_port: 68,
705 dst_port: 67,
706 };
707 const UDP_RECV: UdpRepr = UdpRepr {
708 src_port: 67,
709 dst_port: 68,
710 };
711
712 const DHCP_DEFAULT: DhcpRepr = DhcpRepr {
713 message_type: DhcpMessageType::Unknown(99),
714 transaction_id: TXID,
715 client_hardware_address: MY_MAC,
716 client_ip: Ipv4Address::UNSPECIFIED,
717 your_ip: Ipv4Address::UNSPECIFIED,
718 server_ip: Ipv4Address::UNSPECIFIED,
719 router: None,
720 subnet_mask: None,
721 relay_agent_ip: Ipv4Address::UNSPECIFIED,
722 broadcast: false,
723 requested_ip: None,
724 client_identifier: None,
725 server_identifier: None,
726 parameter_request_list: None,
727 dns_servers: None,
728 max_size: None,
729 lease_duration: None,
730 };
731
732 const DHCP_DISCOVER: DhcpRepr = DhcpRepr {
733 message_type: DhcpMessageType::Discover,
734 client_identifier: Some(MY_MAC),
735 parameter_request_list: Some(&[1, 3, 6]),
736 max_size: Some(1432),
737 ..DHCP_DEFAULT
738 };
739
740 const DHCP_OFFER: DhcpRepr = DhcpRepr {
741 message_type: DhcpMessageType::Offer,
742 server_ip: SERVER_IP,
743 server_identifier: Some(SERVER_IP),
744
745 your_ip: MY_IP,
746 router: Some(SERVER_IP),
747 subnet_mask: Some(MASK_24),
748 dns_servers: Some(DNS_IPS),
749 lease_duration: Some(1000),
750
751 ..DHCP_DEFAULT
752 };
753
754 const DHCP_REQUEST: DhcpRepr = DhcpRepr {
755 message_type: DhcpMessageType::Request,
756 client_identifier: Some(MY_MAC),
757 server_identifier: Some(SERVER_IP),
758 max_size: Some(1432),
759
760 requested_ip: Some(MY_IP),
761 parameter_request_list: Some(&[1, 3, 6]),
762 ..DHCP_DEFAULT
763 };
764
765 const DHCP_ACK: DhcpRepr = DhcpRepr {
766 message_type: DhcpMessageType::Ack,
767 server_ip: SERVER_IP,
768 server_identifier: Some(SERVER_IP),
769
770 your_ip: MY_IP,
771 router: Some(SERVER_IP),
772 subnet_mask: Some(MASK_24),
773 dns_servers: Some(DNS_IPS),
774 lease_duration: Some(1000),
775
776 ..DHCP_DEFAULT
777 };
778
779 const DHCP_NAK: DhcpRepr = DhcpRepr {
780 message_type: DhcpMessageType::Nak,
781 server_ip: SERVER_IP,
782 server_identifier: Some(SERVER_IP),
783 ..DHCP_DEFAULT
784 };
785
786 const DHCP_RENEW: DhcpRepr = DhcpRepr {
787 message_type: DhcpMessageType::Request,
788 client_identifier: Some(MY_MAC),
789 client_ip: MY_IP,
791 max_size: Some(1432),
792
793 requested_ip: None,
794 parameter_request_list: Some(&[1, 3, 6]),
795 ..DHCP_DEFAULT
796 };
797
798 fn socket() -> TestSocket {
802 let mut s = Dhcpv4Socket::new();
803 assert_eq!(s.poll(), Some(Event::Deconfigured));
804 TestSocket {
805 socket: s,
806 cx: Context::mock(),
807 }
808 }
809
810 fn socket_bound() -> TestSocket {
811 let mut s = socket();
812 s.state = ClientState::Renewing(RenewState {
813 config: Config {
814 address: Ipv4Cidr::new(MY_IP, 24),
815 dns_servers: DNS_IPS,
816 router: Some(SERVER_IP),
817 },
818 server: ServerInfo {
819 address: SERVER_IP,
820 identifier: SERVER_IP,
821 },
822 renew_at: Instant::from_secs(500),
823 expires_at: Instant::from_secs(1000),
824 });
825
826 s
827 }
828
829 #[test]
830 fn test_bind() {
831 let mut s = socket();
832
833 recv!(s, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
834 assert_eq!(s.poll(), None);
835 send!(s, (IP_RECV, UDP_RECV, DHCP_OFFER));
836 assert_eq!(s.poll(), None);
837 recv!(s, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
838 assert_eq!(s.poll(), None);
839 send!(s, (IP_RECV, UDP_RECV, DHCP_ACK));
840
841 assert_eq!(
842 s.poll(),
843 Some(Event::Configured(Config {
844 address: Ipv4Cidr::new(MY_IP, 24),
845 dns_servers: DNS_IPS,
846 router: Some(SERVER_IP),
847 }))
848 );
849
850 match &s.state {
851 ClientState::Renewing(r) => {
852 assert_eq!(r.renew_at, Instant::from_secs(500));
853 assert_eq!(r.expires_at, Instant::from_secs(1000));
854 }
855 _ => panic!("Invalid state"),
856 }
857 }
858
859 #[test]
860 fn test_discover_retransmit() {
861 let mut s = socket();
862
863 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
864 recv!(s, time 1_000, []);
865 recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
866 recv!(s, time 11_000, []);
867 recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
868
869 send!(s, time 20_000, (IP_RECV, UDP_RECV, DHCP_OFFER));
871 recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
872 }
873
874 #[test]
875 fn test_request_retransmit() {
876 let mut s = socket();
877
878 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
879 send!(s, time 0, (IP_RECV, UDP_RECV, DHCP_OFFER));
880 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
881 recv!(s, time 1_000, []);
882 recv!(s, time 5_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
883 recv!(s, time 6_000, []);
884 recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
885 recv!(s, time 15_000, []);
886 recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
887
888 send!(s, time 20_000, (IP_RECV, UDP_RECV, DHCP_ACK));
890
891 match &s.state {
892 ClientState::Renewing(r) => {
893 assert_eq!(r.renew_at, Instant::from_secs(20 + 500));
894 assert_eq!(r.expires_at, Instant::from_secs(20 + 1000));
895 }
896 _ => panic!("Invalid state"),
897 }
898 }
899
900 #[test]
901 fn test_request_timeout() {
902 let mut s = socket();
903
904 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
905 send!(s, time 0, (IP_RECV, UDP_RECV, DHCP_OFFER));
906 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
907 recv!(s, time 5_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
908 recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
909 recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
910 recv!(s, time 30_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
911
912 recv!(s, time 70_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
915
916 send!(s, time 60_000, (IP_RECV, UDP_RECV, DHCP_OFFER));
918 recv!(s, time 60_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
919 }
920
921 #[test]
922 fn test_request_nak() {
923 let mut s = socket();
924
925 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
926 send!(s, time 0, (IP_RECV, UDP_RECV, DHCP_OFFER));
927 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
928 send!(s, time 0, (IP_SERVER_BROADCAST, UDP_RECV, DHCP_NAK));
929 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
930 }
931
932 #[test]
933 fn test_renew() {
934 let mut s = socket_bound();
935
936 recv!(s, []);
937 assert_eq!(s.poll(), None);
938 recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
939 assert_eq!(s.poll(), None);
940
941 match &s.state {
942 ClientState::Renewing(r) => {
943 assert_eq!(r.expires_at, Instant::from_secs(1000));
946 }
947 _ => panic!("Invalid state"),
948 }
949
950 send!(s, time 500_000, (IP_RECV, UDP_RECV, DHCP_ACK));
951 assert_eq!(s.poll(), None);
952
953 match &s.state {
954 ClientState::Renewing(r) => {
955 assert_eq!(r.renew_at, Instant::from_secs(500 + 500));
957 assert_eq!(r.expires_at, Instant::from_secs(500 + 1000));
958 }
959 _ => panic!("Invalid state"),
960 }
961 }
962
963 #[test]
964 fn test_renew_retransmit() {
965 let mut s = socket_bound();
966
967 recv!(s, []);
968 recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
969 recv!(s, time 749_000, []);
970 recv!(s, time 750_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
971 recv!(s, time 874_000, []);
972 recv!(s, time 875_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
973
974 send!(s, time 875_000, (IP_RECV, UDP_RECV, DHCP_ACK));
976 match &s.state {
977 ClientState::Renewing(r) => {
978 assert_eq!(r.renew_at, Instant::from_secs(875 + 500));
980 assert_eq!(r.expires_at, Instant::from_secs(875 + 1000));
981 }
982 _ => panic!("Invalid state"),
983 }
984 }
985
986 #[test]
987 fn test_renew_timeout() {
988 let mut s = socket_bound();
989
990 recv!(s, []);
991 recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
992 recv!(s, time 999_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
993 recv!(s, time 1_000_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
994 match &s.state {
995 ClientState::Discovering(_) => {}
996 _ => panic!("Invalid state"),
997 }
998 }
999
1000 #[test]
1001 fn test_renew_nak() {
1002 let mut s = socket_bound();
1003
1004 recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
1005 send!(s, time 500_000, (IP_SERVER_BROADCAST, UDP_RECV, DHCP_NAK));
1006 recv!(s, time 500_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
1007 }
1008}