Skip to content

Commit

Permalink
Start working in Interface
Browse files Browse the repository at this point in the history
  • Loading branch information
thvdveld committed May 25, 2021
1 parent 73b8cff commit 007d0cd
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 5 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Expand Up @@ -35,7 +35,7 @@ alloc = ["managed/alloc"]
verbose = []
"medium-ethernet" = ["socket"]
"medium-ip" = ["socket"]
"medium-sixlowpan" = ["socket", "sixlowpan"]
"medium-sixlowpan" = ["socket", "sixlowpan", "proto-sixlowpan"]
"phy-raw_socket" = ["std", "libc", "medium-ethernet"]
"phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
"ieee802154" = []
Expand All @@ -44,6 +44,7 @@ verbose = []
"proto-igmp" = ["proto-ipv4"]
"proto-dhcpv4" = ["proto-ipv4", "socket-raw", "medium-ethernet"]
"proto-ipv6" = []
"proto-sixlowpan" = []
"socket" = []
"socket-raw" = ["socket"]
"socket-udp" = ["socket"]
Expand Down
140 changes: 138 additions & 2 deletions src/iface/interface.rs
Expand Up @@ -36,6 +36,8 @@ struct InterfaceInner<'a> {
neighbor_cache: Option<NeighborCache<'a>>,
#[cfg(feature = "medium-ethernet")]
ethernet_addr: Option<EthernetAddress>,
#[cfg(feature = "medium-sixlowpan")]
ieee802154_addr: Option<Ieee802154Address>,
ip_addrs: ManagedSlice<'a, IpCidr>,
#[cfg(feature = "proto-ipv4")]
any_ip: bool,
Expand All @@ -55,6 +57,8 @@ pub struct InterfaceBuilder <'a, DeviceT: for<'d> Device<'d>> {
ethernet_addr: Option<EthernetAddress>,
#[cfg(feature = "medium-ethernet")]
neighbor_cache: Option<NeighborCache<'a>>,
#[cfg(feature = "medium-sixlowpan")]
ieee802154_addr: Option<Ieee802154Address>,
ip_addrs: ManagedSlice<'a, IpCidr>,
#[cfg(feature = "proto-ipv4")]
any_ip: bool,
Expand Down Expand Up @@ -99,6 +103,8 @@ let iface = InterfaceBuilder::new(device)
ethernet_addr: None,
#[cfg(feature = "medium-ethernet")]
neighbor_cache: None,
#[cfg(feature = "medium-sixlowpan")]
ieee802154_addr: None,
ip_addrs: ManagedSlice::Borrowed(&mut []),
#[cfg(feature = "proto-ipv4")]
any_ip: false,
Expand Down Expand Up @@ -219,20 +225,27 @@ let iface = InterfaceBuilder::new(device)
assert!(self.neighbor_cache.is_none(), "neighbor_cache is set, but device medium is IP");
(None, None)
}
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => {
assert!(self.ieee802154_addr.is_some(), "ieee802154_addr required option was not set");
(None, None)
}
};

Interface {
device: self.device,
inner: InterfaceInner {
#[cfg(feature = "medium-ethernet")]
ethernet_addr,
#[cfg(feature = "medium-sixlowpan")]
ieee802154_addr: self.ieee802154_addr,
ip_addrs: self.ip_addrs,
#[cfg(feature = "proto-ipv4")]
any_ip: self.any_ip,
routes: self.routes,
device_capabilities,
#[cfg(feature = "medium-ethernet")]
neighbor_cache,
neighbor_cache: self.neighbor_cache,
#[cfg(feature = "proto-igmp")]
ipv4_multicast_groups: self.ipv4_multicast_groups,
#[cfg(feature = "proto-igmp")]
Expand Down Expand Up @@ -630,6 +643,24 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
}
})
}
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => {
inner.process_sixlowpan(sockets, timestamp, &frame).map_err(|err| {
net_debug!("cannot process ingress packet: {}", err);
err
}).and_then(|response| {
processed_any = true;
match response {
Some(packet) => {
inner.dispatch_ip(tx_token, timestamp, packet).map_err(|err| {
net_debug!("cannot dispatch response packet: {}", err);
err
})
}
None => Ok(())
}
})
}
}
})?;
}
Expand Down Expand Up @@ -690,6 +721,8 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
Medium::Ethernet => _caps.max_transmission_unit - EthernetFrame::<&[u8]>::header_len(),
#[cfg(feature = "medium-ip")]
Medium::Ip => _caps.max_transmission_unit,
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => todo!(),
};
socket.dispatch(timestamp, ip_mtu, |response|
respond!(IpPacket::Tcp(response)))
Expand Down Expand Up @@ -909,6 +942,81 @@ impl<'a> InterfaceInner<'a> {
}
}


#[cfg(feature = "medium-sixlowpan")]
fn process_sixlowpan<'frame, T: AsRef<[u8]> + ?Sized>
(&mut self, sockets: &mut SocketSet, timestamp: Instant, sixlowpan_payload: &'frame T) ->
Result<Option<IpPacket<'frame>>>
{
let ieee802154_frame = Ieee802154Frame::new_checked(sixlowpan_payload)?;
let ieee802154_repr = Ieee802154Repr::parse(&ieee802154_frame)?;

match ieee802154_repr.payload {
Some(payload) => {
// The first header needs to be an IPHC header.
let iphc_packet = SixlowpanIphcPacket::new_checked(payload)?;
let iphc_repr = SixlowpanIphcRepr::parse(&iphc_packet, ieee802154_repr.src_addr, ieee802154_repr.dst_addr)?;

if !iphc_repr.src_addr.is_unicast() {
// Discard packets with non-unicast source addresses.
net_debug!("non-unicast source address");
return Err(Error::Malformed)
}

let payload = iphc_packet.payload();
let ip_repr = IpRepr::Sixlowpan(iphc_repr);

// Currently we assume the next header is a UDP, so we mark all the rest with todo.
match iphc_repr.next_header {
SixlowpanNextHeader::Compressed => {
match SixlowpanNhcPacket::dispatch(payload)? {
SixlowpanNhcPacket::ExtensionHeader(ext_header) => todo!(),
SixlowpanNhcPacket::UdpHeader(udp_packet) => {
// Handle the UDP
let udp_repr = SixlowpanUdpRepr::parse(&udp_packet, &iphc_repr.src_addr, &iphc_repr.dst_addr, udp_packet.checksum())?;

// Look for UDP sockets that will accept the UDP packet.
// If it does not accept the packet, then send an ICMP message.
for mut udp_socket in sockets.iter_mut().filter_map(UdpSocket::downcast) {
if !udp_socket.accepts(&ip_repr, &udp_repr) { continue; }

match udp_socket.process(&ip_repr, &udp_repr) {
Ok(()) => return Ok(None),
Err(e) => return Err(e),
}
}

// The packet wasn't handled by a socket, send an ICMP port unreachable packet.
match ip_repr {
#[cfg(feature = "proto-ipv6")]
IpRepr::Ipv6(ipv6_repr) => {
let payload_len = icmp_reply_payload_len(payload.len(), IPV6_MIN_MTU,
ipv6_repr.buffer_len());
let icmpv6_reply_repr = Icmpv6Repr::DstUnreachable {
reason: Icmpv6DstUnreachable::PortUnreachable,
header: ipv6_repr,
data: &payload[0..payload_len]
};
Ok(self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr))
},
IpRepr::Unspecified { .. } => Err(Error::Unaddressable),
_ => unreachable!(),
}
}
}
}
SixlowpanNextHeader::Uncompressed(nxt_hdr) => {
match nxt_hdr {
IpProtocol::Icmpv6 => self.process_icmpv6(sockets, timestamp, ip_repr, iphc_packet.payload()),
hdr => todo!("{:?}", hdr),
}
}
}
}
None => Ok(None)
}
}

#[cfg(all(feature = "medium-ethernet", feature = "proto-ipv4"))]
fn process_arp<'frame, T: AsRef<[u8]>>
(&mut self, timestamp: Instant, eth_frame: &EthernetFrame<&'frame T>) ->
Expand Down Expand Up @@ -1481,6 +1589,25 @@ impl<'a> InterfaceInner<'a> {
};
Ok(self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr))
},
#[cfg(feature = "sixlowpan")]
IpRepr::Sixlowpan(sixlowpan_repr) => {
let ipv6_repr = Ipv6Repr {
src_addr: sixlowpan_repr.src_addr,
dst_addr: sixlowpan_repr.dst_addr,
next_header: IpProtocol::Udp, // XXX
payload_len: ip_payload.len(),
hop_limit: sixlowpan_repr.hop_limit,
};

let payload_len = icmp_reply_payload_len(ip_payload.len(), IPV6_MIN_MTU,
sixlowpan_repr.buffer_len());
let icmpv6_reply_repr = Icmpv6Repr::DstUnreachable {
reason: Icmpv6DstUnreachable::PortUnreachable,
header: ipv6_repr,
data: &ip_payload[0..payload_len]
};
Ok(self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr))
}
IpRepr::Unspecified { .. } => Err(Error::Unaddressable),
}
}
Expand Down Expand Up @@ -1589,6 +1716,8 @@ impl<'a> InterfaceInner<'a> {
.found(),
#[cfg(feature = "medium-ip")]
Medium::Ip => true,
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => todo!(),
}
}
Err(_) => false
Expand Down Expand Up @@ -1732,6 +1861,11 @@ impl<'a> InterfaceInner<'a> {
Ok(())
})
}
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => {
// Conver the packet to a LOWPAN compatible packet.
todo!();
}
}
}

Expand Down Expand Up @@ -2627,7 +2761,9 @@ mod test {
Ipv4Packet::new_checked(eth_frame.payload()).ok()?
}
#[cfg(feature = "medium-ip")]
Medium::Ip => Ipv4Packet::new_checked(&frame[..]).ok()?
Medium::Ip => Ipv4Packet::new_checked(&frame[..]).ok()?,
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => todo!(),
};
let ipv4_repr = Ipv4Repr::parse(&ipv4_packet, &checksum_caps).ok()?;
let ip_payload = ipv4_packet.payload();
Expand Down
4 changes: 2 additions & 2 deletions src/iface/mod.rs
Expand Up @@ -7,7 +7,7 @@ provides lookup and caching of hardware addresses, and handles management packet
#[cfg(feature = "medium-ethernet")]
mod neighbor;
mod route;
#[cfg(any(feature = "medium-ethernet", feature = "medium-ip"))]
#[cfg(any(feature = "medium-ethernet", feature = "medium-ip", feature = "medium-sixlowpan"))]
mod interface;

#[cfg(feature = "medium-ethernet")]
Expand All @@ -18,5 +18,5 @@ pub(crate) use self::neighbor::Answer as NeighborAnswer;
pub use self::neighbor::Cache as NeighborCache;
pub use self::route::{Route, Routes};

#[cfg(any(feature = "medium-ethernet", feature = "medium-ip"))]
#[cfg(any(feature = "medium-ethernet", feature = "medium-ip", feature = "medium-sixlowpan"))]
pub use self::interface::{Interface, InterfaceBuilder};
9 changes: 9 additions & 0 deletions src/phy/mod.rs
Expand Up @@ -247,6 +247,13 @@ pub enum Medium {
/// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
#[cfg(feature = "medium-ip")]
Ip,

/// 6LoWPAN medium. Devices of this type send and receive IPv6 frames encoded using 6LoWPAN.
/// They are transmitted over IEEE802.15.4 or BLE.
///
/// Examples of devices of this type are found in the Internet of Things realm.
#[cfg(feature = "medium-sixlowpan")]
Sixlowpan,
}


Expand All @@ -256,6 +263,8 @@ impl Default for Medium {
return Medium::Ethernet;
#[cfg(all(feature = "medium-ip", not(feature = "medium-ethernet")))]
return Medium::Ip;
#[cfg(feature = "medium-sixlowpan")]
return Medium::Sixlowpan;
#[cfg(all(not(feature = "medium-ip"), not(feature = "medium-ethernet")))]
panic!("No medium enabled");
}
Expand Down
2 changes: 2 additions & 0 deletions src/phy/pcap_writer.rs
Expand Up @@ -138,6 +138,8 @@ impl<D: for<'a> Device<'a>, S: PcapSink + Clone> PcapWriter<D, S> {
Medium::Ip => PcapLinkType::Ip,
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => PcapLinkType::Ethernet,
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => todo!(),
};
sink.global_header(link_type);
PcapWriter { lower, sink, mode }
Expand Down
4 changes: 4 additions & 0 deletions src/phy/sys/tuntap_interface.rs
Expand Up @@ -38,6 +38,8 @@ impl TunTapInterfaceDesc {
Medium::Ip => imp::IFF_TUN,
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => imp::IFF_TAP,
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => todo!(),
};
self.ifreq.ifr_data = mode | imp::IFF_NO_PI;
ifreq_ioctl(self.lower, &mut self.ifreq, imp::TUNSETIFF).map(|_| ())
Expand All @@ -64,6 +66,8 @@ impl TunTapInterfaceDesc {
Medium::Ip => ip_mtu,
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => ip_mtu + EthernetFrame::<&[u8]>::header_len(),
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => todo!(),
};

Ok(mtu)
Expand Down
2 changes: 2 additions & 0 deletions src/phy/tracer.rs
Expand Up @@ -135,6 +135,8 @@ impl<'a> fmt::Display for Packet<'a> {
Ok(crate::wire::IpVersion::Ipv6) => crate::wire::Ipv6Packet::<&'static [u8]>::pretty_print(&self.buffer, f, &mut indent),
_ => f.write_str("unrecognized IP version")
}
#[cfg(feature = "medium-sixlowpan")]
Medium::Sixlowpan => todo!(),
}
}
}
14 changes: 14 additions & 0 deletions src/wire/ieee802154.rs
Expand Up @@ -108,6 +108,20 @@ impl Address {
Self::Extended(a)
}

pub fn from_bytes(a: &[u8]) -> Self {
if a.len() == 2 {
let mut b = [0u8; 2];
b.copy_from_slice(a);
Address::Short(b)
} else if a.len() == 8 {
let mut b = [0u8; 8];
b.copy_from_slice(a);
Address::Extended(b)
} else {
panic!("Not an IEEE802.15.4 address");
}
}

pub fn as_bytes(&self) -> &[u8] {
match self {
Address::Absent => &[],
Expand Down

0 comments on commit 007d0cd

Please sign in to comment.