1use std::net::IpAddr;
2
3use monitor_api::CompartmentHandle;
4use secgate::{
5 TwzError,
6 util::{Descriptor, Handle},
7};
8use smoltcp::{
9 phy::{DeviceCapabilities, Medium, RxToken, TxToken},
10 wire::EthernetAddress,
11};
12use twizzler::object::{MapFlags, ObjID, Object, RawObject};
13use twizzler_abi::syscall::ThreadSyncSleep;
14use twizzler_io::packet::PacketObject;
15use twizzler_queue::{Queue, QueueBase};
16
17use crate::{
18 ClientMsg, ClientMsgKind, ClientRet, INVALID_PACKET, PacketNum, PacketSet, ServerMsg,
19 ServerMsgKind, ServerRet, endpoint::Pair,
20};
21
22pub struct NetClient {
23 tx: Pair<ClientMsg, ServerRet>,
24 rx: Pair<ServerMsg, ClientRet>,
25 handle: Descriptor,
26 pending_rx: PacketSet,
27 pending_id: Option<u32>,
28 pub info: NetClientOpenInfo,
29}
30
31#[derive(Clone, Copy, Debug)]
32#[repr(C)]
33pub struct NetClientOpenInfo {
34 pub tx_buf: ObjID,
35 pub rx_buf: ObjID,
36 pub tx_queue: ObjID,
37 pub rx_queue: ObjID,
38 pub handle: Descriptor,
39 pub addr: IpAddr,
40 pub addr_prefix_len: u8,
41 pub gateway: IpAddr,
42 pub hwaddr: EthernetAddress,
43}
44
45impl NetClient {
46 pub fn rx_waiter(&self) -> ThreadSyncSleep {
47 self.rx.rx_waiter()
48 }
49
50 pub fn has_rx_pending(&self) -> bool {
51 self.rx.has_pending_msg() || self.pending_rx.0.iter().any(|p| *p != INVALID_PACKET)
52 }
53}
54
55pub fn net_open_client(config: NetClientConfig) -> Result<NetClientOpenInfo, TwzError> {
56 let comp = CompartmentHandle::lookup("net")?;
57 let gate = unsafe { comp.dynamic_gate("twz_net_open_client") }?;
58 (gate)(config)
59}
60
61pub fn net_drop_client(desc: u32) -> Result<(), TwzError> {
62 let comp = CompartmentHandle::lookup("net")?;
63 let gate = unsafe { comp.dynamic_gate("twz_net_drop_client") }?;
64 (gate)(desc)
65}
66
67pub fn net_alloc_port(desc: Descriptor, port: Option<u16>) -> Result<u16, TwzError> {
68 let comp = CompartmentHandle::lookup("net")?;
69 let gate = unsafe { comp.dynamic_gate("twz_net_alloc_port") }?;
70 (gate)(desc, port)
71}
72
73pub fn net_release_port(desc: Descriptor, port: u16) -> Result<(), TwzError> {
74 let comp = CompartmentHandle::lookup("net")?;
75 let gate = unsafe { comp.dynamic_gate("twz_net_release_port") }?;
76 (gate)(desc, port)
77}
78
79impl secgate::util::Handle for NetClient {
80 type OpenError = TwzError;
81
82 type OpenInfo = NetClientConfig;
83
84 fn open(info: Self::OpenInfo) -> Result<Self, Self::OpenError>
85 where
86 Self: Sized,
87 {
88 let info = net_open_client(info)?;
89 let tx_queue = Object::<QueueBase<ClientMsg, ServerRet>>::map(
90 info.tx_queue,
91 MapFlags::READ | MapFlags::WRITE,
92 )?;
93 let rx_queue = Object::<QueueBase<ServerMsg, ClientRet>>::map(
94 info.rx_queue,
95 MapFlags::READ | MapFlags::WRITE,
96 )?;
97 let tx = Pair::new(
98 PacketObject::from(Object::map(info.tx_buf, MapFlags::READ | MapFlags::WRITE)?),
99 Queue::from(tx_queue.handle().clone()),
100 );
101 let rx = Pair::new(
102 PacketObject::from(Object::map(info.rx_buf, MapFlags::READ | MapFlags::WRITE)?),
103 Queue::from(rx_queue.handle().clone()),
104 );
105 Ok(Self {
106 tx,
107 rx,
108 handle: info.handle,
109 pending_id: None,
110 pending_rx: PacketSet::new(),
111 info,
112 })
113 }
114
115 fn release(&mut self) {
116 let _ = net_drop_client(self.handle);
117 }
118}
119
120impl Drop for NetClient {
121 fn drop(&mut self) {
122 self.release();
123 }
124}
125
126#[derive(Clone, Copy, Debug)]
127#[repr(C)]
128pub struct NetClientConfig {}
129
130impl smoltcp::phy::Device for NetClient {
131 type RxToken<'a>
132 = NetClientRxToken<'a>
133 where
134 Self: 'a;
135
136 type TxToken<'a>
137 = NetClientTxToken<'a>
138 where
139 Self: 'a;
140
141 fn receive(
142 &mut self,
143 timestamp: smoltcp::time::Instant,
144 ) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
145 let idx = self.pending_rx.0.iter().position(|x| *x != INVALID_PACKET);
146 if let Some(idx) = idx {
147 let next = self.pending_rx.0[idx];
148 self.pending_rx.0[idx] = INVALID_PACKET;
149 self.tx.check_completions();
150
151 return Some((
152 NetClientRxToken {
153 nc: self,
154 packet: next,
155 },
156 NetClientTxToken {
157 nc: self,
158 packet: self.tx.allocate_packet().unwrap(),
159 consumed: false,
160 },
161 ));
162 }
163
164 if let Some(pending_id) = self.pending_id.take() {
165 self.rx.complete(pending_id, ClientRet {});
166 }
167
168 let (id, msg) = self.rx.recv_msg()?;
169 self.pending_id = Some(id);
170 match msg.kind {
171 ServerMsgKind::Tx(packet_set) => {
172 self.pending_rx = packet_set;
173 }
174 }
175 self.receive(timestamp)
176 }
177
178 fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
179 self.tx.check_completions();
180 let packet = self.tx.allocate_packet()?;
181 Some(NetClientTxToken {
182 nc: self,
183 packet,
184 consumed: false,
185 })
186 }
187
188 fn capabilities(&self) -> DeviceCapabilities {
189 let mut cap = DeviceCapabilities::default();
190 cap.medium = Medium::Ethernet;
191 cap.max_transmission_unit = 1514;
192 cap.max_burst_size = Some(1);
193 cap
194 }
195}
196
197pub struct NetClientTxToken<'a> {
198 nc: &'a NetClient,
199 packet: PacketNum,
200 consumed: bool,
201}
202
203pub struct NetClientRxToken<'a> {
204 nc: &'a NetClient,
205 packet: PacketNum,
206}
207
208impl TxToken for NetClientTxToken<'_> {
209 fn consume<R, F>(mut self, len: usize, f: F) -> R
210 where
211 F: FnOnce(&mut [u8]) -> R,
212 {
213 if len > self.nc.tx.packet_size() {
214 panic!("packet size exceeded");
215 }
216 let mem = self.nc.tx.packet_mem_mut(self.packet);
217 let ret = f(&mut mem[0..len]);
218 self.consumed = true;
219
220 self.nc
221 .tx
222 .send_packets(&[self.packet], |s| ClientMsg {
223 kind: ClientMsgKind::Tx(s),
224 })
225 .expect("failed to send packet");
226
227 ret
228 }
229}
230
231impl RxToken for NetClientRxToken<'_> {
232 fn consume<R, F>(self, f: F) -> R
233 where
234 F: FnOnce(&mut [u8]) -> R,
235 {
236 let mem = self.nc.rx.packet_mem_mut(self.packet);
237 f(mem)
238 }
239}
240
241impl Drop for NetClientTxToken<'_> {
242 fn drop(&mut self) {
243 if !self.consumed {
244 self.nc.tx.release_packet(self.packet);
245 }
246 }
247}