mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 09:26:26 +04:00
add net support
This commit is contained in:
parent
fa2d574c3b
commit
44bf23ee88
@ -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"
|
||||
|
@ -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:
|
||||
|
@ -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
41
os/src/drivers/net/mod.rs
Normal 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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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
92
os/src/net/mod.rs
Normal 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
93
os/src/net/socket.rs
Normal 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
94
os/src/net/udp.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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
14
os/src/syscall/net.rs
Normal 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
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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])
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user