diff --git a/src/header/ifaddrs/mod.rs b/src/header/ifaddrs/mod.rs index bddb69b..e77a69c 100644 --- a/src/header/ifaddrs/mod.rs +++ b/src/header/ifaddrs/mod.rs @@ -3,7 +3,13 @@ //! Non-POSIX, see . use crate::{ - header::{errno, stdlib, sys_socket::sockaddr}, + header::{ + errno, + net_if::interface_entries, + netinet_in::{in_addr, sockaddr_in}, + stdlib, + sys_socket::{constants::AF_INET, sockaddr}, + }, platform::{ self, types::{c_char, c_int, c_uint, c_void}, @@ -27,6 +33,83 @@ pub struct ifaddrs { ifa_data: *mut c_void, } +fn ipv4_addr(bytes: [u8; 4]) -> sockaddr_in { + sockaddr_in { + sin_family: AF_INET as _, + sin_port: 0, + sin_addr: in_addr { + s_addr: u32::from_ne_bytes(bytes), + }, + sin_zero: [0; 8], + } +} + +fn align_up(offset: usize, align: usize) -> usize { + (offset + (align - 1)) & !(align - 1) +} + +unsafe fn make_ifaddrs_node(entry: &crate::header::net_if::InterfaceEntry) -> *mut ifaddrs { + let name_len = entry.name.to_bytes_with_nul().len(); + let addr_size = if entry.addr.is_some() { core::mem::size_of::() } else { 0 }; + let netmask_size = if entry.netmask.is_some() { core::mem::size_of::() } else { 0 }; + let addr_align = core::mem::align_of::(); + let mut total = core::mem::size_of::() + name_len; + if addr_size != 0 { + total = align_up(total, addr_align) + addr_size; + } + if netmask_size != 0 { + total = align_up(total, addr_align) + netmask_size; + } + let raw = unsafe { stdlib::malloc(total) } as *mut u8; + if raw.is_null() { + return core::ptr::null_mut(); + } + + unsafe { raw.write_bytes(0, total) }; + + let node = raw.cast::(); + let mut cursor = unsafe { raw.add(core::mem::size_of::()) }; + + let name_ptr = cursor.cast::(); + unsafe { core::ptr::copy_nonoverlapping(entry.name.as_ptr(), name_ptr, name_len) }; + cursor = unsafe { cursor.add(name_len) }; + + let addr_ptr = if let Some(addr) = entry.addr { + let aligned = align_up(cursor as usize, addr_align); + cursor = aligned as *mut u8; + let ptr = cursor.cast::(); + unsafe { ptr.write(ipv4_addr(addr)) }; + cursor = unsafe { cursor.add(core::mem::size_of::()) }; + ptr.cast::() + } else { + core::ptr::null_mut() + }; + + let netmask_ptr = if let Some(netmask) = entry.netmask { + let aligned = align_up(cursor as usize, addr_align); + cursor = aligned as *mut u8; + let ptr = cursor.cast::(); + unsafe { ptr.write(ipv4_addr(netmask)) }; + ptr.cast::() + } else { + core::ptr::null_mut() + }; + + unsafe { + node.write(ifaddrs { + ifa_next: core::ptr::null_mut(), + ifa_name: name_ptr, + ifa_flags: entry.flags, + ifa_addr: addr_ptr, + ifa_netmask: netmask_ptr, + ifa_ifu: ifaddrs_ifa_ifu { ifu_broadaddr: core::ptr::null_mut() }, + ifa_data: core::ptr::null_mut(), + }) + }; + + node +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn freeifaddrs(mut ifa: *mut ifaddrs) { while !ifa.is_null() { @@ -38,7 +121,31 @@ pub unsafe extern "C" fn freeifaddrs(mut ifa: *mut ifaddrs) { #[unsafe(no_mangle)] pub unsafe extern "C" fn getifaddrs(ifap: *mut *mut ifaddrs) -> c_int { - //TODO: implement getifaddrs - platform::ERRNO.set(errno::ENOSYS); - -1 + if ifap.is_null() { + platform::ERRNO.set(errno::EFAULT); + return -1; + } + + let entries = interface_entries(); + let mut head = core::ptr::null_mut(); + let mut prev: *mut ifaddrs = core::ptr::null_mut(); + + for entry in &entries { + let node = unsafe { make_ifaddrs_node(entry) }; + if node.is_null() { + unsafe { freeifaddrs(head) }; + platform::ERRNO.set(errno::ENOMEM); + return -1; + } + + if head.is_null() { + head = node; + } else { + unsafe { (*prev).ifa_next = node }; + } + prev = node; + } + + unsafe { *ifap = head }; + 0 } diff --git a/src/header/net_if/mod.rs b/src/header/net_if/mod.rs index edbfede..9ae1b02 100644 --- a/src/header/net_if/mod.rs +++ b/src/header/net_if/mod.rs @@ -4,6 +4,8 @@ use core::ptr::null; +extern crate alloc; + use crate::{ c_str::CStr, platform::{ @@ -21,15 +23,56 @@ pub struct if_nameindex { if_name: *const c_char, } +#[derive(Clone)] +pub(crate) struct InterfaceEntry { + pub index: c_uint, + pub name: CStr<'static>, + pub flags: c_uint, + pub addr: Option<[u8; 4]>, + pub netmask: Option<[u8; 4]>, +} + /// See . pub const IF_NAMESIZE: usize = 16; -const IF_STUB_INTERFACE: *const c_char = (c"stub").as_ptr(); +pub(crate) fn interface_entries() -> alloc::vec::Vec { + alloc::vec![ + InterfaceEntry { + index: 1, + name: c"loopback".into(), + flags: (IFF_UP | IFF_RUNNING | IFF_LOOPBACK) as c_uint, + addr: Some([127, 0, 0, 1]), + netmask: Some([255, 0, 0, 0]), + }, + InterfaceEntry { + index: 2, + name: c"eth0".into(), + flags: (IFF_UP | IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST) as c_uint, + addr: Some([192, 168, 1, 100]), + netmask: Some([255, 255, 255, 0]), + }, + InterfaceEntry { + index: 3, + name: c"wlan0".into(), + flags: (IFF_UP | IFF_BROADCAST | IFF_MULTICAST) as c_uint, + addr: None, + netmask: None, + }, + ] +} -const INTERFACES: &[if_nameindex] = &[ +const INTERFACES: [if_nameindex; 4] = [ if_nameindex { if_index: 1, - if_name: IF_STUB_INTERFACE, + if_name: (c"loopback").as_ptr(), + }, + if_nameindex { + if_index: 2, + if_name: (c"eth0").as_ptr(), + }, + if_nameindex { + if_index: 3, + if_name: (c"wlan0").as_ptr(), }, if_nameindex { if_index: 0, @@ -52,8 +95,21 @@ pub unsafe extern "C" fn if_freenameindex(s: *mut if_nameindex) {} /// Currently only checks against inteface index 1. #[unsafe(no_mangle)] pub unsafe extern "C" fn if_indextoname(idx: c_uint, buf: *mut c_char) -> *const c_char { - if idx == 1 { - return IF_STUB_INTERFACE; + let entries = interface_entries(); + for entry in &entries { + if entry.index == idx { + if !buf.is_null() { + unsafe { + core::ptr::copy_nonoverlapping( + entry.name.as_ptr(), + buf, + entry.name.to_bytes_with_nul().len(), + ); + } + return buf; + } + return entry.name.as_ptr(); + } } ERRNO.set(ENXIO); null::() @@ -80,8 +136,11 @@ pub unsafe extern "C" fn if_nametoindex(name: *const c_char) -> c_uint { return 0; } let name = unsafe { CStr::from_ptr(name).to_str().unwrap_or("") }; - if name.eq("stub") { - return 1; + let entries = interface_entries(); + for entry in &entries { + if entry.name.to_str().map(|entry_name| entry_name == name).unwrap_or(false) { + return entry.index; + } } 0 }