1 #[cfg(feature = "async")] 2 use core::task::Waker; 3 4 use crate::iface::Context; 5 use crate::time::{Duration, Instant}; 6 use crate::wire::dhcpv4::field as dhcpv4_field; 7 use crate::wire::{ 8 DhcpMessageType, DhcpPacket, DhcpRepr, IpAddress, IpProtocol, Ipv4Address, Ipv4Cidr, Ipv4Repr, 9 UdpRepr, DHCP_CLIENT_PORT, DHCP_MAX_DNS_SERVER_COUNT, DHCP_SERVER_PORT, UDP_HEADER_LEN, 10 }; 11 use crate::wire::{DhcpOption, HardwareAddress}; 12 use heapless::Vec; 13 14 #[cfg(feature = "async")] 15 use super::WakerRegistration; 16 17 use super::PollAt; 18 19 const DEFAULT_LEASE_DURATION: Duration = Duration::from_secs(120); 20 21 const DEFAULT_PARAMETER_REQUEST_LIST: &[u8] = &[ 22 dhcpv4_field::OPT_SUBNET_MASK, 23 dhcpv4_field::OPT_ROUTER, 24 dhcpv4_field::OPT_DOMAIN_NAME_SERVER, 25 ]; 26 27 /// IPv4 configuration data provided by the DHCP server. 28 #[derive(Debug, Eq, PartialEq, Clone)] 29 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 30 pub struct Config<'a> { 31 /// Information on how to reach the DHCP server that responded with DHCP 32 /// configuration. 33 pub server: ServerInfo, 34 /// IP address 35 pub address: Ipv4Cidr, 36 /// Router address, also known as default gateway. Does not necessarily 37 /// match the DHCP server's address. 38 pub router: Option<Ipv4Address>, 39 /// DNS servers 40 pub dns_servers: Vec<Ipv4Address, DHCP_MAX_DNS_SERVER_COUNT>, 41 /// Received DHCP packet 42 pub packet: Option<DhcpPacket<&'a [u8]>>, 43 } 44 45 /// Information on how to reach a DHCP server. 46 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 47 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 48 pub struct ServerInfo { 49 /// IP address to use as destination in outgoing packets 50 pub address: Ipv4Address, 51 /// Server identifier to use in outgoing packets. Usually equal to server_address, 52 /// but may differ in some situations (eg DHCP relays) 53 pub identifier: Ipv4Address, 54 } 55 56 #[derive(Debug)] 57 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 58 struct DiscoverState { 59 /// When to send next request 60 retry_at: Instant, 61 } 62 63 #[derive(Debug)] 64 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 65 struct RequestState { 66 /// When to send next request 67 retry_at: Instant, 68 /// How many retries have been done 69 retry: u16, 70 /// Server we're trying to request from 71 server: ServerInfo, 72 /// IP address that we're trying to request. 73 requested_ip: Ipv4Address, 74 } 75 76 #[derive(Debug)] 77 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 78 struct RenewState { 79 /// Active network config 80 config: Config<'static>, 81 82 /// Renew timer. When reached, we will start attempting 83 /// to renew this lease with the DHCP server. 84 /// Must be less or equal than `expires_at`. 85 renew_at: Instant, 86 /// Expiration timer. When reached, this lease is no longer valid, so it must be 87 /// thrown away and the ethernet interface deconfigured. 88 expires_at: Instant, 89 } 90 91 #[derive(Debug)] 92 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 93 enum ClientState { 94 /// Discovering the DHCP server 95 Discovering(DiscoverState), 96 /// Requesting an address 97 Requesting(RequestState), 98 /// Having an address, refresh it periodically. 99 Renewing(RenewState), 100 } 101 102 /// Timeout and retry configuration. 103 #[derive(Debug, PartialEq, Eq, Copy, Clone)] 104 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 105 pub struct RetryConfig { 106 pub discover_timeout: Duration, 107 /// The REQUEST timeout doubles every 2 tries. 108 pub initial_request_timeout: Duration, 109 pub request_retries: u16, 110 pub min_renew_timeout: Duration, 111 } 112 113 impl Default for RetryConfig { default() -> Self114 fn default() -> Self { 115 Self { 116 discover_timeout: Duration::from_secs(10), 117 initial_request_timeout: Duration::from_secs(5), 118 request_retries: 5, 119 min_renew_timeout: Duration::from_secs(60), 120 } 121 } 122 } 123 124 /// Return value for the `Dhcpv4Socket::poll` function 125 #[derive(Debug, PartialEq, Eq)] 126 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 127 pub enum Event<'a> { 128 /// Configuration has been lost (for example, the lease has expired) 129 Deconfigured, 130 /// Configuration has been newly acquired, or modified. 131 Configured(Config<'a>), 132 } 133 134 #[derive(Debug)] 135 pub struct Socket<'a> { 136 /// State of the DHCP client. 137 state: ClientState, 138 /// Set to true on config/state change, cleared back to false by the `config` function. 139 config_changed: bool, 140 /// xid of the last sent message. 141 transaction_id: u32, 142 143 /// Max lease duration. If set, it sets a maximum cap to the server-provided lease duration. 144 /// Useful to react faster to IP configuration changes and to test whether renews work correctly. 145 max_lease_duration: Option<Duration>, 146 147 retry_config: RetryConfig, 148 149 /// Ignore NAKs. 150 ignore_naks: bool, 151 152 /// Server port config 153 pub(crate) server_port: u16, 154 155 /// Client port config 156 pub(crate) client_port: u16, 157 158 /// A buffer contains options additional to be added to outgoing DHCP 159 /// packets. 160 outgoing_options: &'a [DhcpOption<'a>], 161 /// A buffer containing all requested parameters. 162 parameter_request_list: Option<&'a [u8]>, 163 164 /// Incoming DHCP packets are copied into this buffer, overwriting the previous. 165 receive_packet_buffer: Option<&'a mut [u8]>, 166 167 /// Waker registration 168 #[cfg(feature = "async")] 169 waker: WakerRegistration, 170 } 171 172 /// DHCP client socket. 173 /// 174 /// The socket acquires an IP address configuration through DHCP autonomously. 175 /// You must query the configuration with `.poll()` after every call to `Interface::poll()`, 176 /// and apply the configuration to the `Interface`. 177 impl<'a> Socket<'a> { 178 /// Create a DHCPv4 socket 179 #[allow(clippy::new_without_default)] new() -> Self180 pub fn new() -> Self { 181 Socket { 182 state: ClientState::Discovering(DiscoverState { 183 retry_at: Instant::from_millis(0), 184 }), 185 config_changed: true, 186 transaction_id: 1, 187 max_lease_duration: None, 188 retry_config: RetryConfig::default(), 189 ignore_naks: false, 190 outgoing_options: &[], 191 parameter_request_list: None, 192 receive_packet_buffer: None, 193 #[cfg(feature = "async")] 194 waker: WakerRegistration::new(), 195 server_port: DHCP_SERVER_PORT, 196 client_port: DHCP_CLIENT_PORT, 197 } 198 } 199 200 /// Set the retry/timeouts configuration. set_retry_config(&mut self, config: RetryConfig)201 pub fn set_retry_config(&mut self, config: RetryConfig) { 202 self.retry_config = config; 203 } 204 205 /// Set the outgoing options. set_outgoing_options(&mut self, options: &'a [DhcpOption<'a>])206 pub fn set_outgoing_options(&mut self, options: &'a [DhcpOption<'a>]) { 207 self.outgoing_options = options; 208 } 209 210 /// Set the buffer into which incoming DHCP packets are copied into. set_receive_packet_buffer(&mut self, buffer: &'a mut [u8])211 pub fn set_receive_packet_buffer(&mut self, buffer: &'a mut [u8]) { 212 self.receive_packet_buffer = Some(buffer); 213 } 214 215 /// Set the parameter request list. 216 /// 217 /// This should contain at least `OPT_SUBNET_MASK` (`1`), `OPT_ROUTER` 218 /// (`3`), and `OPT_DOMAIN_NAME_SERVER` (`6`). set_parameter_request_list(&mut self, parameter_request_list: &'a [u8])219 pub fn set_parameter_request_list(&mut self, parameter_request_list: &'a [u8]) { 220 self.parameter_request_list = Some(parameter_request_list); 221 } 222 223 /// Get the configured max lease duration. 224 /// 225 /// See also [`Self::set_max_lease_duration()`] max_lease_duration(&self) -> Option<Duration>226 pub fn max_lease_duration(&self) -> Option<Duration> { 227 self.max_lease_duration 228 } 229 230 /// Set the max lease duration. 231 /// 232 /// When set, the lease duration will be capped at the configured duration if the 233 /// DHCP server gives us a longer lease. This is generally not recommended, but 234 /// can be useful for debugging or reacting faster to network configuration changes. 235 /// 236 /// If None, no max is applied (the lease duration from the DHCP server is used.) set_max_lease_duration(&mut self, max_lease_duration: Option<Duration>)237 pub fn set_max_lease_duration(&mut self, max_lease_duration: Option<Duration>) { 238 self.max_lease_duration = max_lease_duration; 239 } 240 241 /// Get whether to ignore NAKs. 242 /// 243 /// See also [`Self::set_ignore_naks()`] ignore_naks(&self) -> bool244 pub fn ignore_naks(&self) -> bool { 245 self.ignore_naks 246 } 247 248 /// Set whether to ignore NAKs. 249 /// 250 /// This is not compliant with the DHCP RFCs, since theoretically 251 /// we must stop using the assigned IP when receiving a NAK. This 252 /// can increase reliability on broken networks with buggy routers 253 /// or rogue DHCP servers, however. set_ignore_naks(&mut self, ignore_naks: bool)254 pub fn set_ignore_naks(&mut self, ignore_naks: bool) { 255 self.ignore_naks = ignore_naks; 256 } 257 258 /// Set the server/client port 259 /// 260 /// Allows you to specify the ports used by DHCP. 261 /// This is meant to support esoteric usecases allowed by the dhclient program. set_ports(&mut self, server_port: u16, client_port: u16)262 pub fn set_ports(&mut self, server_port: u16, client_port: u16) { 263 self.server_port = server_port; 264 self.client_port = client_port; 265 } 266 poll_at(&self, _cx: &mut Context) -> PollAt267 pub(crate) fn poll_at(&self, _cx: &mut Context) -> PollAt { 268 let t = match &self.state { 269 ClientState::Discovering(state) => state.retry_at, 270 ClientState::Requesting(state) => state.retry_at, 271 ClientState::Renewing(state) => state.renew_at.min(state.expires_at), 272 }; 273 PollAt::Time(t) 274 } 275 process( &mut self, cx: &mut Context, ip_repr: &Ipv4Repr, repr: &UdpRepr, payload: &[u8], )276 pub(crate) fn process( 277 &mut self, 278 cx: &mut Context, 279 ip_repr: &Ipv4Repr, 280 repr: &UdpRepr, 281 payload: &[u8], 282 ) { 283 let src_ip = ip_repr.src_addr; 284 285 // This is enforced in interface.rs. 286 assert!(repr.src_port == self.server_port && repr.dst_port == self.client_port); 287 288 let dhcp_packet = match DhcpPacket::new_checked(payload) { 289 Ok(dhcp_packet) => dhcp_packet, 290 Err(e) => { 291 net_debug!("DHCP invalid pkt from {}: {:?}", src_ip, e); 292 return; 293 } 294 }; 295 let dhcp_repr = match DhcpRepr::parse(&dhcp_packet) { 296 Ok(dhcp_repr) => dhcp_repr, 297 Err(e) => { 298 net_debug!("DHCP error parsing pkt from {}: {:?}", src_ip, e); 299 return; 300 } 301 }; 302 303 let Some(HardwareAddress::Ethernet(ethernet_addr)) = cx.hardware_addr() else { 304 panic!("using DHCPv4 socket with a non-ethernet hardware address."); 305 }; 306 307 if dhcp_repr.client_hardware_address != ethernet_addr { 308 return; 309 } 310 if dhcp_repr.transaction_id != self.transaction_id { 311 return; 312 } 313 let server_identifier = match dhcp_repr.server_identifier { 314 Some(server_identifier) => server_identifier, 315 None => { 316 net_debug!( 317 "DHCP ignoring {:?} because missing server_identifier", 318 dhcp_repr.message_type 319 ); 320 return; 321 } 322 }; 323 324 net_debug!( 325 "DHCP recv {:?} from {}: {:?}", 326 dhcp_repr.message_type, 327 src_ip, 328 dhcp_repr 329 ); 330 331 // Copy over the payload into the receive packet buffer. 332 if let Some(buffer) = self.receive_packet_buffer.as_mut() { 333 if let Some(buffer) = buffer.get_mut(..payload.len()) { 334 buffer.copy_from_slice(payload); 335 } 336 } 337 338 match (&mut self.state, dhcp_repr.message_type) { 339 (ClientState::Discovering(_state), DhcpMessageType::Offer) => { 340 if !dhcp_repr.your_ip.is_unicast() { 341 net_debug!("DHCP ignoring OFFER because your_ip is not unicast"); 342 return; 343 } 344 345 self.state = ClientState::Requesting(RequestState { 346 retry_at: cx.now(), 347 retry: 0, 348 server: ServerInfo { 349 address: src_ip, 350 identifier: server_identifier, 351 }, 352 requested_ip: dhcp_repr.your_ip, // use the offered ip 353 }); 354 } 355 (ClientState::Requesting(state), DhcpMessageType::Ack) => { 356 if let Some((config, renew_at, expires_at)) = 357 Self::parse_ack(cx.now(), &dhcp_repr, self.max_lease_duration, state.server) 358 { 359 self.state = ClientState::Renewing(RenewState { 360 config, 361 renew_at, 362 expires_at, 363 }); 364 self.config_changed(); 365 } 366 } 367 (ClientState::Requesting(_), DhcpMessageType::Nak) => { 368 if !self.ignore_naks { 369 self.reset(); 370 } 371 } 372 (ClientState::Renewing(state), DhcpMessageType::Ack) => { 373 if let Some((config, renew_at, expires_at)) = Self::parse_ack( 374 cx.now(), 375 &dhcp_repr, 376 self.max_lease_duration, 377 state.config.server, 378 ) { 379 state.renew_at = renew_at; 380 state.expires_at = expires_at; 381 // The `receive_packet_buffer` field isn't populated until 382 // the client asks for the state, but receiving any packet 383 // will change it, so we indicate that the config has 384 // changed every time if the receive packet buffer is set, 385 // but we only write changes to the rest of the config now. 386 let config_changed = 387 state.config != config || self.receive_packet_buffer.is_some(); 388 if state.config != config { 389 state.config = config; 390 } 391 if config_changed { 392 self.config_changed(); 393 } 394 } 395 } 396 (ClientState::Renewing(_), DhcpMessageType::Nak) => { 397 if !self.ignore_naks { 398 self.reset(); 399 } 400 } 401 _ => { 402 net_debug!( 403 "DHCP ignoring {:?}: unexpected in current state", 404 dhcp_repr.message_type 405 ); 406 } 407 } 408 } 409 parse_ack( now: Instant, dhcp_repr: &DhcpRepr, max_lease_duration: Option<Duration>, server: ServerInfo, ) -> Option<(Config<'static>, Instant, Instant)>410 fn parse_ack( 411 now: Instant, 412 dhcp_repr: &DhcpRepr, 413 max_lease_duration: Option<Duration>, 414 server: ServerInfo, 415 ) -> Option<(Config<'static>, Instant, Instant)> { 416 let subnet_mask = match dhcp_repr.subnet_mask { 417 Some(subnet_mask) => subnet_mask, 418 None => { 419 net_debug!("DHCP ignoring ACK because missing subnet_mask"); 420 return None; 421 } 422 }; 423 424 let prefix_len = match IpAddress::Ipv4(subnet_mask).prefix_len() { 425 Some(prefix_len) => prefix_len, 426 None => { 427 net_debug!("DHCP ignoring ACK because subnet_mask is not a valid mask"); 428 return None; 429 } 430 }; 431 432 if !dhcp_repr.your_ip.is_unicast() { 433 net_debug!("DHCP ignoring ACK because your_ip is not unicast"); 434 return None; 435 } 436 437 let mut lease_duration = dhcp_repr 438 .lease_duration 439 .map(|d| Duration::from_secs(d as _)) 440 .unwrap_or(DEFAULT_LEASE_DURATION); 441 if let Some(max_lease_duration) = max_lease_duration { 442 lease_duration = lease_duration.min(max_lease_duration); 443 } 444 445 // Cleanup the DNS servers list, keeping only unicasts/ 446 // TP-Link TD-W8970 sends 0.0.0.0 as second DNS server if there's only one configured :( 447 let mut dns_servers = Vec::new(); 448 449 dhcp_repr 450 .dns_servers 451 .iter() 452 .flatten() 453 .filter(|s| s.is_unicast()) 454 .for_each(|a| { 455 // This will never produce an error, as both the arrays and `dns_servers` 456 // have length DHCP_MAX_DNS_SERVER_COUNT 457 dns_servers.push(*a).ok(); 458 }); 459 460 let config = Config { 461 server, 462 address: Ipv4Cidr::new(dhcp_repr.your_ip, prefix_len), 463 router: dhcp_repr.router, 464 dns_servers, 465 packet: None, 466 }; 467 468 // Set renew time as per RFC 2131: 469 // The renew time (T1) can be specified by the server using option 58: 470 let renew_duration = dhcp_repr 471 .renew_duration 472 .map(|d| Duration::from_secs(d as u64)) 473 // Since we don't follow the REBINDING part of the spec, when no 474 // explicit T1 time is given, we will also consider the rebinding 475 // time if it is given and less than the default. 476 .or_else(|| { 477 dhcp_repr 478 .rebind_duration 479 .map(|d| Duration::from_secs(d as u64).min(lease_duration / 2)) 480 }) 481 // Otherwise, we use the default T1 time, which is half the lease 482 // duration. 483 .unwrap_or(lease_duration / 2); 484 let renew_at = now + renew_duration; 485 let expires_at = now + lease_duration; 486 487 Some((config, renew_at, expires_at)) 488 } 489 490 #[cfg(not(test))] random_transaction_id(cx: &mut Context) -> u32491 fn random_transaction_id(cx: &mut Context) -> u32 { 492 cx.rand().rand_u32() 493 } 494 495 #[cfg(test)] random_transaction_id(_cx: &mut Context) -> u32496 fn random_transaction_id(_cx: &mut Context) -> u32 { 497 0x12345678 498 } 499 dispatch<F, E>(&mut self, cx: &mut Context, emit: F) -> Result<(), E> where F: FnOnce(&mut Context, (Ipv4Repr, UdpRepr, DhcpRepr)) -> Result<(), E>,500 pub(crate) fn dispatch<F, E>(&mut self, cx: &mut Context, emit: F) -> Result<(), E> 501 where 502 F: FnOnce(&mut Context, (Ipv4Repr, UdpRepr, DhcpRepr)) -> Result<(), E>, 503 { 504 // note: Dhcpv4Socket is only usable in ethernet mediums, so the 505 // unwrap can never fail. 506 let Some(HardwareAddress::Ethernet(ethernet_addr)) = cx.hardware_addr() else { 507 panic!("using DHCPv4 socket with a non-ethernet hardware address."); 508 }; 509 510 // Worst case biggest IPv4 header length. 511 // 0x0f * 4 = 60 bytes. 512 const MAX_IPV4_HEADER_LEN: usize = 60; 513 514 // We don't directly modify self.transaction_id because sending the packet 515 // may fail. We only want to update state after succesfully sending. 516 let next_transaction_id = Self::random_transaction_id(cx); 517 518 let mut dhcp_repr = DhcpRepr { 519 message_type: DhcpMessageType::Discover, 520 transaction_id: next_transaction_id, 521 secs: 0, 522 client_hardware_address: ethernet_addr, 523 client_ip: Ipv4Address::UNSPECIFIED, 524 your_ip: Ipv4Address::UNSPECIFIED, 525 server_ip: Ipv4Address::UNSPECIFIED, 526 router: None, 527 subnet_mask: None, 528 relay_agent_ip: Ipv4Address::UNSPECIFIED, 529 broadcast: false, 530 requested_ip: None, 531 client_identifier: Some(ethernet_addr), 532 server_identifier: None, 533 parameter_request_list: Some( 534 self.parameter_request_list 535 .unwrap_or(DEFAULT_PARAMETER_REQUEST_LIST), 536 ), 537 max_size: Some((cx.ip_mtu() - MAX_IPV4_HEADER_LEN - UDP_HEADER_LEN) as u16), 538 lease_duration: None, 539 renew_duration: None, 540 rebind_duration: None, 541 dns_servers: None, 542 additional_options: self.outgoing_options, 543 }; 544 545 let udp_repr = UdpRepr { 546 src_port: self.client_port, 547 dst_port: self.server_port, 548 }; 549 550 let mut ipv4_repr = Ipv4Repr { 551 src_addr: Ipv4Address::UNSPECIFIED, 552 dst_addr: Ipv4Address::BROADCAST, 553 next_header: IpProtocol::Udp, 554 payload_len: 0, // filled right before emit 555 hop_limit: 64, 556 }; 557 558 match &mut self.state { 559 ClientState::Discovering(state) => { 560 if cx.now() < state.retry_at { 561 return Ok(()); 562 } 563 564 // send packet 565 net_debug!( 566 "DHCP send DISCOVER to {}: {:?}", 567 ipv4_repr.dst_addr, 568 dhcp_repr 569 ); 570 ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len(); 571 emit(cx, (ipv4_repr, udp_repr, dhcp_repr))?; 572 573 // Update state AFTER the packet has been successfully sent. 574 state.retry_at = cx.now() + self.retry_config.discover_timeout; 575 self.transaction_id = next_transaction_id; 576 Ok(()) 577 } 578 ClientState::Requesting(state) => { 579 if cx.now() < state.retry_at { 580 return Ok(()); 581 } 582 583 if state.retry >= self.retry_config.request_retries { 584 net_debug!("DHCP request retries exceeded, restarting discovery"); 585 self.reset(); 586 return Ok(()); 587 } 588 589 dhcp_repr.message_type = DhcpMessageType::Request; 590 dhcp_repr.requested_ip = Some(state.requested_ip); 591 dhcp_repr.server_identifier = Some(state.server.identifier); 592 593 net_debug!( 594 "DHCP send request to {}: {:?}", 595 ipv4_repr.dst_addr, 596 dhcp_repr 597 ); 598 ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len(); 599 emit(cx, (ipv4_repr, udp_repr, dhcp_repr))?; 600 601 // Exponential backoff: Double every 2 retries. 602 state.retry_at = cx.now() 603 + (self.retry_config.initial_request_timeout << (state.retry as u32 / 2)); 604 state.retry += 1; 605 606 self.transaction_id = next_transaction_id; 607 Ok(()) 608 } 609 ClientState::Renewing(state) => { 610 if state.expires_at <= cx.now() { 611 net_debug!("DHCP lease expired"); 612 self.reset(); 613 // return Ok so we get polled again 614 return Ok(()); 615 } 616 617 if cx.now() < state.renew_at { 618 return Ok(()); 619 } 620 621 ipv4_repr.src_addr = state.config.address.address(); 622 ipv4_repr.dst_addr = state.config.server.address; 623 dhcp_repr.message_type = DhcpMessageType::Request; 624 dhcp_repr.client_ip = state.config.address.address(); 625 626 net_debug!("DHCP send renew to {}: {:?}", ipv4_repr.dst_addr, dhcp_repr); 627 ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len(); 628 emit(cx, (ipv4_repr, udp_repr, dhcp_repr))?; 629 630 // In both RENEWING and REBINDING states, if the client receives no 631 // response to its DHCPREQUEST message, the client SHOULD wait one-half 632 // of the remaining time until T2 (in RENEWING state) and one-half of 633 // the remaining lease time (in REBINDING state), down to a minimum of 634 // 60 seconds, before retransmitting the DHCPREQUEST message. 635 state.renew_at = cx.now() 636 + self 637 .retry_config 638 .min_renew_timeout 639 .max((state.expires_at - cx.now()) / 2); 640 641 self.transaction_id = next_transaction_id; 642 Ok(()) 643 } 644 } 645 } 646 647 /// Reset state and restart discovery phase. 648 /// 649 /// Use this to speed up acquisition of an address in a new 650 /// network if a link was down and it is now back up. reset(&mut self)651 pub fn reset(&mut self) { 652 net_trace!("DHCP reset"); 653 if let ClientState::Renewing(_) = &self.state { 654 self.config_changed(); 655 } 656 self.state = ClientState::Discovering(DiscoverState { 657 retry_at: Instant::from_millis(0), 658 }); 659 } 660 661 /// Query the socket for configuration changes. 662 /// 663 /// The socket has an internal "configuration changed" flag. If 664 /// set, this function returns the configuration and resets the flag. poll(&mut self) -> Option<Event>665 pub fn poll(&mut self) -> Option<Event> { 666 if !self.config_changed { 667 None 668 } else if let ClientState::Renewing(state) = &self.state { 669 self.config_changed = false; 670 Some(Event::Configured(Config { 671 server: state.config.server, 672 address: state.config.address, 673 router: state.config.router, 674 dns_servers: state.config.dns_servers.clone(), 675 packet: self 676 .receive_packet_buffer 677 .as_deref() 678 .map(DhcpPacket::new_unchecked), 679 })) 680 } else { 681 self.config_changed = false; 682 Some(Event::Deconfigured) 683 } 684 } 685 686 /// This function _must_ be called when the configuration provided to the 687 /// interface, by this DHCP socket, changes. It will update the `config_changed` field 688 /// so that a subsequent call to `poll` will yield an event, and wake a possible waker. config_changed(&mut self)689 pub(crate) fn config_changed(&mut self) { 690 self.config_changed = true; 691 #[cfg(feature = "async")] 692 self.waker.wake(); 693 } 694 695 /// Register a waker. 696 /// 697 /// The waker is woken on state changes that might affect the return value 698 /// of `poll` method calls, which indicates a new state in the DHCP configuration 699 /// provided by this DHCP socket. 700 /// 701 /// Notes: 702 /// 703 /// - Only one waker can be registered at a time. If another waker was previously registered, 704 /// it is overwritten and will no longer be woken. 705 /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes. 706 #[cfg(feature = "async")] register_waker(&mut self, waker: &Waker)707 pub fn register_waker(&mut self, waker: &Waker) { 708 self.waker.register(waker) 709 } 710 } 711 712 #[cfg(test)] 713 mod test { 714 715 use std::ops::{Deref, DerefMut}; 716 717 use super::*; 718 use crate::wire::EthernetAddress; 719 720 // =========================================================================================// 721 // Helper functions 722 723 struct TestSocket { 724 socket: Socket<'static>, 725 cx: Context, 726 } 727 728 impl Deref for TestSocket { 729 type Target = Socket<'static>; deref(&self) -> &Self::Target730 fn deref(&self) -> &Self::Target { 731 &self.socket 732 } 733 } 734 735 impl DerefMut for TestSocket { deref_mut(&mut self) -> &mut Self::Target736 fn deref_mut(&mut self) -> &mut Self::Target { 737 &mut self.socket 738 } 739 } 740 send( s: &mut TestSocket, timestamp: Instant, (ip_repr, udp_repr, dhcp_repr): (Ipv4Repr, UdpRepr, DhcpRepr), )741 fn send( 742 s: &mut TestSocket, 743 timestamp: Instant, 744 (ip_repr, udp_repr, dhcp_repr): (Ipv4Repr, UdpRepr, DhcpRepr), 745 ) { 746 s.cx.set_now(timestamp); 747 748 net_trace!("send: {:?}", ip_repr); 749 net_trace!(" {:?}", udp_repr); 750 net_trace!(" {:?}", dhcp_repr); 751 752 let mut payload = vec![0; dhcp_repr.buffer_len()]; 753 dhcp_repr 754 .emit(&mut DhcpPacket::new_unchecked(&mut payload)) 755 .unwrap(); 756 757 s.socket.process(&mut s.cx, &ip_repr, &udp_repr, &payload) 758 } 759 recv(s: &mut TestSocket, timestamp: Instant, reprs: &[(Ipv4Repr, UdpRepr, DhcpRepr)])760 fn recv(s: &mut TestSocket, timestamp: Instant, reprs: &[(Ipv4Repr, UdpRepr, DhcpRepr)]) { 761 s.cx.set_now(timestamp); 762 763 let mut i = 0; 764 765 while s.socket.poll_at(&mut s.cx) <= PollAt::Time(timestamp) { 766 let _ = s 767 .socket 768 .dispatch(&mut s.cx, |_, (mut ip_repr, udp_repr, dhcp_repr)| { 769 assert_eq!(ip_repr.next_header, IpProtocol::Udp); 770 assert_eq!( 771 ip_repr.payload_len, 772 udp_repr.header_len() + dhcp_repr.buffer_len() 773 ); 774 775 // We validated the payload len, change it to 0 to make equality testing easier 776 ip_repr.payload_len = 0; 777 778 net_trace!("recv: {:?}", ip_repr); 779 net_trace!(" {:?}", udp_repr); 780 net_trace!(" {:?}", dhcp_repr); 781 782 let got_repr = (ip_repr, udp_repr, dhcp_repr); 783 match reprs.get(i) { 784 Some(want_repr) => assert_eq!(want_repr, &got_repr), 785 None => panic!("Too many reprs emitted"), 786 } 787 i += 1; 788 Ok::<_, ()>(()) 789 }); 790 } 791 792 assert_eq!(i, reprs.len()); 793 } 794 795 macro_rules! send { 796 ($socket:ident, $repr:expr) => 797 (send!($socket, time 0, $repr)); 798 ($socket:ident, time $time:expr, $repr:expr) => 799 (send(&mut $socket, Instant::from_millis($time), $repr)); 800 } 801 802 macro_rules! recv { 803 ($socket:ident, $reprs:expr) => ({ 804 recv!($socket, time 0, $reprs); 805 }); 806 ($socket:ident, time $time:expr, $reprs:expr) => ({ 807 recv(&mut $socket, Instant::from_millis($time), &$reprs); 808 }); 809 } 810 811 // =========================================================================================// 812 // Constants 813 814 const TXID: u32 = 0x12345678; 815 816 const MY_IP: Ipv4Address = Ipv4Address([192, 168, 1, 42]); 817 const SERVER_IP: Ipv4Address = Ipv4Address([192, 168, 1, 1]); 818 const DNS_IP_1: Ipv4Address = Ipv4Address([1, 1, 1, 1]); 819 const DNS_IP_2: Ipv4Address = Ipv4Address([1, 1, 1, 2]); 820 const DNS_IP_3: Ipv4Address = Ipv4Address([1, 1, 1, 3]); 821 const DNS_IPS: &[Ipv4Address] = &[DNS_IP_1, DNS_IP_2, DNS_IP_3]; 822 823 const MASK_24: Ipv4Address = Ipv4Address([255, 255, 255, 0]); 824 825 const MY_MAC: EthernetAddress = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]); 826 827 const IP_BROADCAST: Ipv4Repr = Ipv4Repr { 828 src_addr: Ipv4Address::UNSPECIFIED, 829 dst_addr: Ipv4Address::BROADCAST, 830 next_header: IpProtocol::Udp, 831 payload_len: 0, 832 hop_limit: 64, 833 }; 834 835 const IP_SERVER_BROADCAST: Ipv4Repr = Ipv4Repr { 836 src_addr: SERVER_IP, 837 dst_addr: Ipv4Address::BROADCAST, 838 next_header: IpProtocol::Udp, 839 payload_len: 0, 840 hop_limit: 64, 841 }; 842 843 const IP_RECV: Ipv4Repr = Ipv4Repr { 844 src_addr: SERVER_IP, 845 dst_addr: MY_IP, 846 next_header: IpProtocol::Udp, 847 payload_len: 0, 848 hop_limit: 64, 849 }; 850 851 const IP_SEND: Ipv4Repr = Ipv4Repr { 852 src_addr: MY_IP, 853 dst_addr: SERVER_IP, 854 next_header: IpProtocol::Udp, 855 payload_len: 0, 856 hop_limit: 64, 857 }; 858 859 const UDP_SEND: UdpRepr = UdpRepr { 860 src_port: DHCP_CLIENT_PORT, 861 dst_port: DHCP_SERVER_PORT, 862 }; 863 const UDP_RECV: UdpRepr = UdpRepr { 864 src_port: DHCP_SERVER_PORT, 865 dst_port: DHCP_CLIENT_PORT, 866 }; 867 868 const DIFFERENT_CLIENT_PORT: u16 = 6800; 869 const DIFFERENT_SERVER_PORT: u16 = 6700; 870 871 const UDP_SEND_DIFFERENT_PORT: UdpRepr = UdpRepr { 872 src_port: DIFFERENT_CLIENT_PORT, 873 dst_port: DIFFERENT_SERVER_PORT, 874 }; 875 const UDP_RECV_DIFFERENT_PORT: UdpRepr = UdpRepr { 876 src_port: DIFFERENT_SERVER_PORT, 877 dst_port: DIFFERENT_CLIENT_PORT, 878 }; 879 880 const DHCP_DEFAULT: DhcpRepr = DhcpRepr { 881 message_type: DhcpMessageType::Unknown(99), 882 transaction_id: TXID, 883 secs: 0, 884 client_hardware_address: MY_MAC, 885 client_ip: Ipv4Address::UNSPECIFIED, 886 your_ip: Ipv4Address::UNSPECIFIED, 887 server_ip: Ipv4Address::UNSPECIFIED, 888 router: None, 889 subnet_mask: None, 890 relay_agent_ip: Ipv4Address::UNSPECIFIED, 891 broadcast: false, 892 requested_ip: None, 893 client_identifier: None, 894 server_identifier: None, 895 parameter_request_list: None, 896 dns_servers: None, 897 max_size: None, 898 renew_duration: None, 899 rebind_duration: None, 900 lease_duration: None, 901 additional_options: &[], 902 }; 903 904 const DHCP_DISCOVER: DhcpRepr = DhcpRepr { 905 message_type: DhcpMessageType::Discover, 906 client_identifier: Some(MY_MAC), 907 parameter_request_list: Some(&[1, 3, 6]), 908 max_size: Some(1432), 909 ..DHCP_DEFAULT 910 }; 911 dhcp_offer() -> DhcpRepr<'static>912 fn dhcp_offer() -> DhcpRepr<'static> { 913 DhcpRepr { 914 message_type: DhcpMessageType::Offer, 915 server_ip: SERVER_IP, 916 server_identifier: Some(SERVER_IP), 917 918 your_ip: MY_IP, 919 router: Some(SERVER_IP), 920 subnet_mask: Some(MASK_24), 921 dns_servers: Some(Vec::from_slice(DNS_IPS).unwrap()), 922 lease_duration: Some(1000), 923 924 ..DHCP_DEFAULT 925 } 926 } 927 928 const DHCP_REQUEST: DhcpRepr = DhcpRepr { 929 message_type: DhcpMessageType::Request, 930 client_identifier: Some(MY_MAC), 931 server_identifier: Some(SERVER_IP), 932 max_size: Some(1432), 933 934 requested_ip: Some(MY_IP), 935 parameter_request_list: Some(&[1, 3, 6]), 936 ..DHCP_DEFAULT 937 }; 938 dhcp_ack() -> DhcpRepr<'static>939 fn dhcp_ack() -> DhcpRepr<'static> { 940 DhcpRepr { 941 message_type: DhcpMessageType::Ack, 942 server_ip: SERVER_IP, 943 server_identifier: Some(SERVER_IP), 944 945 your_ip: MY_IP, 946 router: Some(SERVER_IP), 947 subnet_mask: Some(MASK_24), 948 dns_servers: Some(Vec::from_slice(DNS_IPS).unwrap()), 949 lease_duration: Some(1000), 950 951 ..DHCP_DEFAULT 952 } 953 } 954 955 const DHCP_NAK: DhcpRepr = DhcpRepr { 956 message_type: DhcpMessageType::Nak, 957 server_ip: SERVER_IP, 958 server_identifier: Some(SERVER_IP), 959 ..DHCP_DEFAULT 960 }; 961 962 const DHCP_RENEW: DhcpRepr = DhcpRepr { 963 message_type: DhcpMessageType::Request, 964 client_identifier: Some(MY_MAC), 965 // NO server_identifier in renew requests, only in first one! 966 client_ip: MY_IP, 967 max_size: Some(1432), 968 969 requested_ip: None, 970 parameter_request_list: Some(&[1, 3, 6]), 971 ..DHCP_DEFAULT 972 }; 973 974 // =========================================================================================// 975 // Tests 976 socket() -> TestSocket977 fn socket() -> TestSocket { 978 let mut s = Socket::new(); 979 assert_eq!(s.poll(), Some(Event::Deconfigured)); 980 TestSocket { 981 socket: s, 982 cx: Context::mock(), 983 } 984 } 985 socket_different_port() -> TestSocket986 fn socket_different_port() -> TestSocket { 987 let mut s = Socket::new(); 988 s.set_ports(DIFFERENT_SERVER_PORT, DIFFERENT_CLIENT_PORT); 989 990 assert_eq!(s.poll(), Some(Event::Deconfigured)); 991 TestSocket { 992 socket: s, 993 cx: Context::mock(), 994 } 995 } 996 socket_bound() -> TestSocket997 fn socket_bound() -> TestSocket { 998 let mut s = socket(); 999 s.state = ClientState::Renewing(RenewState { 1000 config: Config { 1001 server: ServerInfo { 1002 address: SERVER_IP, 1003 identifier: SERVER_IP, 1004 }, 1005 address: Ipv4Cidr::new(MY_IP, 24), 1006 dns_servers: Vec::from_slice(DNS_IPS).unwrap(), 1007 router: Some(SERVER_IP), 1008 packet: None, 1009 }, 1010 renew_at: Instant::from_secs(500), 1011 expires_at: Instant::from_secs(1000), 1012 }); 1013 1014 s 1015 } 1016 1017 #[test] test_bind()1018 fn test_bind() { 1019 let mut s = socket(); 1020 1021 recv!(s, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1022 assert_eq!(s.poll(), None); 1023 send!(s, (IP_RECV, UDP_RECV, dhcp_offer())); 1024 assert_eq!(s.poll(), None); 1025 recv!(s, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1026 assert_eq!(s.poll(), None); 1027 send!(s, (IP_RECV, UDP_RECV, dhcp_ack())); 1028 1029 assert_eq!( 1030 s.poll(), 1031 Some(Event::Configured(Config { 1032 server: ServerInfo { 1033 address: SERVER_IP, 1034 identifier: SERVER_IP, 1035 }, 1036 address: Ipv4Cidr::new(MY_IP, 24), 1037 dns_servers: Vec::from_slice(DNS_IPS).unwrap(), 1038 router: Some(SERVER_IP), 1039 packet: None, 1040 })) 1041 ); 1042 1043 match &s.state { 1044 ClientState::Renewing(r) => { 1045 assert_eq!(r.renew_at, Instant::from_secs(500)); 1046 assert_eq!(r.expires_at, Instant::from_secs(1000)); 1047 } 1048 _ => panic!("Invalid state"), 1049 } 1050 } 1051 1052 #[test] test_bind_different_ports()1053 fn test_bind_different_ports() { 1054 let mut s = socket_different_port(); 1055 1056 recv!(s, [(IP_BROADCAST, UDP_SEND_DIFFERENT_PORT, DHCP_DISCOVER)]); 1057 assert_eq!(s.poll(), None); 1058 send!(s, (IP_RECV, UDP_RECV_DIFFERENT_PORT, dhcp_offer())); 1059 assert_eq!(s.poll(), None); 1060 recv!(s, [(IP_BROADCAST, UDP_SEND_DIFFERENT_PORT, DHCP_REQUEST)]); 1061 assert_eq!(s.poll(), None); 1062 send!(s, (IP_RECV, UDP_RECV_DIFFERENT_PORT, dhcp_ack())); 1063 1064 assert_eq!( 1065 s.poll(), 1066 Some(Event::Configured(Config { 1067 server: ServerInfo { 1068 address: SERVER_IP, 1069 identifier: SERVER_IP, 1070 }, 1071 address: Ipv4Cidr::new(MY_IP, 24), 1072 dns_servers: Vec::from_slice(DNS_IPS).unwrap(), 1073 router: Some(SERVER_IP), 1074 packet: None, 1075 })) 1076 ); 1077 1078 match &s.state { 1079 ClientState::Renewing(r) => { 1080 assert_eq!(r.renew_at, Instant::from_secs(500)); 1081 assert_eq!(r.expires_at, Instant::from_secs(1000)); 1082 } 1083 _ => panic!("Invalid state"), 1084 } 1085 } 1086 1087 #[test] test_discover_retransmit()1088 fn test_discover_retransmit() { 1089 let mut s = socket(); 1090 1091 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1092 recv!(s, time 1_000, []); 1093 recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1094 recv!(s, time 11_000, []); 1095 recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1096 1097 // check after retransmits it still works 1098 send!(s, time 20_000, (IP_RECV, UDP_RECV, dhcp_offer())); 1099 recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1100 } 1101 1102 #[test] test_request_retransmit()1103 fn test_request_retransmit() { 1104 let mut s = socket(); 1105 1106 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1107 send!(s, time 0, (IP_RECV, UDP_RECV, dhcp_offer())); 1108 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1109 recv!(s, time 1_000, []); 1110 recv!(s, time 5_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1111 recv!(s, time 6_000, []); 1112 recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1113 recv!(s, time 15_000, []); 1114 recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1115 1116 // check after retransmits it still works 1117 send!(s, time 20_000, (IP_RECV, UDP_RECV, dhcp_ack())); 1118 1119 match &s.state { 1120 ClientState::Renewing(r) => { 1121 assert_eq!(r.renew_at, Instant::from_secs(20 + 500)); 1122 assert_eq!(r.expires_at, Instant::from_secs(20 + 1000)); 1123 } 1124 _ => panic!("Invalid state"), 1125 } 1126 } 1127 1128 #[test] test_request_timeout()1129 fn test_request_timeout() { 1130 let mut s = socket(); 1131 1132 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1133 send!(s, time 0, (IP_RECV, UDP_RECV, dhcp_offer())); 1134 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1135 recv!(s, time 5_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1136 recv!(s, time 10_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1137 recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1138 recv!(s, time 30_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1139 1140 // After 5 tries and 70 seconds, it gives up. 1141 // 5 + 5 + 10 + 10 + 20 = 70 1142 recv!(s, time 70_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1143 1144 // check it still works 1145 send!(s, time 60_000, (IP_RECV, UDP_RECV, dhcp_offer())); 1146 recv!(s, time 60_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1147 } 1148 1149 #[test] test_request_nak()1150 fn test_request_nak() { 1151 let mut s = socket(); 1152 1153 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1154 send!(s, time 0, (IP_RECV, UDP_RECV, dhcp_offer())); 1155 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]); 1156 send!(s, time 0, (IP_SERVER_BROADCAST, UDP_RECV, DHCP_NAK)); 1157 recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1158 } 1159 1160 #[test] test_renew()1161 fn test_renew() { 1162 let mut s = socket_bound(); 1163 1164 recv!(s, []); 1165 assert_eq!(s.poll(), None); 1166 recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]); 1167 assert_eq!(s.poll(), None); 1168 1169 match &s.state { 1170 ClientState::Renewing(r) => { 1171 // the expiration still hasn't been bumped, because 1172 // we haven't received the ACK yet 1173 assert_eq!(r.expires_at, Instant::from_secs(1000)); 1174 } 1175 _ => panic!("Invalid state"), 1176 } 1177 1178 send!(s, time 500_000, (IP_RECV, UDP_RECV, dhcp_ack())); 1179 assert_eq!(s.poll(), None); 1180 1181 match &s.state { 1182 ClientState::Renewing(r) => { 1183 // NOW the expiration gets bumped 1184 assert_eq!(r.renew_at, Instant::from_secs(500 + 500)); 1185 assert_eq!(r.expires_at, Instant::from_secs(500 + 1000)); 1186 } 1187 _ => panic!("Invalid state"), 1188 } 1189 } 1190 1191 #[test] test_renew_retransmit()1192 fn test_renew_retransmit() { 1193 let mut s = socket_bound(); 1194 1195 recv!(s, []); 1196 recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]); 1197 recv!(s, time 749_000, []); 1198 recv!(s, time 750_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]); 1199 recv!(s, time 874_000, []); 1200 recv!(s, time 875_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]); 1201 1202 // check it still works 1203 send!(s, time 875_000, (IP_RECV, UDP_RECV, dhcp_ack())); 1204 match &s.state { 1205 ClientState::Renewing(r) => { 1206 // NOW the expiration gets bumped 1207 assert_eq!(r.renew_at, Instant::from_secs(875 + 500)); 1208 assert_eq!(r.expires_at, Instant::from_secs(875 + 1000)); 1209 } 1210 _ => panic!("Invalid state"), 1211 } 1212 } 1213 1214 #[test] test_renew_timeout()1215 fn test_renew_timeout() { 1216 let mut s = socket_bound(); 1217 1218 recv!(s, []); 1219 recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]); 1220 recv!(s, time 999_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]); 1221 recv!(s, time 1_000_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1222 match &s.state { 1223 ClientState::Discovering(_) => {} 1224 _ => panic!("Invalid state"), 1225 } 1226 } 1227 1228 #[test] test_renew_nak()1229 fn test_renew_nak() { 1230 let mut s = socket_bound(); 1231 1232 recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]); 1233 send!(s, time 500_000, (IP_SERVER_BROADCAST, UDP_RECV, DHCP_NAK)); 1234 recv!(s, time 500_000, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]); 1235 } 1236 } 1237