add net support

This commit is contained in:
yufeng 2023-02-06 19:21:43 +08:00
parent fa2d574c3b
commit 44bf23ee88
12 changed files with 354 additions and 0 deletions

View File

@ -15,6 +15,7 @@ bitflags = "1.2.1"
xmas-elf = "0.7.0"
volatile = "0.3"
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" }
easy-fs = { path = "../easy-fs" }
virtio-input-decoder = "0.1.4"
embedded-graphics = "0.7.1"

View File

@ -85,6 +85,8 @@ run-inner-none: build
# -device virtio-gpu-device \
-device virtio-keyboard-device \
-device virtio-mouse-device \
-device virtio-net-device,netdev=net0 \
-netdev user,id=net0,hostfwd=udp::6200-:2000 \
-serial stdio
run-inner: build
@ -99,6 +101,8 @@ run-inner: build
-device virtio-gpu-device \
-device virtio-keyboard-device \
-device virtio-mouse-device \
-device virtio-net-device,netdev=net0 \
-netdev user,id=net0,hostfwd=udp::6200-:2000 \
-serial stdio
fdt:

View File

@ -3,6 +3,7 @@ pub mod bus;
pub mod chardev;
pub mod gpu;
pub mod input;
pub mod net;
pub mod plic;
pub use block::BLOCK_DEVICE;
@ -10,3 +11,4 @@ pub use bus::*;
pub use chardev::UART;
pub use gpu::*;
pub use input::*;
pub use net::*;

41
os/src/drivers/net/mod.rs Normal file
View File

@ -0,0 +1,41 @@
use core::any::Any;
use alloc::sync::Arc;
use lazy_static::*;
use virtio_drivers::{VirtIONet, VirtIOHeader};
use crate::drivers::virtio::VirtioHal;
use crate::sync::UPIntrFreeCell;
const VIRTIO8: usize = 0x10004000;
lazy_static! {
pub static ref NET_DEVICE: Arc<dyn NetDevice> = Arc::new(VirtIONetWrapper::new());
}
pub trait NetDevice: Send + Sync + Any {
fn transmit(&self, data: &[u8]);
fn receive(&self, data: &mut [u8]) -> usize;
}
pub struct VirtIONetWrapper(UPIntrFreeCell<VirtIONet<'static, VirtioHal>>);
impl NetDevice for VirtIONetWrapper {
fn transmit(&self, data: &[u8]) {
self.0.exclusive_access().send(data).expect("can't send data")
}
fn receive(&self, data: &mut [u8]) -> usize {
self.0.exclusive_access().recv(data).expect("can't receive data")
}
}
impl VirtIONetWrapper {
pub fn new() -> Self {
unsafe {
let virtio =
VirtIONet::<VirtioHal>::new(&mut *(VIRTIO8 as *mut VirtIOHeader))
.expect("can't create net device by virtio");
VirtIONetWrapper(UPIntrFreeCell::new(virtio))
}
}
}

View File

@ -29,6 +29,7 @@ mod syscall;
mod task;
mod timer;
mod trap;
mod net;
use riscv::register::*;
// mod riscvreg;

92
os/src/net/mod.rs Normal file
View File

@ -0,0 +1,92 @@
pub mod udp;
pub mod socket;
pub use lose_net_stack::IPv4;
use alloc::{vec, sync::Arc};
use lose_net_stack::{LoseStack, MacAddress, results::Packet};
use crate::{drivers::NET_DEVICE, sync::UPIntrFreeCell, net::socket::{get_socket, push_data}};
pub struct NetStack(UPIntrFreeCell<LoseStack>);
impl NetStack {
pub fn new() -> Self {
unsafe {
NetStack(UPIntrFreeCell::new(LoseStack::new(
IPv4::new(10, 0, 2, 15),
MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56])
)))
}
}
}
lazy_static::lazy_static! {
static ref LOSE_NET_STACK: Arc<NetStack> = Arc::new(NetStack::new());
}
pub fn net_interrupt_handler() {
let mut recv_buf = vec![0u8; 1024];
let len = NET_DEVICE.receive(&mut recv_buf);
let packet = LOSE_NET_STACK.0.exclusive_access().analysis(&recv_buf[..len]);
// println!("[kernel] receive a packet");
// hexdump(&recv_buf[..len]);
match packet {
Packet::ARP(arp_packet) => {
let lose_stack = LOSE_NET_STACK.0.exclusive_access();
let reply_packet = arp_packet.reply_packet(lose_stack.ip, lose_stack.mac).expect("can't build reply");
let reply_data = reply_packet.build_data();
NET_DEVICE.transmit(&reply_data)
},
Packet::UDP(udp_packet) => {
let target = udp_packet.source_ip;
let lport = udp_packet.dest_port;
let rport = udp_packet.source_port;
if let Some(socket_index) = get_socket(target, lport, rport) {
push_data(socket_index, udp_packet.data.to_vec());
}
}
_ => {}
}
}
#[allow(unused)]
pub fn hexdump(data: &[u8]) {
const PRELAND_WIDTH: usize = 70;
println!("[kernel] {:-^1$}", " hexdump ", PRELAND_WIDTH);
for offset in (0..data.len()).step_by(16) {
print!("[kernel] ");
for i in 0..16 {
if offset + i < data.len() {
print!("{:02x} ", data[offset + i]);
} else {
print!("{:02} ", "");
}
}
print!("{:>6}", ' ');
for i in 0..16 {
if offset + i < data.len() {
let c = data[offset + i];
if c >= 0x20 && c <= 0x7e {
print!("{}", c as char);
} else {
print!(".");
}
} else {
print!("{:02} ", "");
}
}
println!("");
}
println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH);
}

93
os/src/net/socket.rs Normal file
View File

@ -0,0 +1,93 @@
use alloc::collections::VecDeque;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use lose_net_stack::IPv4;
use crate::sync::UPIntrFreeCell;
// TODO: specify the protocol, TCP or UDP
pub struct Socket {
pub raddr: IPv4, // remote address
pub lport: u16, // local port
pub rport: u16, // rempote port
pub buffers: VecDeque<Vec<u8>> // datas
}
lazy_static! {
static ref SOCKET_TABLE:UPIntrFreeCell<Vec<Option<Socket>>> = unsafe {
UPIntrFreeCell::new(Vec::new())
};
}
pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
let socket_table = SOCKET_TABLE.exclusive_access();
for i in 0..socket_table.len() {
let sock = &socket_table[i];
if sock.is_none() {
continue;
}
let sock = sock.as_ref().unwrap();
if sock.raddr == raddr && sock.lport == lport && sock.rport == rport {
return Some(i)
}
}
None
}
pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
if get_socket(raddr, lport, rport).is_some() {
return None;
}
let mut socket_table = SOCKET_TABLE.exclusive_access();
let mut index = usize::MAX;
for i in 0..socket_table.len() {
if socket_table[i].is_none() {
index = i;
break;
}
}
let socket = Socket {
raddr,
lport,
rport,
buffers: VecDeque::new()
};
if index == usize::MAX {
socket_table.push(Some(socket));
Some(socket_table.len() - 1)
} else {
socket_table[index] = Some(socket);
Some(index)
}
}
pub fn remove_socket(index: usize) {
let mut socket_table = SOCKET_TABLE.exclusive_access();
assert!(socket_table.len() > index);
socket_table[index] = None;
}
pub fn push_data(index: usize, data: Vec<u8>) {
let mut socket_table = SOCKET_TABLE.exclusive_access();
assert!(socket_table.len() > index);
assert!(socket_table[index].is_some());
socket_table[index].as_mut().unwrap().buffers.push_back(data);
}
pub fn pop_data(index: usize) -> Option<Vec<u8>> {
let mut socket_table = SOCKET_TABLE.exclusive_access();
assert!(socket_table.len() > index);
assert!(socket_table[index].is_some());
socket_table[index].as_mut().unwrap().buffers.pop_front()
}

94
os/src/net/udp.rs Normal file
View File

@ -0,0 +1,94 @@
use alloc::vec;
use lose_net_stack::MacAddress;
use lose_net_stack::packets::udp::UDPPacket;
use lose_net_stack::IPv4;
use crate::fs::File;
use super::net_interrupt_handler;
use super::socket::{add_socket, remove_socket, pop_data};
use super::LOSE_NET_STACK;
use super::NET_DEVICE;
pub struct UDP{
pub target: IPv4,
pub sport: u16,
pub dport: u16,
pub socket_index: usize
}
impl UDP {
pub fn new(target: IPv4, sport: u16, dport: u16) -> Self {
let index = add_socket(target, sport, dport).expect("can't add socket");
Self {
target,
sport,
dport,
socket_index: index
}
}
}
impl File for UDP {
fn readable(&self) -> bool {
true
}
fn writable(&self) -> bool {
true
}
fn read(&self, mut buf: crate::mm::UserBuffer) -> usize {
loop {
if let Some(data) = pop_data(self.socket_index) {
let data_len = data.len();
let mut left = 0;
for i in 0..buf.buffers.len() {
let buffer_i_len = buf.buffers[i].len().min(data_len - left);
buf.buffers[i][..buffer_i_len].copy_from_slice(&data[left..(left + buffer_i_len)]);
left += buffer_i_len;
if left == data_len {
break;
}
}
return left;
} else {
net_interrupt_handler();
}
}
}
fn write(&self, buf: crate::mm::UserBuffer) -> usize {
let lose_net_stack = LOSE_NET_STACK.0.exclusive_access();
let mut data = vec![0u8; buf.len()];
let mut left = 0;
for i in 0..buf.buffers.len() {
data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]);
left += buf.buffers[i].len();
}
let len = data.len();
let udp_packet = UDPPacket::new(
lose_net_stack.ip,
lose_net_stack.mac,
self.sport,
self.target,
MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
self.dport,
len,
data.as_ref()
);
NET_DEVICE.transmit(&udp_packet.build_data());
len
}
}
impl Drop for UDP {
fn drop(&mut self) {
remove_socket(self.socket_index)
}
}

View File

@ -1,4 +1,5 @@
const SYSCALL_DUP: usize = 24;
const SYSCALL_CONNECT: usize = 29;
const SYSCALL_OPEN: usize = 56;
const SYSCALL_CLOSE: usize = 57;
const SYSCALL_PIPE: usize = 59;
@ -30,15 +31,18 @@ mod fs;
mod process;
mod sync;
mod thread;
mod net;
use fs::*;
use process::*;
use sync::*;
use thread::*;
use net::*;
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
match syscall_id {
SYSCALL_DUP => sys_dup(args[0]),
SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _),
SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32),
SYSCALL_CLOSE => sys_close(args[0]),
SYSCALL_PIPE => sys_pipe(args[0] as *mut usize),

14
os/src/syscall/net.rs Normal file
View File

@ -0,0 +1,14 @@
use alloc::sync::Arc;
use crate::net::IPv4;
use crate::net::udp::UDP;
use crate::task::current_process;
// just support udp
pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize {
let process = current_process();
let mut inner = process.inner_exclusive_access();
let fd = inner.alloc_fd();
let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport);
inner.fd_table[fd] = Some(Arc::new(udp_node));
fd as isize
}

View File

@ -72,6 +72,9 @@ bitflags! {
pub fn dup(fd: usize) -> isize {
sys_dup(fd)
}
pub fn connect(ip: u32, sport: u16, dport: u16) -> isize {
sys_connect(ip, sport, dport)
}
pub fn open(path: &str, flags: OpenFlags) -> isize {
sys_open(path, flags.bits)
}

View File

@ -1,4 +1,5 @@
const SYSCALL_DUP: usize = 24;
const SYSCALL_CONNECT: usize = 29;
const SYSCALL_OPEN: usize = 56;
const SYSCALL_CLOSE: usize = 57;
const SYSCALL_PIPE: usize = 59;
@ -44,6 +45,10 @@ pub fn sys_dup(fd: usize) -> isize {
syscall(SYSCALL_DUP, [fd, 0, 0])
}
pub fn sys_connect(dest: u32, sport: u16, dport: u16) -> isize {
syscall(SYSCALL_CONNECT, [dest as usize, sport as usize, dport as usize])
}
pub fn sys_open(path: &str, flags: u32) -> isize {
syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0])
}