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.
* 802.3 and 802.1Q are **not** supported.
* Jumbo frames are **not** supported.
* Frame check sequence calculation is **not** supported.
### IP layer

View File

@ -216,10 +216,10 @@ impl<'a, 'b: 'a,
_ => return Err(Error::Unrecognized)
}
let tx_size = self.device.mtu();
match response {
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));
frame.set_src_addr(self.hardware_addr);
frame.set_dst_addr(match repr {
@ -239,14 +239,16 @@ impl<'a, 'b: 'a,
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));
frame.set_src_addr(self.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, icmp_repr.len());
ip_repr.emit(&mut ip_packet, icmp_repr.buffer_len());
let mut icmp_packet = try!(Icmpv4Packet::new(ip_packet.payload_mut()));
icmp_repr.emit(&mut icmp_packet);
@ -261,19 +263,6 @@ impl<'a, 'b: 'a,
for socket in self.sockets.borrow_mut() {
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 =
match (src_addr, dst_addr) {
(&InternetAddress::Ipv4(src_addr),
@ -286,7 +275,24 @@ impl<'a, 'b: 'a,
},
_ => 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());
Ok(())

View File

@ -38,7 +38,8 @@ impl Device for RawSocket {
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
let mut lower = self.lower.borrow_mut();
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)
}

View File

@ -38,7 +38,8 @@ impl Device for TapInterface {
fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
let mut lower = self.lower.borrow_mut();
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)
}

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,
/// and serves as an accessory to [trait Socket](trait.Socket.html).
pub trait PacketRepr {
/// Return the length required to serialize this high-level representation.
fn len(&self) -> usize;
/// Return the length of the buffer required to serialize this high-level representation.
fn buffer_len(&self) -> usize;
/// Emit this high-level representation into a sequence of octets.
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> {
fn len(&self) -> usize {
self.len()
fn buffer_len(&self) -> usize {
self.buffer_len()
}
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.
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
match self {

View File

@ -1,5 +1,7 @@
use core::cmp;
use core::fmt;
use byteorder::{ByteOrder, NetworkEndian};
use Error;
enum_with_unknown! {
@ -95,6 +97,14 @@ impl<T: AsRef<[u8]>> Frame<T> {
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.
#[inline(always)]
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.
pub fn len(&self) -> usize {
pub fn buffer_len(&self) -> usize {
match self {
&Repr::EchoRequest { 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> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Repr::EchoRequest { ident, seq_no, .. } =>
write!(f, "ICMPv4 Echo Request id={} seq={}", ident, seq_no),
&Repr::EchoReply { ident, seq_no, .. } =>
write!(f, "ICMPv4 Echo Reply id={} seq={}", ident, seq_no),
&Repr::EchoRequest { ident, seq_no, data } =>
write!(f, "ICMPv4 Echo Request id={} seq={} len={}",
ident, seq_no, data.len()),
&Repr::EchoReply { ident, seq_no, data } =>
write!(f, "ICMPv4 Echo Reply id={} seq={} len={}",
ident, seq_no, data.len()),
&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.
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>,
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.
pub fn len(&self) -> usize {
pub fn buffer_len(&self) -> usize {
field::CHECKSUM.end + self.payload.len()
}