dhcpv4.rs 50 KB

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