mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-25 19:03:35 +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"
|
xmas-elf = "0.7.0"
|
||||||
volatile = "0.3"
|
volatile = "0.3"
|
||||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
|
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" }
|
easy-fs = { path = "../easy-fs" }
|
||||||
virtio-input-decoder = "0.1.4"
|
virtio-input-decoder = "0.1.4"
|
||||||
embedded-graphics = "0.7.1"
|
embedded-graphics = "0.7.1"
|
||||||
|
@ -85,6 +85,8 @@ run-inner-none: build
|
|||||||
# -device virtio-gpu-device \
|
# -device virtio-gpu-device \
|
||||||
-device virtio-keyboard-device \
|
-device virtio-keyboard-device \
|
||||||
-device virtio-mouse-device \
|
-device virtio-mouse-device \
|
||||||
|
-device virtio-net-device,netdev=net0 \
|
||||||
|
-netdev user,id=net0,hostfwd=udp::6200-:2000 \
|
||||||
-serial stdio
|
-serial stdio
|
||||||
|
|
||||||
run-inner: build
|
run-inner: build
|
||||||
@ -99,6 +101,8 @@ run-inner: build
|
|||||||
-device virtio-gpu-device \
|
-device virtio-gpu-device \
|
||||||
-device virtio-keyboard-device \
|
-device virtio-keyboard-device \
|
||||||
-device virtio-mouse-device \
|
-device virtio-mouse-device \
|
||||||
|
-device virtio-net-device,netdev=net0 \
|
||||||
|
-netdev user,id=net0,hostfwd=udp::6200-:2000 \
|
||||||
-serial stdio
|
-serial stdio
|
||||||
|
|
||||||
fdt:
|
fdt:
|
||||||
|
@ -3,6 +3,7 @@ pub mod bus;
|
|||||||
pub mod chardev;
|
pub mod chardev;
|
||||||
pub mod gpu;
|
pub mod gpu;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
pub mod net;
|
||||||
pub mod plic;
|
pub mod plic;
|
||||||
|
|
||||||
pub use block::BLOCK_DEVICE;
|
pub use block::BLOCK_DEVICE;
|
||||||
@ -10,3 +11,4 @@ pub use bus::*;
|
|||||||
pub use chardev::UART;
|
pub use chardev::UART;
|
||||||
pub use gpu::*;
|
pub use gpu::*;
|
||||||
pub use input::*;
|
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 task;
|
||||||
mod timer;
|
mod timer;
|
||||||
mod trap;
|
mod trap;
|
||||||
|
mod net;
|
||||||
|
|
||||||
use riscv::register::*;
|
use riscv::register::*;
|
||||||
// mod riscvreg;
|
// 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_DUP: usize = 24;
|
||||||
|
const SYSCALL_CONNECT: usize = 29;
|
||||||
const SYSCALL_OPEN: usize = 56;
|
const SYSCALL_OPEN: usize = 56;
|
||||||
const SYSCALL_CLOSE: usize = 57;
|
const SYSCALL_CLOSE: usize = 57;
|
||||||
const SYSCALL_PIPE: usize = 59;
|
const SYSCALL_PIPE: usize = 59;
|
||||||
@ -30,15 +31,18 @@ mod fs;
|
|||||||
mod process;
|
mod process;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod thread;
|
mod thread;
|
||||||
|
mod net;
|
||||||
|
|
||||||
use fs::*;
|
use fs::*;
|
||||||
use process::*;
|
use process::*;
|
||||||
use sync::*;
|
use sync::*;
|
||||||
use thread::*;
|
use thread::*;
|
||||||
|
use net::*;
|
||||||
|
|
||||||
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||||
match syscall_id {
|
match syscall_id {
|
||||||
SYSCALL_DUP => sys_dup(args[0]),
|
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_OPEN => sys_open(args[0] as *const u8, args[1] as u32),
|
||||||
SYSCALL_CLOSE => sys_close(args[0]),
|
SYSCALL_CLOSE => sys_close(args[0]),
|
||||||
SYSCALL_PIPE => sys_pipe(args[0] as *mut usize),
|
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 {
|
pub fn dup(fd: usize) -> isize {
|
||||||
sys_dup(fd)
|
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 {
|
pub fn open(path: &str, flags: OpenFlags) -> isize {
|
||||||
sys_open(path, flags.bits)
|
sys_open(path, flags.bits)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const SYSCALL_DUP: usize = 24;
|
const SYSCALL_DUP: usize = 24;
|
||||||
|
const SYSCALL_CONNECT: usize = 29;
|
||||||
const SYSCALL_OPEN: usize = 56;
|
const SYSCALL_OPEN: usize = 56;
|
||||||
const SYSCALL_CLOSE: usize = 57;
|
const SYSCALL_CLOSE: usize = 57;
|
||||||
const SYSCALL_PIPE: usize = 59;
|
const SYSCALL_PIPE: usize = 59;
|
||||||
@ -44,6 +45,10 @@ pub fn sys_dup(fd: usize) -> isize {
|
|||||||
syscall(SYSCALL_DUP, [fd, 0, 0])
|
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 {
|
pub fn sys_open(path: &str, flags: u32) -> isize {
|
||||||
syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0])
|
syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0])
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user