Skip to content

Commit

Permalink
Merge #469
Browse files Browse the repository at this point in the history
469: Add IEEE 802.15.4/6LoWPAN support r=Dirbaio a=thibautvdv

This adds the IEEE 802.15.4 frame representation.
Still a work in progress and interested to know what you think about this.

I really would like to add 6LowPAN as well, however I'm not sure where to put this in smoltcp, since 6LowPAN is kind of weird.

Co-authored-by: Thibaut Vandervelden <thvdveld@vub.be>
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
  • Loading branch information
3 people authored Oct 20, 2021
2 parents 5dbfc42 + bc2934d commit c8141bb
Show file tree
Hide file tree
Showing 36 changed files with 3,769 additions and 259 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:

features:
# These feature sets cannot run tests, so we only check they build.
- rand-custom-impl medium-ip medium-ethernet proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async
- rand-custom-impl medium-ip medium-ethernet medium-ieee802154 proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async
- rand-custom-impl defmt defmt-trace medium-ip medium-ethernet proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async

steps:
Expand Down
16 changes: 13 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,24 @@ verbose = []
rand-custom-impl = []
"medium-ethernet" = ["socket"]
"medium-ip" = ["socket"]
"phy-raw_socket" = ["std", "libc", "medium-ethernet"]
"medium-ieee802154" = ["socket", "proto-sixlowpan"]

"phy-raw_socket" = ["std", "libc"]
"phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]

"proto-ipv4" = []
"proto-igmp" = ["proto-ipv4"]
"proto-dhcpv4" = ["proto-ipv4"]
"proto-ipv6" = []
"proto-sixlowpan" = ["proto-ipv6"]

"socket" = []
"socket-raw" = ["socket"]
"socket-udp" = ["socket"]
"socket-tcp" = ["socket"]
"socket-icmp" = ["socket"]
"socket-dhcpv4" = ["socket", "medium-ethernet", "proto-dhcpv4"]

"async" = []

defmt-trace = []
Expand All @@ -59,9 +65,9 @@ defmt-error = []

default = [
"std", "log", # needed for `cargo test --no-default-features --features default` :/
"medium-ethernet", "medium-ip",
"medium-ethernet", "medium-ip", "medium-ieee802154",
"phy-raw_socket", "phy-tuntap_interface",
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6",
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6", "proto-sixlowpan",
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dhcpv4",
"async"
]
Expand Down Expand Up @@ -110,5 +116,9 @@ required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interfac
name = "dhcp_client"
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "proto-dhcpv4", "socket-raw"]

[[example]]
name = "sixlowpan"
required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "socket-udp"]

[profile.release]
debug = 2
2 changes: 1 addition & 1 deletion examples/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ fn main() {
let mut builder = InterfaceBuilder::new(device).ip_addrs(ip_addrs);
if medium == Medium::Ethernet {
builder = builder
.ethernet_addr(ethernet_addr)
.hardware_addr(ethernet_addr.into())
.neighbor_cache(neighbor_cache);
}
let mut iface = builder.finalize();
Expand Down
2 changes: 1 addition & 1 deletion examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn main() {
.routes(routes);
if medium == Medium::Ethernet {
builder = builder
.ethernet_addr(ethernet_addr)
.hardware_addr(ethernet_addr.into())
.neighbor_cache(neighbor_cache);
}
let mut iface = builder.finalize();
Expand Down
2 changes: 1 addition & 1 deletion examples/dhcp_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn main() {
.routes(routes);
if medium == Medium::Ethernet {
builder = builder
.ethernet_addr(ethernet_addr)
.hardware_addr(ethernet_addr.into())
.neighbor_cache(neighbor_cache);
}
let mut iface = builder.finalize();
Expand Down
2 changes: 1 addition & 1 deletion examples/httpclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn main() {
.routes(routes);
if medium == Medium::Ethernet {
builder = builder
.ethernet_addr(ethernet_addr)
.hardware_addr(ethernet_addr.into())
.neighbor_cache(neighbor_cache);
}
let mut iface = builder.finalize();
Expand Down
2 changes: 1 addition & 1 deletion examples/loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ fn main() {

let mut ip_addrs = [IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)];
let mut iface = InterfaceBuilder::new(device)
.ethernet_addr(EthernetAddress::default())
.hardware_addr(EthernetAddress::default().into())
.neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs)
.finalize();
Expand Down
2 changes: 1 addition & 1 deletion examples/multicast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn main() {
let ip_addr = IpCidr::new(IpAddress::from(local_addr), 24);
let mut ipv4_multicast_storage = [None; 1];
let mut iface = InterfaceBuilder::new(device)
.ethernet_addr(ethernet_addr)
.hardware_addr(ethernet_addr.into())
.neighbor_cache(neighbor_cache)
.ip_addrs([ip_addr])
.ipv4_multicast_groups(&mut ipv4_multicast_storage[..])
Expand Down
2 changes: 1 addition & 1 deletion examples/ping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fn main() {
.routes(routes);
if medium == Medium::Ethernet {
builder = builder
.ethernet_addr(ethernet_addr)
.hardware_addr(ethernet_addr.into())
.neighbor_cache(neighbor_cache);
}
let mut iface = builder.finalize();
Expand Down
2 changes: 1 addition & 1 deletion examples/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fn main() {
let mut builder = InterfaceBuilder::new(device).ip_addrs(ip_addrs);
if medium == Medium::Ethernet {
builder = builder
.ethernet_addr(ethernet_addr)
.hardware_addr(ethernet_addr.into())
.neighbor_cache(neighbor_cache);
}
let mut iface = builder.finalize();
Expand Down
134 changes: 134 additions & 0 deletions examples/sixlowpan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
//! 6lowpan exmaple
//!
//! This example is designed to run using the Linux ieee802154/6lowpan support,
//! using mac802154_hwsim.
//!
//! mac802154_hwsim allows you to create multiple "virtual" radios and specify
//! which is in range with which. This is very useful for testing without
//! needing real hardware. By default it creates two interfaces `wpan0` and
//! `wpan1` that are in range with each other. You can customize this with
//! the `wpan-hwsim` tool.
//!
//! We'll configure Linux to speak 6lowpan on `wpan0`, and leave `wpan1`
//! unconfigured so smoltcp can use it with a raw socket.
//!
//! # Setup
//!
//! modprobe mac802154_hwsim
//!
//! ip link set wpan0 down
//! ip link set wpan1 down
//! iwpan dev wpan0 set pan_id 0xbeef
//! iwpan dev wpan1 set pan_id 0xbeef
//! ip link add link wpan0 name lowpan0 type lowpan
//! ip link set wpan0 up
//! ip link set wpan1 up
//! ip link set lowpan0 up
//!
//! # Running
//!
//! Run it with `sudo ./target/debug/examples/sixlowpan`.
//!
//! You can set wireshark to sniff on interface `wpan0` to see the packets.
//!
//! Ping it with `ping fe80::180b:4242:4242:4242%lowpan0`.
//!
//! Speak UDP with `nc -uv fe80::180b:4242:4242:4242%lowpan0 6969`.
//!
//! # Teardown
//!
//! rmmod mac802154_hwsim
//!

mod utils;

use log::debug;
use std::collections::BTreeMap;
use std::os::unix::io::AsRawFd;
use std::str;

use smoltcp::iface::{InterfaceBuilder, NeighborCache};
use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
use smoltcp::socket::SocketSet;
use smoltcp::socket::{UdpPacketMetadata, UdpSocket, UdpSocketBuffer};
use smoltcp::time::Instant;
use smoltcp::wire::{Ieee802154Pan, IpAddress, IpCidr};

fn main() {
utils::setup_logging("");

let (mut opts, mut free) = utils::create_options();
utils::add_middleware_options(&mut opts, &mut free);

let mut matches = utils::parse_options(&opts, free);

let device = RawSocket::new("wpan1", Medium::Ieee802154).unwrap();

let fd = device.as_raw_fd();
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);

let neighbor_cache = NeighborCache::new(BTreeMap::new());

let udp_rx_buffer = UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; 64]);
let udp_tx_buffer = UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; 128]);
let udp_socket = UdpSocket::new(udp_rx_buffer, udp_tx_buffer);

let ieee802154_addr = smoltcp::wire::Ieee802154Address::Extended([
0x1a, 0x0b, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
]);
let ip_addrs = [IpCidr::new(
IpAddress::v6(0xfe80, 0, 0, 0, 0x180b, 0x4242, 0x4242, 0x4242),
64,
)];

let mut builder = InterfaceBuilder::new(device)
.ip_addrs(ip_addrs)
.pan_id(Ieee802154Pan(0xbeef));
builder = builder
.hardware_addr(ieee802154_addr.into())
.neighbor_cache(neighbor_cache);
let mut iface = builder.finalize();

let mut sockets = SocketSet::new(vec![]);
let udp_handle = sockets.add(udp_socket);

loop {
let timestamp = Instant::now();
match iface.poll(&mut sockets, timestamp) {
Ok(_) => {}
Err(e) => {
debug!("poll error: {}", e);
}
}

// udp:6969: respond "hello"
{
let mut socket = sockets.get::<UdpSocket>(udp_handle);
if !socket.is_open() {
socket.bind(6969).unwrap()
}

let client = match socket.recv() {
Ok((data, endpoint)) => {
debug!(
"udp:6969 recv data: {:?} from {}",
str::from_utf8(data).unwrap(),
endpoint
);
Some(endpoint)
}
Err(_) => None,
};
if let Some(endpoint) = client {
let data = b"hello\n";
debug!(
"udp:6969 send data: {:?}",
str::from_utf8(data.as_ref()).unwrap()
);
socket.send_slice(data, endpoint).unwrap();
}
}

phy_wait(fd, iface.poll_delay(&sockets, timestamp)).expect("wait error");
}
}
2 changes: 1 addition & 1 deletion examples/tcpdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::os::unix::io::AsRawFd;

fn main() {
let ifname = env::args().nth(1).unwrap();
let mut socket = RawSocket::new(ifname.as_ref()).unwrap();
let mut socket = RawSocket::new(ifname.as_ref(), smoltcp::phy::Medium::Ethernet).unwrap();
loop {
phy_wait(socket.as_raw_fd(), None).unwrap();
let (rx_token, _) = socket.receive().unwrap();
Expand Down
6 changes: 0 additions & 6 deletions examples/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use std::process;
use std::str::{self, FromStr};
use std::time::{SystemTime, UNIX_EPOCH};

use smoltcp::phy::RawSocket;
#[cfg(feature = "phy-tuntap_interface")]
use smoltcp::phy::TunTapInterface;
use smoltcp::phy::{Device, FaultInjector, Medium, Tracer};
Expand Down Expand Up @@ -112,11 +111,6 @@ pub fn parse_tuntap_options(matches: &mut Matches) -> TunTapInterface {
}
}

pub fn parse_raw_socket_options(matches: &mut Matches) -> RawSocket {
let interface = matches.free.remove(0);
RawSocket::new(&interface).unwrap()
}

pub fn add_middleware_options(opts: &mut Options, _free: &mut Vec<&str>) {
opts.optopt("", "pcap", "Write a packet capture file", "FILE");
opts.optopt(
Expand Down
Loading

0 comments on commit c8141bb

Please sign in to comment.