use crate::*;
pub const DHCP_SERVER_PORT: u16 = 67;
pub const DHCP_CLIENT_PORT: u16 = 68;
const DHCP_COOKIE: u32 = 0x63_82_53_63;
const DHCP_END: u32 = 0xff;
use byte_struct::*;
use ufmt::derive::uDebug;
#[derive(ByteStruct, uDebug, Debug, Clone, Copy, PartialEq, Eq)]
#[byte_struct_be]
pub struct DhcpFixedPayload {
op: DhcpOperation,
htype: u8,
hlen: u8,
hops: u8,
xid: u32,
secs: u16,
flags: u16,
ciaddr: IpV4Addr,
yiaddr: IpV4Addr,
siaddr: IpV4Addr,
giaddr: IpV4Addr,
chaddr: MacAddr,
_pad0: [u16; 5],
_pad1: [u128; 12],
cookie: u32,
kind_option: DhcpMessageKindOption,
}
impl DhcpFixedPayload {
pub fn new(
end_of_message: bool,
op: DhcpOperation,
kind: DhcpMessageKind,
transaction_id: u32,
broadcast: bool,
ciaddr: IpV4Addr,
yiaddr: IpV4Addr,
siaddr: IpV4Addr,
chaddr: MacAddr,
) -> Self {
DhcpFixedPayload {
op: op,
htype: 1_u8, hlen: 6_u8, hops: 0,
xid: transaction_id,
secs: 0,
flags: (broadcast as u16) * 32768,
ciaddr: ciaddr,
yiaddr: yiaddr,
siaddr: siaddr,
giaddr: IpV4Addr::ANY,
chaddr: chaddr,
_pad0: [0_u16; 5],
_pad1: [0_u128; 12],
cookie: DHCP_COOKIE,
kind_option: DhcpMessageKindOption::new(kind, end_of_message),
}
}
pub fn new_inform(ipaddr: IpV4Addr, macaddr: MacAddr, transaction_id: u32) -> Self {
Self::new(
true,
DhcpOperation::Request,
DhcpMessageKind::Inform,
transaction_id,
true,
ipaddr,
IpV4Addr::ANY,
IpV4Addr::ANY,
macaddr,
)
}
pub fn to_be_bytes(&self) -> [u8; Self::BYTE_LEN] {
let mut header_bytes = [0_u8; Self::BYTE_LEN];
self.write_bytes(&mut header_bytes);
header_bytes
}
}
#[derive(ByteStruct, uDebug, Debug, Clone, Copy, PartialEq, Eq)]
#[byte_struct_be]
pub struct DhcpMessageKindOption {
pub kind: DhcpOptionKind,
length: u8,
value: DhcpMessageKind,
_pad: u8,
}
impl DhcpMessageKindOption {
pub fn new(kind: DhcpMessageKind, eom: bool) -> Self {
DhcpMessageKindOption {
kind: DhcpOptionKind::DhcpMessageType,
length: 1,
value: kind,
_pad: match eom {
true => 255,
false => 0,
},
}
}
}
enum_with_unknown! {
pub enum DhcpOperation(u8) {
Request = 1,
Reply = 2
}
}
impl ByteStructLen for DhcpOperation {
const BYTE_LEN: usize = 1;
}
impl ByteStruct for DhcpOperation {
fn read_bytes(bytes: &[u8]) -> Self {
Self::from(bytes[0])
}
fn write_bytes(&self, bytes: &mut [u8]) {
bytes[0] = u8::from(*self);
}
}
enum_with_unknown! {
#[allow(missing_docs)]
pub enum DhcpMessageKind(u8) {
Discover = 1,
Offer = 2,
Request = 3,
Decline = 4,
Ack = 5, Nak = 6, Release = 7,
Inform = 8,
ForceRenew = 9,
LeaseQuery = 10,
LeaseUnassigned = 11,
LeaseUnknown = 12,
LeaseActive = 13,
BulkLeaseQuery = 14,
LeaseQueryDone = 15,
ActiveLeaseQuery = 16,
LeaseQueryStatus = 17,
Tls = 18
}
}
impl ByteStructLen for DhcpMessageKind {
const BYTE_LEN: usize = 1;
}
impl ByteStruct for DhcpMessageKind {
fn read_bytes(bytes: &[u8]) -> Self {
Self::from(bytes[0])
}
fn write_bytes(&self, bytes: &mut [u8]) {
bytes[0] = u8::from(*self);
}
}
enum_with_unknown! {
#[allow(missing_docs)]
pub enum DhcpOptionKind(u8) {
Pad = 0,
SubnetMask = 1,
TimeOffset = 2,
Router = 3,
TimeServer = 4,
NameServer = 5,
DomainNameServers = 6,
LogServer = 7,
CookieServer = 8,
LPRServer = 9,
ImpressServer = 10,
ResourceLocationServer = 11,
HostName = 12,
BootFileSize = 13,
MeritDumpFileSize = 14,
DomainName = 15,
SwapServer = 16,
RootPath = 17,
ExtensionsPath = 18,
IPForwardEnable = 19,
SourceRoutingEnable = 20,
PolicyFilter = 21,
MaximumDatagramSize = 22,
DefaultIpTtl = 23,
PathMtuTimeout = 24,
PathMtuPlateau = 25,
InterfaceMtu = 26,
AllSubnetsLocal = 27,
BroadcastAddress = 28,
PerformMaskDiscovery = 29,
MaskSupplier = 30,
PerformRouterDiscovery = 31,
RouterSolicitationAddress = 32,
StaticRoute = 33,
TrailerEncapsulation = 34,
ArpCacheTimeout = 35,
EthernetEncapsulation = 36,
TcpDefaultTtl = 37,
TcpKeepAliveInterval = 38,
TcpKeepAliveGarbage = 39,
NetworkInfoServiceDomain = 40,
NetworkInfoSevers = 41,
NtpServers = 42,
VendorInfo = 43,
NetBiosNameServer = 44,
NetBiosDistributionServer = 45,
NetBiosNodeType = 46,
NetBiosScope = 47,
XWindowFontServer = 48,
XWindowDisplayMgr = 49,
RequestedIpAddress = 50,
IpAddressLeaseTime = 51,
OptionOverload = 52,
DhcpMessageType = 53,
ServerIdentifier = 54,
ParameterRequestList = 55,
Message = 56,
MaxDhcpMessageSize = 57,
RenewalTime = 58,
RebindingTime = 59,
VendorClassId = 60,
ClientId = 61,
TftpServerName = 62,
BootFileName = 63,
NisPlusDomain = 64,
NisPlusServers = 65,
MobileIpHomeAgent = 68,
SmtpServer = 69,
Pop3Server = 70,
NntpServer = 71,
DefaultWwwServer = 72,
DefaultFingerServer = 73,
DefaultIrcServer = 74,
StreetTalkServer = 75,
StreetTalkDirectoryServer = 76,
RelayAgentInfo = 82,
NdsServers = 85,
NdsContext = 86,
TimeZonePosix = 100,
TimeZoneTz = 101,
DhcpCaptivePortal = 114,
DomainSearch = 119,
ClasslessStaticRoute = 121,
ConfigFile = 209,
PathPrefix = 210,
RebootTime = 211,
End = 255,
}
}
impl ByteStructLen for DhcpOptionKind {
const BYTE_LEN: usize = 1;
}
impl ByteStruct for DhcpOptionKind {
fn read_bytes(bytes: &[u8]) -> Self {
Self::from(bytes[0])
}
fn write_bytes(&self, bytes: &mut [u8]) {
bytes[0] = u8::from(*self);
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_serialization_loop() {
let dhcp_inform = DhcpFixedPayload::new_inform(
IpV4Addr::new([1, 2, 3, 4]),
MacAddr::new([5, 6, 7, 8, 9, 10]),
12345,
);
let mut bytes = [0_u8; DhcpFixedPayload::BYTE_LEN];
dhcp_inform.write_bytes(&mut bytes);
let msg_parsed = DhcpFixedPayload::read_bytes(&bytes);
assert_eq!(msg_parsed, dhcp_inform);
}
}