Add netdevice ioctl command
This commit is contained in:
parent
5e9a617350
commit
e13242e7e5
@ -200,6 +200,14 @@ enclave {
|
|||||||
void occlum_ocall_print_log(uint32_t level, [in, string] const char* msg);
|
void occlum_ocall_print_log(uint32_t level, [in, string] const char* msg);
|
||||||
void occlum_ocall_flush_log(void);
|
void occlum_ocall_flush_log(void);
|
||||||
|
|
||||||
|
int occlum_ocall_ioctl_repack(
|
||||||
|
int fd,
|
||||||
|
int request,
|
||||||
|
[in, out, size=len] char *buf,
|
||||||
|
int len,
|
||||||
|
[out] int* recv_len
|
||||||
|
) propagate_errno;
|
||||||
|
|
||||||
int occlum_ocall_ioctl(
|
int occlum_ocall_ioctl(
|
||||||
int fd,
|
int fd,
|
||||||
int request,
|
int request,
|
||||||
|
@ -10,3 +10,18 @@ pub struct WinSize {
|
|||||||
pub ws_xpixel: u16,
|
pub ws_xpixel: u16,
|
||||||
pub ws_ypixel: u16,
|
pub ws_ypixel: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct IfConf {
|
||||||
|
pub ifc_len: i32,
|
||||||
|
pub ifc_buf: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
const IFNAMSIZ: usize = 16;
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct IfReq {
|
||||||
|
pub ifr_name: [u8; IFNAMSIZ],
|
||||||
|
pub ifr_union: [u8; 24],
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub use self::builtin::WinSize;
|
pub use self::builtin::*;
|
||||||
pub use self::non_builtin::{NonBuiltinIoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
pub use self::non_builtin::{NonBuiltinIoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -37,6 +37,21 @@ impl_ioctl_nums_and_cmds! {
|
|||||||
TIOCNOTTY => (0x5422, ()),
|
TIOCNOTTY => (0x5422, ()),
|
||||||
// Get the number of bytes in the input buffer
|
// Get the number of bytes in the input buffer
|
||||||
FIONREAD => (0x541B, mut i32),
|
FIONREAD => (0x541B, mut i32),
|
||||||
|
// Low-level access to Linux network devices on man7/netdevice.7
|
||||||
|
// Only non-privileged operations are supported for now
|
||||||
|
SIOCGIFNAME => (0x8910, mut IfReq),
|
||||||
|
SIOCGIFCONF => (0x8912, mut IfConf),
|
||||||
|
SIOCGIFFLAGS => (0x8913, mut IfReq),
|
||||||
|
SIOCGIFADDR => (0x8915, mut IfReq),
|
||||||
|
SIOCGIFDSTADDR => (0x8917, mut IfReq),
|
||||||
|
SIOCGIFBRDADDR => (0x8919, mut IfReq),
|
||||||
|
SIOCGIFNETMASK => (0x891B, mut IfReq),
|
||||||
|
SIOCGIFMTU => (0x8921, mut IfReq),
|
||||||
|
SIOCGIFHWADDR => (0x8927, mut IfReq),
|
||||||
|
SIOCGIFINDEX => (0x8933, mut IfReq),
|
||||||
|
SIOCGIFPFLAGS => (0x8935, mut IfReq),
|
||||||
|
SIOCGIFTXQLEN => (0x8942, mut IfReq),
|
||||||
|
SIOCGIFMAP => (0x8970, mut IfReq),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is the centralized place to add sanity checks for the argument values
|
/// This is the centralized place to add sanity checks for the argument values
|
||||||
|
@ -14,7 +14,8 @@ pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags};
|
|||||||
pub use self::flock::{Flock, FlockType};
|
pub use self::flock::{Flock, FlockType};
|
||||||
pub use self::fsync::{do_fdatasync, do_fsync};
|
pub use self::fsync::{do_fdatasync, do_fsync};
|
||||||
pub use self::ioctl::{
|
pub use self::ioctl::{
|
||||||
do_ioctl, occlum_ocall_ioctl, IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum,
|
do_ioctl, occlum_ocall_ioctl, BuiltinIoctlNum, IfConf, IoctlCmd, StructuredIoctlArgType,
|
||||||
|
StructuredIoctlNum,
|
||||||
};
|
};
|
||||||
pub use self::link::do_link;
|
pub use self::link::do_link;
|
||||||
pub use self::lseek::do_lseek;
|
pub use self::lseek::do_lseek;
|
||||||
|
@ -14,8 +14,8 @@ pub use self::dev_fs::AsDevRandom;
|
|||||||
pub use self::event_file::{AsEvent, EventCreationFlags, EventFile};
|
pub use self::event_file::{AsEvent, EventCreationFlags, EventFile};
|
||||||
pub use self::file::{File, FileRef};
|
pub use self::file::{File, FileRef};
|
||||||
pub use self::file_ops::{
|
pub use self::file_ops::{
|
||||||
occlum_ocall_ioctl, AccessMode, CreationFlags, FileMode, Flock, FlockType, IoctlCmd, Stat,
|
occlum_ocall_ioctl, AccessMode, BuiltinIoctlNum, CreationFlags, FileMode, Flock, FlockType,
|
||||||
StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
|
IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
|
||||||
};
|
};
|
||||||
pub use self::file_table::{FileDesc, FileTable};
|
pub use self::file_table::{FileDesc, FileTable};
|
||||||
pub use self::fs_view::FsView;
|
pub use self::fs_view::FsView;
|
||||||
|
82
src/libos/src/net/socket_file/ioctl_impl.rs
Normal file
82
src/libos/src/net/socket_file/ioctl_impl.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use super::*;
|
||||||
|
use fs::{occlum_ocall_ioctl, BuiltinIoctlNum, IoctlCmd};
|
||||||
|
|
||||||
|
impl SocketFile {
|
||||||
|
pub(super) fn ioctl_impl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||||
|
if let IoctlCmd::SIOCGIFCONF(arg_ref) = cmd {
|
||||||
|
return self.ioctl_getifconf(arg_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmd_num = cmd.cmd_num() as c_int;
|
||||||
|
let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void;
|
||||||
|
let ret = try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
self.fd(),
|
||||||
|
cmd_num,
|
||||||
|
cmd_arg_ptr,
|
||||||
|
cmd.arg_len(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
// FIXME: add sanity checks for results returned for socket-related ioctls
|
||||||
|
cmd.validate_arg_and_ret_vals(ret)?;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioctl_getifconf(&self, arg_ref: &mut IfConf) -> Result<i32> {
|
||||||
|
if !arg_ref.ifc_buf.is_null() && arg_ref.ifc_len == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = try_libc!({
|
||||||
|
let mut recv_len: i32 = 0;
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl_repack(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
self.fd(),
|
||||||
|
BuiltinIoctlNum::SIOCGIFCONF as i32,
|
||||||
|
arg_ref.ifc_buf,
|
||||||
|
arg_ref.ifc_len,
|
||||||
|
&mut recv_len as *mut i32,
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
// If ifc_req is NULL, SIOCGIFCONF returns the necessary buffer
|
||||||
|
// size in bytes for receiving all available addresses in ifc_len
|
||||||
|
// which is irrelevant to the orginal ifc_len.
|
||||||
|
if !arg_ref.ifc_buf.is_null() {
|
||||||
|
assert!(arg_ref.ifc_len >= recv_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_ref.ifc_len = recv_len;
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
// Used to ioctl arguments with pointer members.
|
||||||
|
//
|
||||||
|
// Before the call the area the pointers points to should be assembled into
|
||||||
|
// one continous memory block. Then the block is repacked to ioctl arguments
|
||||||
|
// in the ocall implementation in host.
|
||||||
|
//
|
||||||
|
// ret: holds the return value of ioctl in host
|
||||||
|
// fd: the host fd for the device
|
||||||
|
// cmd_num: request number of the ioctl
|
||||||
|
// buf: the data to exchange with host
|
||||||
|
// len: the size of the buf
|
||||||
|
// recv_len: accepts transferred data length when buf is used to get data from host
|
||||||
|
//
|
||||||
|
fn occlum_ocall_ioctl_repack(
|
||||||
|
ret: *mut i32,
|
||||||
|
fd: c_int,
|
||||||
|
cmd_num: c_int,
|
||||||
|
buf: *const u8,
|
||||||
|
len: i32,
|
||||||
|
recv_len: *mut i32,
|
||||||
|
) -> sgx_status_t;
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::fs::IfConf;
|
||||||
|
|
||||||
|
mod ioctl_impl;
|
||||||
mod recv;
|
mod recv;
|
||||||
mod send;
|
mod send;
|
||||||
|
|
||||||
use fs::{occlum_ocall_ioctl, AccessMode, CreationFlags, File, FileRef, IoctlCmd, StatusFlags};
|
use fs::{AccessMode, CreationFlags, File, FileRef, IoctlCmd, StatusFlags};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
@ -107,23 +109,7 @@ impl File for SocketFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||||
let cmd_num = cmd.cmd_num() as c_int;
|
self.ioctl_impl(cmd)
|
||||||
let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void;
|
|
||||||
let ret = try_libc!({
|
|
||||||
let mut retval: i32 = 0;
|
|
||||||
let status = occlum_ocall_ioctl(
|
|
||||||
&mut retval as *mut i32,
|
|
||||||
self.fd(),
|
|
||||||
cmd_num,
|
|
||||||
cmd_arg_ptr,
|
|
||||||
cmd.arg_len(),
|
|
||||||
);
|
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
|
||||||
retval
|
|
||||||
});
|
|
||||||
// FIXME: add sanity checks for results returned for socket-related ioctls
|
|
||||||
cmd.validate_arg_and_ret_vals(ret)?;
|
|
||||||
Ok(ret)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_access_mode(&self) -> Result<AccessMode> {
|
fn get_access_mode(&self) -> Result<AccessMode> {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "ocalls.h"
|
#include "ocalls.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <net/if.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
@ -12,9 +13,33 @@ int occlum_ocall_eventfd(unsigned int initval, int flags) {
|
|||||||
return eventfd(initval, flags);
|
return eventfd(initval, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int occlum_ocall_ioctl_repack(int fd, int request, char *buf, int len, int *recv_len) {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
switch (request) {
|
||||||
|
case SIOCGIFCONF:
|
||||||
|
if (recv_len == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ifconf config = { .ifc_len = len, .ifc_buf = buf };
|
||||||
|
ret = ioctl(fd, SIOCGIFCONF, &config);
|
||||||
|
if (ret == 0) {
|
||||||
|
*recv_len = config.ifc_len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int occlum_ocall_ioctl(int fd, int request, void *arg, size_t len) {
|
int occlum_ocall_ioctl(int fd, int request, void *arg, size_t len) {
|
||||||
if (((arg == NULL) ^ (len == 0)) == 1) {
|
if (((arg == NULL) ^ (len == 0)) == 1) {
|
||||||
printf("invalid ioctl parameters\n");
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -216,6 +218,62 @@ int test_sgx_ioctl_SGXIOC_CREATE_AND_VERIFY_REPORT(void) {
|
|||||||
return do_sgx_ioctl_test(do_SGXIOC_CREATE_AND_VERIFY_REPORT);
|
return do_sgx_ioctl_test(do_SGXIOC_CREATE_AND_VERIFY_REPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CONFIG_SIZE 512
|
||||||
|
int test_ioctl_SIOCGIFCONF(void) {
|
||||||
|
struct ifreq *req;
|
||||||
|
struct ifconf conf;
|
||||||
|
char buf[CONFIG_SIZE];
|
||||||
|
memset(buf, 0, CONFIG_SIZE);
|
||||||
|
|
||||||
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
conf.ifc_len = 0;
|
||||||
|
conf.ifc_buf = buf;
|
||||||
|
if (ioctl(sock, SIOCGIFCONF, &conf) < 0) {
|
||||||
|
close(sock);
|
||||||
|
THROW_ERROR("empty length ioctl failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf.ifc_len != 0) {
|
||||||
|
close(sock);
|
||||||
|
THROW_ERROR("wrong returned length");
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.ifc_len = CONFIG_SIZE;
|
||||||
|
conf.ifc_buf = 0;
|
||||||
|
if (ioctl(sock, SIOCGIFCONF, &conf) < 0) {
|
||||||
|
close(sock);
|
||||||
|
THROW_ERROR("empty buffer ioctl failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret_len = conf.ifc_len;
|
||||||
|
|
||||||
|
conf.ifc_len = CONFIG_SIZE;
|
||||||
|
conf.ifc_buf = buf;
|
||||||
|
if (ioctl(sock, SIOCGIFCONF, &conf) < 0) {
|
||||||
|
close(sock);
|
||||||
|
THROW_ERROR("buffer passed ioctl failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf.ifc_len != ret_len) {
|
||||||
|
close(sock);
|
||||||
|
THROW_ERROR("wrong return length");
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
req = (struct ifreq *)buf;
|
||||||
|
int num = conf.ifc_len / sizeof (struct ifreq);
|
||||||
|
|
||||||
|
printf(" interface names got:\n");
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
printf(" %d: %s\n", i + 1, req->ifr_name);
|
||||||
|
req ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test suite
|
// Test suite
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -226,7 +284,8 @@ static test_case_t test_cases[] = {
|
|||||||
TEST_CASE(test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID),
|
TEST_CASE(test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID),
|
||||||
TEST_CASE(test_sgx_ioctl_SGXIOC_GEN_QUOTE),
|
TEST_CASE(test_sgx_ioctl_SGXIOC_GEN_QUOTE),
|
||||||
TEST_CASE(test_sgx_ioctl_SGXIOC_SELF_TARGET),
|
TEST_CASE(test_sgx_ioctl_SGXIOC_SELF_TARGET),
|
||||||
TEST_CASE(test_sgx_ioctl_SGXIOC_CREATE_AND_VERIFY_REPORT)
|
TEST_CASE(test_sgx_ioctl_SGXIOC_CREATE_AND_VERIFY_REPORT),
|
||||||
|
TEST_CASE(test_ioctl_SIOCGIFCONF),
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user