Sort out buffer lengths.

This commit is contained in:
whitequark 2016-12-19 23:50:04 +00:00
parent 9c922d0306
commit f86fac2223
11 changed files with 64 additions and 31 deletions

View File

@ -21,7 +21,6 @@ The only supported medium is Ethernet.
* ARP packets (including gratuitous requests and replies) are supported. * ARP packets (including gratuitous requests and replies) are supported.
* 802.3 and 802.1Q are **not** supported. * 802.3 and 802.1Q are **not** supported.
* Jumbo frames are **not** supported. * Jumbo frames are **not** supported.
* Frame check sequence calculation is **not** supported.
### IP layer ### IP layer

View File

@ -216,10 +216,10 @@ impl<'a, 'b: 'a,
_ => return Err(Error::Unrecognized) _ => return Err(Error::Unrecognized)
} }
let tx_size = self.device.mtu();
match response { match response {
Response::Arp(repr) => { Response::Arp(repr) => {
let mut tx_buffer = try!(self.device.transmit(tx_size)); let tx_len = EthernetFrame::<&[u8]>::buffer_len(repr.buffer_len());
let mut tx_buffer = try!(self.device.transmit(tx_len));
let mut frame = try!(EthernetFrame::new(&mut tx_buffer)); let mut frame = try!(EthernetFrame::new(&mut tx_buffer));
frame.set_src_addr(self.hardware_addr); frame.set_src_addr(self.hardware_addr);
frame.set_dst_addr(match repr { frame.set_dst_addr(match repr {
@ -239,14 +239,16 @@ impl<'a, 'b: 'a,
Some(hardware_addr) => hardware_addr Some(hardware_addr) => hardware_addr
}; };
let mut tx_buffer = try!(self.device.transmit(tx_size)); let tx_len = EthernetFrame::<&[u8]>::buffer_len(ip_repr.buffer_len() +
icmp_repr.buffer_len());
let mut tx_buffer = try!(self.device.transmit(tx_len));
let mut frame = try!(EthernetFrame::new(&mut tx_buffer)); let mut frame = try!(EthernetFrame::new(&mut tx_buffer));
frame.set_src_addr(self.hardware_addr); frame.set_src_addr(self.hardware_addr);
frame.set_dst_addr(dst_hardware_addr); frame.set_dst_addr(dst_hardware_addr);
frame.set_ethertype(EthernetProtocolType::Ipv4); frame.set_ethertype(EthernetProtocolType::Ipv4);
let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut())); let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
ip_repr.emit(&mut ip_packet, icmp_repr.len()); ip_repr.emit(&mut ip_packet, icmp_repr.buffer_len());
let mut icmp_packet = try!(Icmpv4Packet::new(ip_packet.payload_mut())); let mut icmp_packet = try!(Icmpv4Packet::new(ip_packet.payload_mut()));
icmp_repr.emit(&mut icmp_packet); icmp_repr.emit(&mut icmp_packet);
@ -261,19 +263,6 @@ impl<'a, 'b: 'a,
for socket in self.sockets.borrow_mut() { for socket in self.sockets.borrow_mut() {
let result = socket.dispatch(&mut |src_addr, dst_addr, protocol, payload| { let result = socket.dispatch(&mut |src_addr, dst_addr, protocol, payload| {
let dst_hardware_addr =
match arp_cache.lookup(*dst_addr) {
None => return Err(Error::Unaddressable),
Some(hardware_addr) => hardware_addr
};
let mut tx_buffer = try!(device.transmit(tx_size));
let mut frame = try!(EthernetFrame::new(&mut tx_buffer));
frame.set_src_addr(src_hardware_addr);
frame.set_dst_addr(dst_hardware_addr);
frame.set_ethertype(EthernetProtocolType::Ipv4);
let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
let ip_repr = let ip_repr =
match (src_addr, dst_addr) { match (src_addr, dst_addr) {
(&InternetAddress::Ipv4(src_addr), (&InternetAddress::Ipv4(src_addr),
@ -286,7 +275,24 @@ impl<'a, 'b: 'a,
}, },
_ => unreachable!() _ => unreachable!()
}; };
ip_repr.emit(&mut ip_packet, payload.len());
let dst_hardware_addr =
match arp_cache.lookup(*dst_addr) {
None => return Err(Error::Unaddressable),
Some(hardware_addr) => hardware_addr
};
let tx_len = EthernetFrame::<&[u8]>::buffer_len(ip_repr.buffer_len() +
payload.buffer_len());
let mut tx_buffer = try!(device.transmit(tx_len));
let mut frame = try!(EthernetFrame::new(&mut tx_buffer));
frame.set_src_addr(src_hardware_addr);
frame.set_dst_addr(dst_hardware_addr);
frame.set_ethertype(EthernetProtocolType::Ipv4);
let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
ip_repr.emit(&mut ip_packet, payload.buffer_len());
payload.emit(src_addr, dst_addr, ip_packet.payload_mut()); payload.emit(src_addr, dst_addr, ip_packet.payload_mut());
Ok(()) Ok(())

View File

@ -38,7 +38,8 @@ impl Device for RawSocket {
fn receive(&mut self) -> Result<Self::RxBuffer, Error> { fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
let mut lower = self.lower.borrow_mut(); let mut lower = self.lower.borrow_mut();
let mut buffer = vec![0; self.mtu]; let mut buffer = vec![0; self.mtu];
lower.recv(&mut buffer[..]).unwrap(); let size = lower.recv(&mut buffer[..]).unwrap();
buffer.resize(size, 0);
Ok(buffer) Ok(buffer)
} }

View File

@ -38,7 +38,8 @@ impl Device for TapInterface {
fn receive(&mut self) -> Result<Self::RxBuffer, Error> { fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
let mut lower = self.lower.borrow_mut(); let mut lower = self.lower.borrow_mut();
let mut buffer = vec![0; self.mtu]; let mut buffer = vec![0; self.mtu];
lower.recv(&mut buffer[..]).unwrap(); let size = lower.recv(&mut buffer[..]).unwrap();
buffer.resize(size, 0);
Ok(buffer) Ok(buffer)
} }

View File

@ -27,8 +27,8 @@ pub use self::tcp::Buffer as TcpBuffer;
/// This interface abstracts the various types of packets layered under the IP protocol, /// This interface abstracts the various types of packets layered under the IP protocol,
/// and serves as an accessory to [trait Socket](trait.Socket.html). /// and serves as an accessory to [trait Socket](trait.Socket.html).
pub trait PacketRepr { pub trait PacketRepr {
/// Return the length required to serialize this high-level representation. /// Return the length of the buffer required to serialize this high-level representation.
fn len(&self) -> usize; fn buffer_len(&self) -> usize;
/// Emit this high-level representation into a sequence of octets. /// Emit this high-level representation into a sequence of octets.
fn emit(&self, src_addr: &Address, dst_addr: &Address, payload: &mut [u8]); fn emit(&self, src_addr: &Address, dst_addr: &Address, payload: &mut [u8]);

View File

@ -201,8 +201,8 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
} }
impl<'a> PacketRepr for UdpRepr<'a> { impl<'a> PacketRepr for UdpRepr<'a> {
fn len(&self) -> usize { fn buffer_len(&self) -> usize {
self.len() self.buffer_len()
} }
fn emit(&self, src_addr: &Address, dst_addr: &Address, payload: &mut [u8]) { fn emit(&self, src_addr: &Address, dst_addr: &Address, payload: &mut [u8]) {

View File

@ -263,6 +263,14 @@ impl Repr {
} }
} }
/// Return the length of a packet that will be emitted from this high-level representation.
pub fn buffer_len(&self) -> usize {
match self {
&Repr::EthernetIpv4 { .. } => field::TPA(6, 4).end,
&Repr::__Nonexhaustive => unreachable!()
}
}
/// Emit a high-level representation into an Address Resolution Protocol packet. /// Emit a high-level representation into an Address Resolution Protocol packet.
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) { pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
match self { match self {

View File

@ -1,5 +1,7 @@
use core::cmp;
use core::fmt; use core::fmt;
use byteorder::{ByteOrder, NetworkEndian}; use byteorder::{ByteOrder, NetworkEndian};
use Error; use Error;
enum_with_unknown! { enum_with_unknown! {
@ -95,6 +97,14 @@ impl<T: AsRef<[u8]>> Frame<T> {
self.buffer self.buffer
} }
/// Return the length of a buffer required to hold a packet with the payload
/// of a given length.
pub fn buffer_len(payload_len: usize) -> usize {
// Minimal frame size is 64, but that includes FCS, which the network device
// is taking care of for us.
cmp::max(field::PAYLOAD.start + payload_len, 60)
}
/// Return the destination address field. /// Return the destination address field.
#[inline(always)] #[inline(always)]
pub fn dst_addr(&self) -> Address { pub fn dst_addr(&self) -> Address {

View File

@ -332,7 +332,7 @@ impl<'a> Repr<'a> {
} }
/// Return the length of a packet that will be emitted from this high-level representation. /// Return the length of a packet that will be emitted from this high-level representation.
pub fn len(&self) -> usize { pub fn buffer_len(&self) -> usize {
match self { match self {
&Repr::EchoRequest { data, .. } | &Repr::EchoRequest { data, .. } |
&Repr::EchoReply { data, .. } => { &Repr::EchoReply { data, .. } => {
@ -384,10 +384,12 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
impl<'a> fmt::Display for Repr<'a> { impl<'a> fmt::Display for Repr<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&Repr::EchoRequest { ident, seq_no, .. } => &Repr::EchoRequest { ident, seq_no, data } =>
write!(f, "ICMPv4 Echo Request id={} seq={}", ident, seq_no), write!(f, "ICMPv4 Echo Request id={} seq={} len={}",
&Repr::EchoReply { ident, seq_no, .. } => ident, seq_no, data.len()),
write!(f, "ICMPv4 Echo Reply id={} seq={}", ident, seq_no), &Repr::EchoReply { ident, seq_no, data } =>
write!(f, "ICMPv4 Echo Reply id={} seq={} len={}",
ident, seq_no, data.len()),
&Repr::__Nonexhaustive => unreachable!() &Repr::__Nonexhaustive => unreachable!()
} }
} }

View File

@ -382,6 +382,12 @@ impl Repr {
}) })
} }
/// Return the length of a header that will be emitted from this high-level representation.
pub fn buffer_len(&self) -> usize {
// We never emit any options.
field::DST_ADDR.end
}
/// Emit a high-level representation into an Internet Protocol version 4 packet. /// Emit a high-level representation into an Internet Protocol version 4 packet.
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>, pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>,
payload_len: usize) { payload_len: usize) {

View File

@ -197,7 +197,7 @@ impl<'a> Repr<'a> {
} }
/// Return the length of a packet that will be emitted from this high-level representation. /// Return the length of a packet that will be emitted from this high-level representation.
pub fn len(&self) -> usize { pub fn buffer_len(&self) -> usize {
field::CHECKSUM.end + self.payload.len() field::CHECKSUM.end + self.payload.len()
} }