diff --git a/src/main.rs b/src/main.rs index 0a0c2c5..946e10d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use core::net::Ipv4Addr; use core::slice; use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; -use dhcparse::dhcpv4::{DhcpOption, Encode as _}; +use dhcparse::dhcpv4::{DhcpOption, Encode as _, MessageType as DhcpMsgType}; use dhcparse::{dhcpv4, v4_options}; use embassy_executor::Spawner; use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket}; @@ -173,7 +173,6 @@ async fn main(spawner: Spawner) { let mut tx_meta = [PacketMetadata::EMPTY; 16]; let mut buf = [0; 4096]; let mut res_buf = Vec::::new(); - let mut res_head = Vec::::new(); loop { let mut socket = UdpSocket::new( stack, @@ -185,28 +184,14 @@ async fn main(spawner: Spawner) { unwrap(socket.bind(67)).await; loop { - // loop { - // if socket.may_recv() { - // break - // } - // } - // info!("may recv"); - // Timer::after_secs(0).await; info!("receiving"); let (n, ep) = unwrap(socket.recv_from(&mut buf).await).await; info!("received"); Timer::after_secs(0).await; - // if let Ok(s) = core::str::from_utf8(&buf[..n]) { - // info!("rxd str from {}: {}", ep, s); - // } else { - // info!("rxd not str from {}: {:?}", ep, &buf[..n]); - // } - // Timer::after_secs(0).await; - let msg = unwrap(dhcpv4::Message::new(&buf[..n])).await; - let opts = unwrap(v4_options!(msg; MessageType required)).await; + let msg_type = unwrap(v4_options!(msg; MessageType required)).await; for o in unwrap(msg.options()).await { info!( "{:?}", @@ -216,11 +201,11 @@ async fn main(spawner: Spawner) { } ); } - info!("{:?}", opts); + info!("{:?}", msg_type); Timer::after_secs(0).await; - match opts { - dhcpv4::MessageType::DISCOVER => { + match msg_type { + DhcpMsgType::DISCOVER | DhcpMsgType::REQUEST => { res_buf.clear(); res_buf.push(2).unwrap(); // op res_buf.push(1).unwrap(); // htype @@ -229,7 +214,7 @@ async fn main(spawner: Spawner) { res_buf.extend_from_slice(&buf[4..8]).unwrap(); // xid res_buf.extend_from_slice(&[0; 2]).unwrap(); // secs res_buf.extend_from_slice(&[0x80, 0x00]).unwrap(); // flags - res_buf.extend_from_slice(&[0; 4]).unwrap(); // ciaddr + res_buf.extend_from_slice(&buf[12..16]).unwrap(); // ciaddr res_buf.extend_from_slice(&[192, 254, 0, 12]).unwrap(); // yiaddr res_buf.extend_from_slice(&[0; 4]).unwrap(); // siaddr res_buf.extend_from_slice(&buf[24..28]).unwrap(); // giaddr @@ -237,80 +222,34 @@ async fn main(spawner: Spawner) { res_buf.extend_from_slice(&[0; 192]).unwrap(); // sname/file res_buf.extend_from_slice(&[99, 130, 83, 99]).unwrap(); // magic cookie - res_buf.extend_from_slice(&[0; 4]).unwrap(); - info!("{}", res_buf.len()); - Timer::after_secs(0).await; - - // let mut res_opts = Vec::::new(); - for o in unwrap(v4_options!(msg; ParameterRequestList)) - .await - .unwrap_or(&[]) - { - let (opt_len, opt): (u8, &[u8]) = match o { - 1 => (4, &[255, 255, 255, 0]), // DhcpOption::SubnetMask(&dhcpv4::Addr([255, 255, 255, 0])), - 2 => (4, &3600_i32.to_be_bytes()), // DhcpOption::TimeOffset(3600), - 3 => (4, &[192, 254, 0, 2]), // DhcpOption::Router(&[dhcpv4::Addr([192, 254, 0, 2])]), - 6 => (4, &[0, 0, 0, 0]), // DhcpOption::DomainNameServer(&[dhcpv4::Addr([0, 0, 0, 0])]), - 12 => (4, b"blue"), // DhcpOption::HostName(b"blue"), - 15 => (11, b"LocalDomain"), // DhcpOption::DomainName(b"LocalDomain"), - 26 => (2, &1514_u16.to_be_bytes()), // DhcpOption::Unknown(26, &[0x5, 0xEA]), // mtu - 28 => (4, &[192, 254, 0, 255]), // DhcpOption::Unknown(28, &[192, 254, 0, 255]), // broadcast - 51 => (4, &700_u32.to_be_bytes()), // DhcpOption::AddressLeaseTime(700), - 54 => (4, &[192, 254, 0, 2]), // DhcpOption::ServerIdentifier(&dhcpv4::Addr([192, 254, 0, 2])), - 58 => (4, &500_u32.to_be_bytes()), // DhcpOption::Unknown(58, &[0, 0, 0x1, 0xF4]), // renewal time = 500s - 59 => (4, &600_u32.to_be_bytes()), // DhcpOption::Unknown(59, &[0, 0, 0x2, 0x58]), // rebinding time = 600s - _ => { - info!("Unhandled requested option : {}", o); - Timer::after_secs(0).await; - continue; - } - }; - res_buf.push(*o).unwrap(); - res_buf.push(opt_len).unwrap(); - res_buf.extend_from_slice(opt).unwrap(); - } + res_buf + .extend_from_slice(&[ + 53, + 1, + match msg_type { + DhcpMsgType::DISCOVER => 2, + DhcpMsgType::REQUEST => 5, + _ => unreachable!(), + }, + ]) + .unwrap(); // opt message type + unwrap( + write_dhcp_opts( + &mut res_buf, + match msg_type { + DhcpMsgType::DISCOVER => { + unwrap(v4_options!(msg; ParameterRequestList)) + .await + .unwrap_or(&[]) + } + DhcpMsgType::REQUEST => &[1, 3, 51, 6, 54], + _ => unreachable!(), + }, + ) + .await, + ) + .await; res_buf.push(255).unwrap(); // end option - // unwrap(res_opts.push(DhcpOption::End)).await; - - // res_buf.clear(); - // unwrap( - // dhcpv4::Encoder - // .append_options(res_opts) - // .encode(&unwrap(dhcpv4::Message::new(&res_head)).await, &mut res_buf), - // ) - // .await; - - // // options - // res_buf.extend_from_slice(&[53, 1, 2]).unwrap(); // message type - // res_buf - // .extend_from_slice(&[1, 4, 255, 255, 255, 0]) - // .unwrap(); // subnet mask - // res_buf.extend_from_slice(&[3, 4, 192, 254, 0, 2]).unwrap(); // router - // res_buf.extend_from_slice(&[6, 4, 0, 0, 0, 0]).unwrap(); // dns - // res_buf.extend_from_slice(&[15, 1, 0]).unwrap(); // domain name - // res_buf.extend_from_slice(&[26, 2, 0x5, 0xEA]).unwrap(); // mtu - // res_buf - // .extend_from_slice(&[28, 4, 192, 254, 0, 255]) - // .unwrap(); // domain name - // res_buf - // .extend_from_slice(&[51, 4, 0, 0, 0x2, 0xBC]) - // .unwrap(); // address lease time = 700s - // res_buf - // .extend_from_slice(&[58, 4, 0, 0, 0x2, 0x58]) - // .unwrap(); // renewal time = 600s - // res_buf - // .extend_from_slice(&[59, 4, 0, 0, 0x2, 0x58]) - // .unwrap(); // rebinding time = 600s - // res_buf.extend_from_slice(&[43, 1, 0]).unwrap(); // vendor specific - // let captive_portal_uri = "http://192.254.0.2:80/"; - // res_buf - // .extend_from_slice(&[114, captive_portal_uri.len() as u8]) - // .unwrap(); // captive portal - // res_buf - // .extend_from_slice(captive_portal_uri.as_bytes()) - // .unwrap(); - // res_buf.extend_from_slice(&[108, 4, 0, 0, 0, 0]).unwrap(); // ipv6 only - // res_buf.push(255).unwrap(); // end mark for o in unwrap(unwrap(dhcpv4::Message::new(&res_buf)).await.options()).await { info!( @@ -322,32 +261,6 @@ async fn main(spawner: Spawner) { ); Timer::after_secs(0).await; } - // let mut mac = [0; 6]; - // mac.clone_from_slice(&buf[28..34]); - // info!("mac : {:?}", mac); - // Timer::after_secs(0).await; - // let mut stack_inner = unwrap(stack.inner.try_borrow_mut()).await; - // let now = stack_inner.iface.inner.now; - // stack_inner.iface.inner.neighbor_cache.fill( - // Ipv4Addr::new(192, 254, 0, 12).into(), - // HardwareAddress::Ethernet(EthernetAddress(mac)), - // now, - // ); - // info!("neighbor cache filled"); - // Timer::after_secs(0).await; - - // unwrap( - // stack_inner - // .iface - // .inner - // .ip_addrs - // .push(Ipv4Cidr::new(Ipv4Addr::new(192, 254, 0, 12), 24).into()), - // ) - // .await; - // info!("ip addr added"); - // Timer::after_secs(0).await; - - // drop(stack_inner); unwrap( socket @@ -386,3 +299,31 @@ struct WifiConnectConf<'a> { password: &'a str, ip: Option, } + +async fn write_dhcp_opts(buf: &mut Vec, op_codes: &[u8]) -> Result<(), ()> { + for o in op_codes { + let (opt_len, opt): (u8, &[u8]) = match o { + 1 => (4, &[255, 255, 255, 0]), // DhcpOption::SubnetMask(&dhcpv4::Addr([255, 255, 255, 0])), + 2 => (4, &3600_i32.to_be_bytes()), // DhcpOption::TimeOffset(3600), + 3 => (4, &[192, 254, 0, 2]), // DhcpOption::Router(&[dhcpv4::Addr([192, 254, 0, 2])]), + 6 => (4, &[0, 0, 0, 0]), // DhcpOption::DomainNameServer(&[dhcpv4::Addr([0, 0, 0, 0])]), + 12 => (4, b"blue"), // DhcpOption::HostName(b"blue"), + 15 => (11, b"LocalDomain"), // DhcpOption::DomainName(b"LocalDomain"), + 26 => (2, &1514_u16.to_be_bytes()), // DhcpOption::Unknown(26, &[0x5, 0xEA]), // mtu + 28 => (4, &[192, 254, 0, 255]), // DhcpOption::Unknown(28, &[192, 254, 0, 255]), // broadcast + 51 => (4, &700_u32.to_be_bytes()), // DhcpOption::AddressLeaseTime(700), + 54 => (4, &[192, 254, 0, 2]), // DhcpOption::ServerIdentifier(&dhcpv4::Addr([192, 254, 0, 2])), + 58 => (4, &500_u32.to_be_bytes()), // DhcpOption::Unknown(58, &[0, 0, 0x1, 0xF4]), // renewal time = 500s + 59 => (4, &600_u32.to_be_bytes()), // DhcpOption::Unknown(59, &[0, 0, 0x2, 0x58]), // rebinding time = 600s + _ => { + info!("Unhandled requested option : {}", o); + Timer::after_secs(0).await; + continue; + } + }; + buf.push(*o).map_err(|_| ())?; + buf.push(opt_len).map_err(|_| ())?; + buf.extend_from_slice(opt)?; + } + Ok(()) +}