From 1f99f1270aaf49b92b483fcce87717065c572caf Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 6 Apr 2019 14:21:35 +0800 Subject: [PATCH] Implement recvmsg syscall for netlink --- kernel/src/drivers/net/ixgbe.rs | 1 - kernel/src/net/structs.rs | 70 ++++++++++++++++++++++++++++++++- kernel/src/process/structs.rs | 2 +- kernel/src/syscall/fs.rs | 10 ++--- kernel/src/syscall/mod.rs | 2 +- kernel/src/syscall/net.rs | 35 +++++++++++++++++ 6 files changed, 111 insertions(+), 9 deletions(-) diff --git a/kernel/src/drivers/net/ixgbe.rs b/kernel/src/drivers/net/ixgbe.rs index 9cf4444..2d3816e 100644 --- a/kernel/src/drivers/net/ixgbe.rs +++ b/kernel/src/drivers/net/ixgbe.rs @@ -8,7 +8,6 @@ use alloc::vec::Vec; use alloc::collections::BTreeMap; use isomorphic_drivers::net::ethernet::intel::ixgbe; use log::*; -use rcore_memory::paging::PageTable; use smoltcp::iface::*; use smoltcp::phy::{self, Checksum, DeviceCapabilities}; use smoltcp::time::Instant; diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 4b45f65..9ff1ded 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -4,6 +4,8 @@ use crate::sync::SpinNoIrqLock as Mutex; use crate::syscall::*; use crate::util; use alloc::boxed::Box; +use bitflags::*; +use core::mem::size_of; use smoltcp::socket::*; use smoltcp::wire::*; @@ -738,6 +740,62 @@ impl Socket for PacketSocketState { } } +#[repr(C)] +#[derive(Debug)] +struct NetlinkMessageHeader { + nlmsg_len: u32, // length of message including header + nlmsg_type: u16, // message content + nlmsg_flags: NetlinkMessageFlags, // additional flags + nlmsg_seq: u32, // sequence number + nlmsg_pid: u32, // sending process port id +} + +bitflags! { + struct NetlinkMessageFlags : u16 { + const REQUEST = 0x01; + const MULTI = 0x02; + const ACK = 0x04; + const ECHO = 0x08; + const DUMP_INTR = 0x10; + const DUMP_FILTERED = 0x20; + // GET request + const ROOT = 0x100; + const MATCH = 0x200; + const ATOMIC = 0x400; + const DUMP = 0x100 | 0x200; + // NEW request + const REPLACE = 0x100; + const EXCL = 0x200; + const CREATE = 0x400; + const APPEND = 0x800; + // DELETE request + const NONREC = 0x100; + // ACK message + const CAPPED = 0x100; + const ACK_TLVS = 0x200; + } +} + +enum_with_unknown! { + /// Netlink message types + pub doc enum NetlinkMessageType(u16) { + /// New link + NewLink = 16, + /// Delete link + DelLink = 17, + /// Get link + GetLink = 18, + /// Set link + SetLink = 19, + /// New addr + NewAddr = 20, + /// Delete addr + DelAddr = 21, + /// Get addr + GetAddr = 22, + } +} + impl NetlinkSocketState { pub fn new() -> Self { NetlinkSocketState {} @@ -751,7 +809,17 @@ impl Socket for NetlinkSocketState { fn write(&self, data: &[u8], _sendto_endpoint: Option) -> SysResult { debug!("data: {:x?}", &data); - unimplemented!() + if data.len() < size_of::() { + return Err(SysError::EINVAL); + } + let header = unsafe { &*(data.as_ptr() as *const NetlinkMessageHeader) }; + if header.nlmsg_len as usize > data.len() { + return Err(SysError::EINVAL); + } + let message_type = NetlinkMessageType::from(header.nlmsg_type); + debug!("header: {:?}", header); + debug!("type: {:?}", message_type); + Ok(data.len()) } fn poll(&self) -> (bool, bool, bool) { diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 93820af..057af1c 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -15,7 +15,7 @@ use xmas_elf::{ use crate::arch::interrupt::{Context, TrapFrame}; use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; -use crate::net::{Socket, SOCKETS}; +use crate::net::SOCKETS; use crate::sync::{Condvar, SpinNoIrqLock as Mutex}; use super::abi::{self, ProcInitInfo}; diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 9628242..f59c203 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -1069,10 +1069,10 @@ pub struct IoVec { /// A valid IoVecs request from user #[derive(Debug)] -struct IoVecs(Vec<&'static mut [u8]>); +pub struct IoVecs(Vec<&'static mut [u8]>); impl IoVecs { - fn check_and_new( + pub fn check_and_new( iov_ptr: *const IoVec, iov_count: usize, vm: &MemorySet, @@ -1098,7 +1098,7 @@ impl IoVecs { Ok(IoVecs(slices)) } - fn read_all_to_vec(&self) -> Vec { + pub fn read_all_to_vec(&self) -> Vec { let mut buf = self.new_buf(false); for slice in self.0.iter() { buf.extend(slice.iter()); @@ -1106,7 +1106,7 @@ impl IoVecs { buf } - fn write_all_from_slice(&mut self, buf: &[u8]) { + pub fn write_all_from_slice(&mut self, buf: &[u8]) { let mut copied_len = 0; for slice in self.0.iter_mut() { let copy_len = min(slice.len(), buf.len() - copied_len); @@ -1122,7 +1122,7 @@ impl IoVecs { /// Create a new Vec buffer from IoVecs /// For readv: `set_len` is true, Vec.len = total_len. /// For writev: `set_len` is false, Vec.cap = total_len. - fn new_buf(&self, set_len: bool) -> Vec { + pub fn new_buf(&self, set_len: bool) -> Vec { let total_len = self.0.iter().map(|slice| slice.len()).sum::(); let mut buf = Vec::with_capacity(total_len); if set_len { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 70ba552..dc2ef48 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -109,7 +109,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { args[5] as *mut u32, ), // SYS_SENDMSG => sys_sendmsg(), - // SYS_RECVMSG => sys_recvmsg(), + SYS_RECVMSG => sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]), SYS_SHUTDOWN => sys_shutdown(args[0], args[1]), SYS_BIND => sys_bind(args[0], args[1] as *const SockAddr, args[2]), // 50 diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index cda2062..b771422 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -1,5 +1,6 @@ //! Syscalls for networking +use super::fs::IoVecs; use super::*; use crate::drivers::SOCKET_ACTIVITY; use crate::fs::FileLike; @@ -173,6 +174,28 @@ pub fn sys_recvfrom( result } +pub fn sys_recvmsg(fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult { + info!("recvmsg: fd: {}, msg: {:?}, flags: {}", fd, msg, flags); + let mut proc = process(); + proc.vm.check_read_ptr(msg)?; + let hdr = unsafe { &mut *msg }; + let mut iovs = IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &proc.vm, true)?; + + let mut buf = iovs.new_buf(true); + let socket = proc.get_socket(fd)?; + let (result, endpoint) = socket.read(&mut buf); + + if let Ok(len) = result { + // copy data to user + iovs.write_all_from_slice(&buf[..len]); + let sockaddr_in = SockAddr::from(endpoint); + unsafe { + sockaddr_in.write_to(&mut proc, hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?; + } + } + unimplemented!() +} + pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len); let mut proc = process(); @@ -433,6 +456,18 @@ impl SockAddr { } } +#[repr(C)] +#[derive(Debug)] +pub struct MsgHdr { + msg_name: *mut SockAddr, + msg_namelen: u32, + msg_iov: *mut IoVec, + msg_iovlen: usize, + msg_control: usize, + msg_controllen: usize, + msg_flags: usize, +} + enum_with_unknown! { /// Address families pub doc enum AddressFamily(u16) {