net_srv/
gates.rs

1use std::{
2    net::IpAddr,
3    str::FromStr,
4    sync::{atomic::Ordering, Mutex},
5};
6
7use secgate::{util::HandleMgr, ResourceError, TwzError};
8use smoltcp::wire::EthernetAddress;
9use tracing::Level;
10use twizzler::{object::RawObject, Result};
11use twizzler_abi::syscall::ObjectCreate;
12use twizzler_net::{
13    packet::PacketObject, ClientMsg, ClientRet, NetClientConfig, NetClientOpenInfo, NetServer,
14    ServerMsg, ServerRet,
15};
16
17use crate::{
18    client::Client, device::device_thread, port::PortAssigner, NetworkInfo, NETINFO, PORTS,
19};
20
21const IP: &str = "10.0.2.15"; // QEMU user networking default IP
22const GATEWAY: &str = "10.0.2.2"; // QEMU user networking gateway
23
24#[secgate::entry(lib = "twizzler-net")]
25pub fn start_network() -> Result<()> {
26    tracing::subscriber::set_global_default(
27        tracing_subscriber::fmt()
28            .with_max_level(Level::INFO)
29            .without_time()
30            .finish(),
31    )
32    .unwrap();
33
34    if NETINFO.get().is_some() {
35        tracing::info!("cannot call start_network more than once");
36        return Err(TwzError::NOT_SUPPORTED);
37    }
38
39    let device = virtio_net::get_device();
40    let _device = device.clone();
41    std::thread::spawn(move || device_thread(_device));
42    tracing::info!("network ready: IP = {}, gateway = {}", IP, GATEWAY);
43
44    let _ = PORTS.set(PortAssigner::new());
45
46    let _ = NETINFO.set(NetworkInfo {
47        handles: Mutex::new(HandleMgr::new(None)),
48        device,
49    });
50
51    Ok(())
52}
53
54#[secgate::entry(lib = "twizzler-net")]
55fn twz_net_alloc_port(desc: secgate::util::Descriptor, port: Option<u16>) -> Result<u16> {
56    let handles = NETINFO
57        .get()
58        .ok_or(TwzError::NOT_SUPPORTED)?
59        .handles
60        .lock()
61        .unwrap();
62    let info = secgate::get_caller().ok_or(TwzError::INVALID_ARGUMENT)?;
63    let caller = info.source_context().ok_or(TwzError::INVALID_ARGUMENT)?;
64    let client = handles
65        .lookup(caller, desc)
66        .ok_or(TwzError::INVALID_ARGUMENT)?;
67
68    let mut ports = client.ports.lock().unwrap();
69    let port = if let Some(port) = port {
70        if !ports.contains_key(&port) {
71            if PORTS.get().unwrap().allocate_port(port) {
72                Some(port)
73            } else {
74                None
75            }
76        } else {
77            Some(port)
78        }
79    } else {
80        PORTS.get().unwrap().get_ephemeral_port()
81    };
82    let Some(port) = port else {
83        return Err(ResourceError::OutOfResources.into());
84    };
85
86    *ports.entry(port).or_default() += 1;
87    Ok(port)
88}
89
90#[secgate::entry(lib = "twizzler-net")]
91fn twz_net_release_port(desc: secgate::util::Descriptor, port: u16) -> Result<()> {
92    let handles = NETINFO
93        .get()
94        .ok_or(TwzError::NOT_SUPPORTED)?
95        .handles
96        .lock()
97        .unwrap();
98    let info = secgate::get_caller().ok_or(TwzError::INVALID_ARGUMENT)?;
99    let caller = info.source_context().ok_or(TwzError::INVALID_ARGUMENT)?;
100    let client = handles
101        .lookup(caller, desc)
102        .ok_or(TwzError::INVALID_ARGUMENT)?;
103    let mut ports = client.ports.lock().unwrap();
104    let entry = ports.entry(port).or_default();
105    *entry -= 1;
106    if *entry == 0 {
107        PORTS.get().unwrap().return_port(port);
108        ports.remove(&port);
109        Ok(())
110    } else {
111        Err(TwzError::INVALID_ARGUMENT)
112    }
113}
114
115#[secgate::entry(lib = "twizzler-net")]
116fn twz_net_drop_client(desc: secgate::util::Descriptor) -> Result<()> {
117    let mut handles = NETINFO
118        .get()
119        .ok_or(TwzError::NOT_SUPPORTED)?
120        .handles
121        .lock()
122        .unwrap();
123    let info = secgate::get_caller().ok_or(TwzError::INVALID_ARGUMENT)?;
124    let caller = info.source_context().ok_or(TwzError::INVALID_ARGUMENT)?;
125    if let Some(client) = handles.remove(caller, desc) {
126        client.active.store(false, Ordering::SeqCst);
127        for port in client.ports.lock().unwrap().drain() {
128            PORTS.get().unwrap().return_port(port.0);
129        }
130    }
131    Ok(())
132}
133
134#[secgate::entry(lib = "twizzler-net")]
135pub fn twz_net_open_client(_config: NetClientConfig) -> Result<NetClientOpenInfo> {
136    let mut handles = NETINFO
137        .get()
138        .ok_or(TwzError::NOT_SUPPORTED)?
139        .handles
140        .lock()
141        .unwrap();
142
143    let info = secgate::get_caller().ok_or(TwzError::INVALID_ARGUMENT)?;
144    let caller = info.source_context().ok_or(TwzError::INVALID_ARGUMENT)?;
145
146    let tx_buf = PacketObject::new(ObjectCreate::default(), 1024, 2048)?;
147    let rx_buf = PacketObject::new(ObjectCreate::default(), 1024, 2048)?;
148
149    let rx_queue_obj = unsafe {
150        twizzler::object::ObjectBuilder::<()>::default()
151            .build_ctor(|obj| {
152                twizzler_queue::Queue::<ServerMsg, ClientRet>::init(obj.handle(), 1024, 1024)
153            })
154            .expect("failed to create queue")
155    };
156    let tx_queue_obj = unsafe {
157        twizzler::object::ObjectBuilder::<()>::default()
158            .build_ctor(|obj| {
159                twizzler_queue::Queue::<ClientMsg, ServerRet>::init(obj.handle(), 1024, 1024)
160            })
161            .expect("failed to create queue")
162    };
163
164    let mut ncinfo = NetClientOpenInfo {
165        tx_buf: tx_buf.id(),
166        rx_buf: rx_buf.id(),
167        tx_queue: tx_queue_obj.id(),
168        rx_queue: rx_queue_obj.id(),
169        handle: 0,
170        addr: IpAddr::from_str(IP).unwrap(),
171        gateway: IpAddr::from_str(GATEWAY).unwrap(),
172        hwaddr: EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]),
173        addr_prefix_len: 8,
174    };
175
176    let ep = NetServer::open(&ncinfo)?;
177    let client = Client::new(ep);
178
179    let desc = handles
180        .insert(caller, client)
181        .ok_or(ResourceError::OutOfResources)?;
182    ncinfo.handle = desc;
183    Ok(ncinfo)
184}