Skip to content

Commit 5d908a7

Browse files
committed
Enable support for DHCP option 15 (domain name)
This makes `smoltcp` work in industrial networks with Windows DHCPs as they do not support option 119.
1 parent b604f56 commit 5d908a7

File tree

6 files changed

+54
-5
lines changed

6 files changed

+54
-5
lines changed

Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ dns-max-name-size-64 = []
249249
dns-max-name-size-128 = []
250250
dns-max-name-size-255 = [] # Default
251251

252+
dhcp-max-domain-name-size-32 = []
253+
dhcp-max-domain-name-size-64 = [] # Default
254+
dhcp-max-domain-name-size-128 = []
255+
dhcp-max-domain-name-size-256 = []
256+
252257
rpl-relations-buffer-count-1 = []
253258
rpl-relations-buffer-count-2 = []
254259
rpl-relations-buffer-count-4 = []

build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ static CONFIGS: &[(&str, usize)] = &[
1919
("DNS_MAX_RESULT_COUNT", 1),
2020
("DNS_MAX_SERVER_COUNT", 1),
2121
("DNS_MAX_NAME_SIZE", 255),
22+
("DHCP_MAX_DOMAIN_NAME_SIZE", 64),
2223
("RPL_RELATIONS_BUFFER_COUNT", 16),
2324
("RPL_PARENTS_BUFFER_COUNT", 8),
2425
// END AUTOGENERATED CONFIG FEATURES

gen_config.py

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def feature(name, default, min, max, pow2=None):
4040
feature("dns_max_result_count", default=1, min=1, max=32, pow2=4)
4141
feature("dns_max_server_count", default=1, min=1, max=32, pow2=4)
4242
feature("dns_max_name_size", default=255, min=64, max=255, pow2=True)
43+
feature("dhcp_max_domain_name_size", default=64, min=32, max=256, pow2=True)
4344
feature("rpl_relations_buffer_count", default=16, min=1, max=128, pow2=True)
4445
feature("rpl_parents_buffer_count", default=8, min=2, max=32, pow2=True)
4546

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ pub mod config {
136136
pub const DNS_MAX_NAME_SIZE: usize = 255;
137137
pub const DNS_MAX_RESULT_COUNT: usize = 1;
138138
pub const DNS_MAX_SERVER_COUNT: usize = 1;
139+
pub const DHCP_MAX_DOMAIN_NAME_SIZE: usize = 64;
139140
pub const FRAGMENTATION_BUFFER_SIZE: usize = 1500;
140141
pub const IFACE_MAX_ADDR_COUNT: usize = 8;
141142
pub const IFACE_MAX_MULTICAST_GROUP_COUNT: usize = 4;

src/socket/dhcpv4.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
use core::str::FromStr;
12
#[cfg(feature = "async")]
23
use core::task::Waker;
34

5+
use crate::config::DHCP_MAX_DOMAIN_NAME_SIZE;
46
use crate::iface::Context;
57
use crate::time::{Duration, Instant};
68
use crate::wire::dhcpv4::field as dhcpv4_field;
@@ -9,7 +11,7 @@ use crate::wire::{
911
UdpRepr, DHCP_CLIENT_PORT, DHCP_MAX_DNS_SERVER_COUNT, DHCP_SERVER_PORT, UDP_HEADER_LEN,
1012
};
1113
use crate::wire::{DhcpOption, HardwareAddress};
12-
use heapless::Vec;
14+
use heapless::{String, Vec};
1315

1416
#[cfg(feature = "async")]
1517
use super::WakerRegistration;
@@ -22,6 +24,7 @@ const DEFAULT_PARAMETER_REQUEST_LIST: &[u8] = &[
2224
dhcpv4_field::OPT_SUBNET_MASK,
2325
dhcpv4_field::OPT_ROUTER,
2426
dhcpv4_field::OPT_DOMAIN_NAME_SERVER,
27+
dhcpv4_field::OPT_DOMAIN_NAME,
2528
];
2629

2730
/// IPv4 configuration data provided by the DHCP server.
@@ -38,6 +41,8 @@ pub struct Config<'a> {
3841
pub router: Option<Ipv4Address>,
3942
/// DNS servers
4043
pub dns_servers: Vec<Ipv4Address, DHCP_MAX_DNS_SERVER_COUNT>,
44+
/// Domain name
45+
pub domain_name: Option<String<DHCP_MAX_DOMAIN_NAME_SIZE>>,
4146
/// Received DHCP packet
4247
pub packet: Option<DhcpPacket<&'a [u8]>>,
4348
}
@@ -494,6 +499,10 @@ impl<'a> Socket<'a> {
494499
address: Ipv4Cidr::new(dhcp_repr.your_ip, prefix_len),
495500
router: dhcp_repr.router,
496501
dns_servers,
502+
domain_name: dhcp_repr
503+
.domain_name
504+
.map(String::from_str)
505+
.and_then(Result::ok),
497506
packet: None,
498507
};
499508

@@ -589,6 +598,7 @@ impl<'a> Socket<'a> {
589598
renew_duration: None,
590599
rebind_duration: None,
591600
dns_servers: None,
601+
domain_name: None,
592602
additional_options: self.outgoing_options,
593603
};
594604

@@ -739,6 +749,7 @@ impl<'a> Socket<'a> {
739749
address: state.config.address,
740750
router: state.config.router,
741751
dns_servers: state.config.dns_servers.clone(),
752+
domain_name: state.config.domain_name.clone(),
742753
packet: self
743754
.receive_packet_buffer
744755
.as_deref()
@@ -779,6 +790,7 @@ impl<'a> Socket<'a> {
779790
#[cfg(test)]
780791
mod test {
781792

793+
use core::str::FromStr;
782794
use std::ops::{Deref, DerefMut};
783795

784796
use super::*;
@@ -886,6 +898,7 @@ mod test {
886898
const DNS_IP_2: Ipv4Address = Ipv4Address([1, 1, 1, 2]);
887899
const DNS_IP_3: Ipv4Address = Ipv4Address([1, 1, 1, 3]);
888900
const DNS_IPS: &[Ipv4Address] = &[DNS_IP_1, DNS_IP_2, DNS_IP_3];
901+
const DOMAIN_NAME: &str = "my.domain";
889902

890903
const MASK_24: Ipv4Address = Ipv4Address([255, 255, 255, 0]);
891904

@@ -969,6 +982,7 @@ mod test {
969982
server_identifier: None,
970983
parameter_request_list: None,
971984
dns_servers: None,
985+
domain_name: None,
972986
max_size: None,
973987
renew_duration: None,
974988
rebind_duration: None,
@@ -979,7 +993,7 @@ mod test {
979993
const DHCP_DISCOVER: DhcpRepr = DhcpRepr {
980994
message_type: DhcpMessageType::Discover,
981995
client_identifier: Some(MY_MAC),
982-
parameter_request_list: Some(&[1, 3, 6]),
996+
parameter_request_list: Some(&[1, 3, 6, 15]),
983997
max_size: Some(1432),
984998
..DHCP_DEFAULT
985999
};
@@ -994,6 +1008,7 @@ mod test {
9941008
router: Some(SERVER_IP),
9951009
subnet_mask: Some(MASK_24),
9961010
dns_servers: Some(Vec::from_slice(DNS_IPS).unwrap()),
1011+
domain_name: Some(DOMAIN_NAME),
9971012
lease_duration: Some(1000),
9981013

9991014
..DHCP_DEFAULT
@@ -1007,7 +1022,7 @@ mod test {
10071022
max_size: Some(1432),
10081023

10091024
requested_ip: Some(MY_IP),
1010-
parameter_request_list: Some(&[1, 3, 6]),
1025+
parameter_request_list: Some(&[1, 3, 6, 15]),
10111026
..DHCP_DEFAULT
10121027
};
10131028

@@ -1021,6 +1036,7 @@ mod test {
10211036
router: Some(SERVER_IP),
10221037
subnet_mask: Some(MASK_24),
10231038
dns_servers: Some(Vec::from_slice(DNS_IPS).unwrap()),
1039+
domain_name: Some(DOMAIN_NAME),
10241040
lease_duration: Some(1000),
10251041

10261042
..DHCP_DEFAULT
@@ -1042,7 +1058,7 @@ mod test {
10421058
max_size: Some(1432),
10431059

10441060
requested_ip: None,
1045-
parameter_request_list: Some(&[1, 3, 6]),
1061+
parameter_request_list: Some(&[1, 3, 6, 15]),
10461062
..DHCP_DEFAULT
10471063
};
10481064

@@ -1054,7 +1070,7 @@ mod test {
10541070
max_size: Some(1432),
10551071

10561072
requested_ip: None,
1057-
parameter_request_list: Some(&[1, 3, 6]),
1073+
parameter_request_list: Some(&[1, 3, 6, 15]),
10581074
..DHCP_DEFAULT
10591075
};
10601076

@@ -1097,6 +1113,7 @@ mod test {
10971113
},
10981114
address: Ipv4Cidr::new(MY_IP, 24),
10991115
dns_servers: Vec::from_slice(DNS_IPS).unwrap(),
1116+
domain_name: Some(String::from_str(DOMAIN_NAME).unwrap()),
11001117
router: Some(SERVER_IP),
11011118
packet: None,
11021119
},
@@ -1132,6 +1149,7 @@ mod test {
11321149
},
11331150
address: Ipv4Cidr::new(MY_IP, 24),
11341151
dns_servers: Vec::from_slice(DNS_IPS).unwrap(),
1152+
domain_name: Some(String::from_str(DOMAIN_NAME).unwrap()),
11351153
router: Some(SERVER_IP),
11361154
packet: None,
11371155
}))
@@ -1170,6 +1188,7 @@ mod test {
11701188
},
11711189
address: Ipv4Cidr::new(MY_IP, 24),
11721190
dns_servers: Vec::from_slice(DNS_IPS).unwrap(),
1191+
domain_name: Some(String::from_str(DOMAIN_NAME).unwrap()),
11731192
router: Some(SERVER_IP),
11741193
packet: None,
11751194
}))

src/wire/dhcpv4.rs

+22
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,8 @@ pub struct Repr<'a> {
647647
pub parameter_request_list: Option<&'a [u8]>,
648648
/// DNS servers
649649
pub dns_servers: Option<Vec<Ipv4Address, MAX_DNS_SERVER_COUNT>>,
650+
/// Domain name
651+
pub domain_name: Option<&'a str>,
650652
/// The maximum size dhcp packet the interface can receive
651653
pub max_size: Option<u16>,
652654
/// The DHCP IP lease duration, specified in seconds.
@@ -692,6 +694,10 @@ impl<'a> Repr<'a> {
692694
len += 2;
693695
len += dns_servers.iter().count() * core::mem::size_of::<u32>();
694696
}
697+
if let Some(domain_name) = &self.domain_name {
698+
len += 2;
699+
len += domain_name.as_bytes().len();
700+
}
695701
if let Some(list) = self.parameter_request_list {
696702
len += list.len() + 2;
697703
}
@@ -738,6 +744,7 @@ impl<'a> Repr<'a> {
738744
let mut subnet_mask = None;
739745
let mut parameter_request_list = None;
740746
let mut dns_servers = None;
747+
let mut domain_name = None;
741748
let mut max_size = None;
742749
let mut lease_duration = None;
743750
let mut renew_duration = None;
@@ -802,6 +809,11 @@ impl<'a> Repr<'a> {
802809
net_trace!("DHCP domain name servers contained invalid address");
803810
}
804811
}
812+
(field::OPT_DOMAIN_NAME, _) => {
813+
if let Ok(name) = core::str::from_utf8(data) {
814+
domain_name = Some(name);
815+
}
816+
}
805817
_ => {}
806818
}
807819
}
@@ -824,6 +836,7 @@ impl<'a> Repr<'a> {
824836
client_identifier,
825837
parameter_request_list,
826838
dns_servers,
839+
domain_name,
827840
max_size,
828841
lease_duration,
829842
renew_duration,
@@ -940,6 +953,13 @@ impl<'a> Repr<'a> {
940953
})?;
941954
}
942955

956+
if let Some(domain_name) = &self.domain_name {
957+
options.emit(DhcpOption {
958+
kind: field::OPT_DOMAIN_NAME,
959+
data: domain_name.as_bytes(),
960+
})?;
961+
}
962+
943963
for option in self.additional_options {
944964
options.emit(*option)?;
945965
}
@@ -1167,6 +1187,7 @@ mod test {
11671187
server_identifier: None,
11681188
parameter_request_list: None,
11691189
dns_servers: None,
1190+
domain_name: None,
11701191
max_size: None,
11711192
renew_duration: None,
11721193
rebind_duration: None,
@@ -1197,6 +1218,7 @@ mod test {
11971218
server_identifier: None,
11981219
parameter_request_list: Some(&[1, 3, 6, 42]),
11991220
dns_servers: None,
1221+
domain_name: None,
12001222
additional_options: &[],
12011223
}
12021224
}

0 commit comments

Comments
 (0)