Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: d02961b0f253
Choose a base ref
...
head repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3335b698b43a
Choose a head ref
  • 2 commits
  • 11 files changed
  • 1 contributor

Commits on Dec 19, 2016

  1. Sort out buffer lengths.

    whitequark committed Dec 19, 2016

    Unverified

    The signing certificate or its chain could not be verified.
    Copy the full SHA
    85ae54a View commit details

Commits on Dec 20, 2016

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3335b69 View commit details
Showing with 135 additions and 62 deletions.
  1. +0 −1 README.md
  2. +95 −49 src/iface/ethernet.rs
  3. +2 −1 src/phy/raw_socket.rs
  4. +2 −1 src/phy/tap_interface.rs
  5. +2 −2 src/socket/mod.rs
  6. +2 −2 src/socket/udp.rs
  7. +8 −0 src/wire/arp.rs
  8. +10 −0 src/wire/ethernet.rs
  9. +7 −5 src/wire/icmpv4.rs
  10. +6 −0 src/wire/ipv4.rs
  11. +1 −1 src/wire/udp.rs
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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

144 changes: 95 additions & 49 deletions src/iface/ethernet.rs
Original file line number Diff line number Diff line change
@@ -118,6 +118,12 @@ impl<'a, 'b: 'a,
Icmpv4(Ipv4Repr, Icmpv4Repr<'a>)
}

// First, transmit any outgoing packets.
loop {
if try!(self.emit()) { break }
}

// Now, receive any incoming packets.
let rx_buffer = try!(self.device.receive());
let eth_frame = try!(EthernetFrame::new(&rx_buffer));

@@ -216,10 +222,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 {
@@ -229,7 +235,9 @@ impl<'a, 'b: 'a,
frame.set_ethertype(EthernetProtocolType::Arp);

let mut packet = try!(ArpPacket::new(frame.payload_mut()));
repr.emit(&mut packet)
repr.emit(&mut packet);

Ok(())
},

Response::Icmpv4(ip_repr, icmp_repr) => {
@@ -239,69 +247,107 @@ 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);

Ok(())
}

Response::Nop => {
// Borrow checker is being overly careful around closures, so we have
// to hack around that.
let src_hardware_addr = self.hardware_addr;
let arp_cache = &mut self.arp_cache;
let device = &mut self.device;

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),
&InternetAddress::Ipv4(dst_addr)) => {
Ipv4Repr {
src_addr: src_addr,
dst_addr: dst_addr,
protocol: protocol
Ok(())
}
}
}

pub fn emit(&mut self) -> Result<bool, Error> {
// Borrow checker is being overly careful around closures, so we have
// to hack around that.
let src_hardware_addr = self.hardware_addr;
let src_protocol_addrs = self.protocol_addrs.borrow();
let arp_cache = &mut self.arp_cache;
let device = &mut self.device;

let mut nothing_to_transmit = true;
for socket in self.sockets.borrow_mut() {
let result = socket.dispatch(&mut |src_addr, dst_addr, protocol, payload| {
let src_addr =
match src_addr {
&InternetAddress::Ipv4(_) if src_addr.is_unspecified() => {
let mut assigned_addr = None;
for addr in src_protocol_addrs {
match addr {
addr @ &InternetAddress::Ipv4(_) => {
assigned_addr = Some(addr);
break
}
},
_ => unreachable!()
};
ip_repr.emit(&mut ip_packet, payload.len());
payload.emit(src_addr, dst_addr, ip_packet.payload_mut());

Ok(())
});

match result {
Ok(()) => break,
Err(Error::Exhausted) => continue,
Err(e) => return Err(e)
}
_ => ()
}
}
assigned_addr.expect(
"to respond to an UDP packet without a source address,\
the interface must have an assigned address from \
the same family")
},
addr => addr
};

let ip_repr =
match (src_addr, dst_addr) {
(&InternetAddress::Ipv4(src_addr),
&InternetAddress::Ipv4(dst_addr)) => {
Ipv4Repr {
src_addr: src_addr,
dst_addr: dst_addr,
protocol: protocol
}
},
_ => unreachable!()
};

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(())
});

match result {
Ok(()) => {
nothing_to_transmit = false;
break
}
Err(Error::Exhausted) => continue,
Err(e) => return Err(e)
}
}

Ok(())
Ok(nothing_to_transmit)
}
}

3 changes: 2 additions & 1 deletion src/phy/raw_socket.rs
Original file line number Diff line number Diff line change
@@ -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)
}

3 changes: 2 additions & 1 deletion src/phy/tap_interface.rs
Original file line number Diff line number Diff line change
@@ -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)
}

4 changes: 2 additions & 2 deletions src/socket/mod.rs
Original file line number Diff line number Diff line change
@@ -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]);
4 changes: 2 additions & 2 deletions src/socket/udp.rs
Original file line number Diff line number Diff line change
@@ -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]) {
8 changes: 8 additions & 0 deletions src/wire/arp.rs
Original file line number Diff line number Diff line change
@@ -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 {
10 changes: 10 additions & 0 deletions src/wire/ethernet.rs
Original file line number Diff line number Diff line change
@@ -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 {
12 changes: 7 additions & 5 deletions src/wire/icmpv4.rs
Original file line number Diff line number Diff line change
@@ -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!()
}
}
6 changes: 6 additions & 0 deletions src/wire/ipv4.rs
Original file line number Diff line number Diff line change
@@ -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) {
2 changes: 1 addition & 1 deletion src/wire/udp.rs
Original file line number Diff line number Diff line change
@@ -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()
}