Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IEEE 802.15.4/6LoWPAN support #469

Merged
merged 23 commits into from
Oct 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3d782f1
Add support for 802.15.4 and 6LoWPAN
thvdveld Apr 29, 2021
68e25a2
Add RawHardwareAddress, use it in wire ndisc.
Dirbaio Oct 7, 2021
102db1d
wire: remove HardwareAddress::BROADCAST
Dirbaio Oct 7, 2021
4b1de11
ipv6: fix Solicited Node address calculation
Dirbaio Oct 7, 2021
cd40acb
6lowpan: do not fill neighbor cache from random packets
Dirbaio Oct 7, 2021
bdd09c4
ieee80154: process packets without the FCS.
Dirbaio Oct 7, 2021
f35e760
phy: Use right protocol on RawSocket based on the medium.
Dirbaio Oct 7, 2021
b74cd58
example/6lowpan: expand readme, do not use monitor interface.
Dirbaio Oct 7, 2021
f67f024
Use one PAN ID for source and destination
thvdveld Oct 11, 2021
7bad4cf
Use `net_debug` and drop instead of `todo!`
thvdveld Oct 11, 2021
aed9fdb
Send ICMP unreachable when no UDP socket is found
thvdveld Oct 11, 2021
3c49822
Set HardwareAddress behind feature flag
thvdveld Oct 11, 2021
2de8b7a
Defmt for RawHardwareAddress
thvdveld Oct 11, 2021
954a757
Remove some more todos
thvdveld Oct 11, 2021
0c39c50
Set flags to zero, because buffer could be reused.
thvdveld Oct 11, 2021
ddfd6f8
Remove IpRepr::Sixlowpan
thvdveld Oct 12, 2021
d8e7b7a
ieee802154: ignore frames with types other than Data
thvdveld Oct 13, 2021
0e3b668
ieee802154: Correct filtering of PAN id
thvdveld Oct 19, 2021
9fecf50
ieee802154: update documentation
thvdveld Oct 20, 2021
aeca423
ieee802154: log when we drop a frame
thvdveld Oct 20, 2021
5e7e75a
Fix some comments.
Dirbaio Oct 20, 2021
d5b2c75
Add medium-ieee802154 to CI.
Dirbaio Oct 20, 2021
bc2934d
Fix build when setting medium-ieee802154 but not proto-sixlowpan.
Dirbaio Oct 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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