use super::*;
#[derive(Debug, Clone)]
pub struct PxeConfig {
pub boot_filename: Option<String>,
pub tftp_server: Option<Ipv4Addr>,
pub boot_server: Option<Ipv4Addr>,
pub vendor_class: String,
pub architecture: u16,
pub boot_menu: Vec<PxeMenuItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PxeMenuItem {
pub id: u16,
pub type_: u16,
pub description: String,
}
pub struct PxeHandler {
config: PxeConfigSettings,
}
impl PxeHandler {
pub fn new(config: PxeConfigSettings) -> Self {
Self { config }
}
pub fn extract_pxe_options(&self, _message: &dhcproto::v4::Message) -> Result<PxeConfig> {
Ok(PxeConfig {
boot_filename: None,
tftp_server: None,
boot_server: None,
vendor_class: self.config.vendor_class.clone(),
architecture: self.config.architecture,
boot_menu: Vec::new(),
})
}
pub async fn boot(&self, pxe_config: &PxeConfig) -> Result<()> {
if !self.config.enabled {
return Err(DhcpClientError::PxeError("PXE is not enabled".to_string()));
}
info!("Starting PXE boot");
if let (Some(filename), Some(server)) = (&pxe_config.boot_filename, &pxe_config.tftp_server) {
info!("Downloading boot file {} from TFTP server {}", filename, server);
info!("PXE boot file downloaded successfully");
} else {
return Err(DhcpClientError::PxeError("Missing boot filename or TFTP server".to_string()));
}
Ok(())
}
pub fn display_boot_menu(&self, menu: &[PxeMenuItem]) {
if menu.is_empty() {
return;
}
info!("PXE Boot Menu:");
for item in menu {
info!(" [{}] {}", item.id, item.description);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pxe_handler_creation() {
let config = PxeConfigSettings::default();
let handler = PxeHandler::new(config);
assert!(!handler.config.enabled);
}
#[test]
fn test_pxe_menu_item() {
let item = PxeMenuItem {
id: 1,
type_: 0,
description: "Local Boot".to_string(),
};
assert_eq!(item.id, 1);
assert_eq!(item.description, "Local Boot");
}
}