Skip to content

Commit 4a4ed0e

Browse files
committed
daemon_network - Reworked DHCP, time for testing
1 parent 293765b commit 4a4ed0e

File tree

3 files changed

+154
-54
lines changed

3 files changed

+154
-54
lines changed

Usermode/daemon_network/src/dhcp.rs

Lines changed: 6 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ use std::convert::TryInto;
55
const UDP_PORT_DHCP_CLIENT: u16 = 68;
66
const UDP_PORT_DHCP_SERVER: u16 = 67;
77

8+
mod options;
9+
use self::options::{Opt,OptionsIter};
10+
811
pub struct Dhcp {
912
socket: ::syscalls::net::FreeSocket,
1013
mac_addr: [u8; 6],
@@ -113,6 +116,7 @@ impl Dhcp
113116
let m = u32::from_le_bytes(m);
114117
subnet_len = m.leading_ones() as u8;
115118
},
119+
_ => {},
116120
}
117121
}
118122
let addr = super::make_ipv4(a[0], a[1], a[2], a[3]);
@@ -290,19 +294,11 @@ impl<'a> DhcpPacket<'a> {
290294
PacketOptions::Decoded(opts) => {
291295
p.push(&[0x63, 0x82, 0x53, 0x63]);
292296
for o in opts {
293-
fn push_opt(p: &mut P, op: u8, data: &[u8]) {
297+
o.encode(|op, data| {
294298
p.push(&[op]);
295299
p.push(&[data.len() as u8]);
296300
p.push(data)
297-
}
298-
match *o {
299-
Opt::Malformed(_op, _data) => {
300-
// Ignore malformed data
301-
}
302-
Opt::Unknown(op, data) => push_opt(&mut p, op, data),
303-
Opt::SubnetMask(data) => push_opt(&mut p, 1, &data),
304-
}
305-
panic!("TODO")
301+
})
306302
}
307303
},
308304
PacketOptions::Encoded(options_iter) => {
@@ -323,46 +319,3 @@ fn get<'a, const N: usize>(src: &mut &'a [u8]) -> &'a [u8; N] {
323319
*src = v.1;
324320
v.0.try_into().unwrap()
325321
}
326-
327-
#[derive(Debug)]
328-
enum Opt<'a> {
329-
Malformed(u8, &'a [u8]),
330-
Unknown(u8, &'a [u8]),
331-
SubnetMask([u8; 4]),
332-
}
333-
//impl<'a> Opt<'a> {
334-
// fn encode(self) -> (u8, &'a [u8]) {
335-
// }
336-
//}
337-
#[derive(Debug)] // TODO: Implement using clone+run
338-
struct OptionsIter<'a>(&'a [u8]);
339-
impl<'a> Iterator for OptionsIter<'a> {
340-
type Item = Opt<'a>;
341-
fn next(&mut self) -> Option<Self::Item> {
342-
match self.0 {
343-
[] => None,
344-
[0, tail @ ..] => {
345-
self.0 = tail;
346-
self.next()
347-
},
348-
[_] => {
349-
self.0 = &[];
350-
None
351-
},
352-
&[code, len, ref tail @ ..] => {
353-
let Some( (data,tail) ) = tail.split_at_checked(len as usize) else {
354-
self.0 = &[];
355-
return None;
356-
};
357-
self.0 = tail;
358-
Some(match code {
359-
1 => match data {
360-
&[a,b,c,d,] => Opt::SubnetMask([a,b,c,d,]),
361-
_ => Opt::Malformed(code, data),
362-
},
363-
_ => Opt::Unknown(code, data)
364-
})
365-
}
366-
}
367-
}
368-
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
use std::convert::TryInto;
2+
3+
#[derive(Debug)]
4+
pub enum Opt<'a> {
5+
Malformed(u8, &'a [u8]),
6+
Unknown(u8, &'a [u8]),
7+
//Pad, // #0
8+
9+
/// Subnet mask, encoded as an address
10+
SubnetMask([u8; 4]),
11+
/// Timezone seconds east of UTC
12+
TimeOffset(i32),
13+
/// A list of routers
14+
Routers(&'a [[u8;4]]),
15+
/// A list of ?NTP time servers
16+
TimeServers(&'a [[u8;4]]),
17+
/// A list of IEN-116 name servers
18+
NameServersIen116(&'a [[u8;4]]),
19+
/// #6 A list of DNS name servers
20+
NameServersDns(&'a [[u8;4]]),
21+
22+
/// #12 Client hostname
23+
HostName(&'a [u8]),
24+
/// #15 Domain Name
25+
DomainName(&'a [u8]),
26+
27+
/// #42 Vendor-specific
28+
VendorSpecific(&'a [u8]),
29+
30+
/// #50 Allows client to request a specific IP address
31+
RequestedIpAddress([u8; 4]),
32+
33+
/// #52 Specifies that `file` or `sname` (or both) also contain options
34+
///
35+
/// 1 = only `file`
36+
/// 2 = only `sname`
37+
/// 3 = both
38+
OptionOverload(u8),
39+
40+
/// #53
41+
DhcpMessageType(u8),
42+
43+
/// #54 IPv4 address of the server that sent this offer/ack
44+
ServerIdentifier([u8; 4]),
45+
46+
/// #56 - Human-readable (ASCII) text error message for DHCPNAK
47+
Message(&'a [u8]),
48+
49+
/// #61 - An opaque blob client identifier
50+
ClientIdentifier(&'a [u8]),
51+
}
52+
macro_rules! enc_dec_option {
53+
($in_data:ident ;
54+
$(
55+
$idx:literal $name:ident( $valname:ident ) : $dec:expr => $enc:expr ;
56+
)*
57+
) => {
58+
impl<'a> Opt<'a> {
59+
pub fn decode(code: u8, $in_data: &'a [u8]) -> Self {
60+
match code {
61+
0 => unreachable!(),
62+
$(
63+
$idx => if let Some(v) = $dec { Opt::$name(v) } else { Opt::Malformed(code, $in_data) },
64+
)*
65+
_ => Opt::Unknown(code, $in_data)
66+
}
67+
}
68+
pub fn encode(&self, mut push: impl FnMut(u8, &[u8])) {
69+
fn flatten(data: &[[u8; 4]]) -> &[u8] {
70+
// SAFE: Same alignment, correct length
71+
unsafe { ::core::slice::from_raw_parts(data.as_ptr() as *const u8, data.len()*4) }
72+
}
73+
match self {
74+
Opt::Malformed(_op, _data) => {
75+
// Ignore malformed data
76+
}
77+
Opt::Unknown(op, data) => push(*op, data),
78+
$(
79+
Opt::$name($valname) => push($idx, $enc),
80+
)*
81+
}
82+
}
83+
}
84+
}
85+
}
86+
fn get_u8_4(data: &[u8]) -> Option<&[u8; 4]> {
87+
data.try_into().ok()
88+
}
89+
fn get_u8_4_seq(data: &[u8]) -> Option<&[[u8;4]]> {
90+
if data.len() % 4 == 0 {
91+
// SAFE: Same alignment, and length is aligned to 4
92+
Some(unsafe { ::core::slice::from_raw_parts(data.as_ptr() as *const [u8; 4], data.len() / 4) })
93+
}
94+
else {
95+
None
96+
}
97+
}
98+
enc_dec_option!{d;
99+
// 0 Pad (not encoded)
100+
1 SubnetMask(data) : get_u8_4(d).copied() => data;
101+
2 TimeOffset(ofs) : get_u8_4(d).map(|v| i32::from_be_bytes(*v)) => &ofs.to_le_bytes();
102+
3 Routers(addrs) : get_u8_4_seq(d) => flatten(addrs);
103+
4 TimeServers(addrs) : get_u8_4_seq(d) => flatten(addrs);
104+
5 NameServersIen116(addrs) : get_u8_4_seq(d) => flatten(addrs);
105+
6 NameServersDns(addrs) : get_u8_4_seq(d) => flatten(addrs);
106+
12 HostName(name) : Some(d) => name;
107+
15 DomainName(name) : Some(d) => name;
108+
42 VendorSpecific(data) : Some(d) => data;
109+
50 RequestedIpAddress(addr) : get_u8_4(d).copied() => addr;
110+
52 OptionOverload(v) : match d { &[v] => Some(v), _ => None } => &[*v];
111+
53 DhcpMessageType(v) : match d { &[v] => Some(v), _ => None } => &[*v];
112+
54 ServerIdentifier(data) : get_u8_4(d).copied() => data;
113+
56 Message(msg) : Some(d) => msg;
114+
61 ClientIdentifier(blob) : Some(d) => blob;
115+
// 255 End (not encoded)
116+
}
117+
118+
#[derive(Debug)] // TODO: Implement using clone+run
119+
pub struct OptionsIter<'a>(pub &'a [u8]);
120+
impl<'a> Iterator for OptionsIter<'a> {
121+
type Item = Opt<'a>;
122+
fn next(&mut self) -> Option<Self::Item> {
123+
match self.0 {
124+
[] => None,
125+
// Padding: Handled specially
126+
[0, tail @ ..] => {
127+
self.0 = tail;
128+
//Some(Opt::Pad)
129+
self.next()
130+
},
131+
// End
132+
[255, ..] => None,
133+
[_] => {
134+
self.0 = &[];
135+
None
136+
},
137+
&[code, len, ref tail @ ..] => {
138+
let Some( (data,tail) ) = tail.split_at_checked(len as usize) else {
139+
self.0 = &[];
140+
return None;
141+
};
142+
self.0 = tail;
143+
Some(Opt::decode(code, data))
144+
}
145+
}
146+
}
147+
}

Usermode/daemon_network/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ fn make_ipv4(a: u8, b: u8, c: u8, d: u8) -> ::syscalls::values::NetworkAddress {
8787
}
8888
}
8989
fn add_iface(net_mgr: &::syscalls::net::Management, iface_idx: usize, iface_info: ::syscalls::values::NetworkInterface) -> Interface {
90-
let v4 = if iface_idx == 0 {
90+
let v4 = if iface_idx == 0 && false {
9191
net_mgr.add_address(iface_idx, make_ipv4(10,0,0,2), 24);
9292
net_mgr.add_route(syscalls::values::NetworkRoute {
9393
addr_ty: syscalls::values::SocketAddressType::Ipv4 as u8,

0 commit comments

Comments
 (0)