use crate::prelude::*; use jinux_frame::sync::SpinLock; use jinux_network::{probe_virtio_net, NetworkDevice, VirtioNet}; use smoltcp::{ iface::{Config, Routes, SocketHandle, SocketSet}, socket::dhcpv4, wire::{self, IpCidr}, }; use super::{common::IfaceCommon, internal::IfaceInternal, Iface}; pub struct IfaceVirtio { driver: SpinLock, common: IfaceCommon, dhcp_handle: SocketHandle, weak_self: Weak, } impl IfaceVirtio { pub fn new() -> Arc { let mut virtio_net = probe_virtio_net().unwrap(); let interface = { let mac_addr = virtio_net.mac_addr(); let ip_addr = IpCidr::new(wire::IpAddress::Ipv4(wire::Ipv4Address::UNSPECIFIED), 0); let routes = Routes::new(); let config = { let mut config = Config::new(); config.hardware_addr = Some(wire::HardwareAddress::Ethernet( wire::EthernetAddress(mac_addr.0), )); config }; let mut interface = smoltcp::iface::Interface::new(config, &mut virtio_net); interface.update_ip_addrs(|ip_addrs| { debug_assert!(ip_addrs.len() == 0); ip_addrs.push(ip_addr).unwrap(); }); interface }; let common = IfaceCommon::new(interface); let mut socket_set = common.sockets(); let dhcp_handle = init_dhcp_client(&mut socket_set); drop(socket_set); Arc::new_cyclic(|weak| Self { driver: SpinLock::new(virtio_net), common, dhcp_handle, weak_self: weak.clone(), }) } /// FIXME: Once we have user program dhcp client, we may remove dhcp logic from kernel. pub fn process_dhcp(&self) { let mut socket_set = self.common.sockets(); let dhcp_socket: &mut dhcpv4::Socket = socket_set.get_mut(self.dhcp_handle); let config = if let Some(event) = dhcp_socket.poll() { debug!("event = {:?}", event); if let dhcpv4::Event::Configured(config) = event { config } else { return; } } else { return; }; let ip_addr = IpCidr::Ipv4(config.address); let mut interface = self.common.interface(); interface.update_ip_addrs(|ipaddrs| { if let Some(addr) = ipaddrs.iter_mut().next() { // already has ipaddrs *addr = ip_addr } else { // does not has ip addr ipaddrs.push(ip_addr).unwrap(); } }); println!( "DHCP update IP address: {:?}", interface.ipv4_addr().unwrap() ); if let Some(router) = config.router { println!("Default router address: {:?}", router); interface .routes_mut() .add_default_ipv4_route(router) .unwrap(); } } } impl IfaceInternal for IfaceVirtio { fn common(&self) -> &IfaceCommon { &self.common } fn arc_self(&self) -> Arc { self.weak_self.upgrade().unwrap() } } impl Iface for IfaceVirtio { fn name(&self) -> &str { "virtio" } fn mac_addr(&self) -> Option { let interface = self.common.interface(); let hardware_addr = interface.hardware_addr(); match hardware_addr { wire::HardwareAddress::Ethernet(ethe_address) => Some(ethe_address), } } fn poll(&self) { let mut driver = self.driver.lock_irq_disabled(); self.common.poll(&mut *driver); self.process_dhcp(); } } /// Register a dhcp socket. fn init_dhcp_client(socket_set: &mut SocketSet) -> SocketHandle { let dhcp_socket = dhcpv4::Socket::new(); socket_set.add(dhcp_socket) }