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"; const GATEWAY: &str = "10.0.2.2"; #[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}