Skip to content

Commit 7b7b67f

Browse files
committed
socket: implement the send path for ethernet sockets
1 parent 955f5c3 commit 7b7b67f

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

src/iface/interface/mod.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -735,8 +735,24 @@ impl Interface {
735735
)
736736
}),
737737
#[cfg(feature = "socket-eth")]
738-
Socket::Eth(_socket) => {
739-
todo!();
738+
Socket::Eth(socket) => {
739+
socket.dispatch(&mut self.inner, |inner, (eth_repr, payload)| {
740+
let token = device.transmit(inner.now).ok_or_else(|| {
741+
net_debug!("failed to transmit raw ETH: device exhausted");
742+
EgressError::Exhausted
743+
})?;
744+
let frame_len = eth_repr.buffer_len() + payload.len();
745+
inner.dispatch_ethernet(token, frame_len, |mut frame| {
746+
frame.set_dst_addr(eth_repr.dst_addr);
747+
frame.set_src_addr(eth_repr.src_addr);
748+
frame.set_ethertype(eth_repr.ethertype);
749+
frame.payload_mut().copy_from_slice(payload);
750+
});
751+
752+
result = PollResult::SocketStateChanged;
753+
754+
Ok(())
755+
})
740756
}
741757
};
742758

src/socket/eth.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,41 @@ impl<'a> Socket<'a> {
333333
self.rx_waker.wake();
334334
}
335335

336+
pub(crate) fn dispatch<F, E>(&mut self, cx: &mut Context, emit: F) -> Result<(), E>
337+
where
338+
F: FnOnce(&mut Context, (EthernetRepr, &[u8])) -> Result<(), E>,
339+
{
340+
let ethertype = self.ethertype;
341+
let res = self.tx_buffer.dequeue_with(|&mut (), buffer| {
342+
#[allow(clippy::useless_asref)]
343+
let frame = match EthernetFrame::new_checked(buffer.as_ref()) {
344+
Ok(x) => x,
345+
Err(_) => {
346+
net_trace!("eth: malformed ethernet frame in queue, dropping.");
347+
return Ok(());
348+
}
349+
};
350+
let eth_repr = match EthernetRepr::parse(&frame) {
351+
Ok(r) => r,
352+
Err(_) => {
353+
net_trace!("eth: malformed ethernet frame in queue, dropping.");
354+
return Ok(());
355+
}
356+
};
357+
net_trace!("eth:{}: sending", ethertype.unwrap_or(0));
358+
emit(cx, (eth_repr, frame.payload()))
359+
});
360+
match res {
361+
Err(Empty) => Ok(()),
362+
Ok(Err(e)) => Err(e),
363+
Ok(Ok(())) => {
364+
#[cfg(feature = "async")]
365+
self.tx_waker.wake();
366+
Ok(())
367+
}
368+
}
369+
}
370+
336371
pub(crate) fn poll_at(&self, _cx: &mut Context) -> PollAt {
337372
if self.tx_buffer.is_empty() {
338373
PollAt::Ingress
@@ -342,4 +377,62 @@ impl<'a> Socket<'a> {
342377
}
343378
}
344379

380+
#[cfg(test)]
381+
mod test {
382+
use super::*;
383+
384+
use crate::phy::Medium;
385+
use crate::tests::setup;
386+
use crate::wire::ethernet::EtherType;
387+
388+
fn buffer(packets: usize) -> PacketBuffer<'static> {
389+
PacketBuffer::new(vec![PacketMetadata::EMPTY; packets], vec![0; 48 * packets])
390+
}
391+
392+
const ETHER_TYPE: u16 = 0x1234;
393+
394+
fn socket(
395+
rx_buffer: PacketBuffer<'static>,
396+
tx_buffer: PacketBuffer<'static>,
397+
) -> Socket<'static> {
398+
Socket::new(Some(ETHER_TYPE), rx_buffer, tx_buffer)
399+
}
345400

401+
#[rustfmt::skip]
402+
pub const PACKET_BYTES: [u8; 18] = [
403+
0xaa, 0xbb, 0xcc, 0x12, 0x34, 0x56,
404+
0xaa, 0xbb, 0xcc, 0x78, 0x90, 0x12,
405+
0x12, 0x34,
406+
0xaa, 0x00, 0x00, 0xff,
407+
];
408+
pub const PACKET_PAYLOAD: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
409+
410+
#[test]
411+
fn test_send() {
412+
let (mut iface, _, _) = setup(Medium::Ethernet);
413+
let mut cx = iface.context();
414+
let mut socket = socket(buffer(1), buffer(1));
415+
assert!(socket.can_send());
416+
assert_eq!(socket.send_slice(&PACKET_BYTES[..]), Ok(()));
417+
assert_eq!(socket.send_slice(b""), Err(SendError::BufferFull));
418+
assert!(!socket.can_send());
419+
assert_eq!(
420+
socket.dispatch(&mut cx, |_, (eth_repr, eth_payload)| {
421+
assert_eq!(eth_repr.ethertype, EtherType::from(ETHER_TYPE));
422+
assert_eq!(eth_payload, PACKET_PAYLOAD);
423+
Err(())
424+
}),
425+
Err(())
426+
);
427+
assert!(!socket.can_send());
428+
assert_eq!(
429+
socket.dispatch(&mut cx, |_, (eth_repr, eth_payload)| {
430+
assert_eq!(eth_repr.ethertype, EtherType::from(ETHER_TYPE));
431+
assert_eq!(eth_payload, PACKET_PAYLOAD);
432+
Ok::<_, ()>(())
433+
}),
434+
Ok(())
435+
);
436+
assert!(socket.can_send());
437+
}
438+
}

0 commit comments

Comments
 (0)