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

ieee: better handle addr for new frame version #870

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions src/iface/interface/sixlowpan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ impl InterfaceInner {
decompressed_size += 2;
decompressed_size -= ext_repr.buffer_len();
next_header = Some(ext_repr.next_header);

if ext_repr.buffer_len() + ext_repr.length as usize > data.len() {
return Err(Error);
}

data = &data[ext_repr.buffer_len() + ext_repr.length as usize..];
}
SixlowpanNhcPacket::UdpHeader => {
Expand Down Expand Up @@ -283,6 +288,10 @@ impl InterfaceInner {
&ChecksumCapabilities::ignored(),
)?;

if payload.len() + 8 > buffer.len() {
return Err(Error);
}

let mut udp = UdpPacket::new_unchecked(&mut buffer[..payload.len() + 8]);
udp_repr
.0
Expand Down
221 changes: 142 additions & 79 deletions src/wire/ieee802154.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,26 @@ impl<T: AsRef<[u8]>> Frame<T> {
let packet = Self::new_unchecked(buffer);
packet.check_len()?;

if matches!(packet.dst_addressing_mode(), AddressingMode::Unknown(_)) {
// We don't handle unknown frame versions.
if matches!(packet.frame_version(), FrameVersion::Unknown(_)) {
return Err(Error);
}

if matches!(packet.src_addressing_mode(), AddressingMode::Unknown(_)) {
// We don't handle unknown addressing modes.
if matches!(packet.dst_addressing_mode(), AddressingMode::Unknown(_))
|| matches!(packet.src_addressing_mode(), AddressingMode::Unknown(_))
{
return Err(Error);
}

// We don't handle absent addressing mode with PAN ID compression for older frame versions.
if matches!(
packet.frame_version(),
FrameVersion::Ieee802154_2003 | FrameVersion::Ieee802154_2006
) && packet.pan_id_compression()
&& matches!(packet.dst_addressing_mode(), AddressingMode::Absent)
&& matches!(packet.src_addressing_mode(), AddressingMode::Absent)
{
return Err(Error);
}

Expand All @@ -295,16 +310,27 @@ impl<T: AsRef<[u8]>> Frame<T> {
return Err(Error);
}

let mut offset = field::ADDRESSING.start + 2;

// Calculate the size of the addressing field.
offset += self.dst_addressing_mode().size();
offset += self.src_addressing_mode().size();

if !self.pan_id_compression() {
offset += 2;
// We don't handle frames with a payload larger than 127 bytes.
if self.buffer.as_ref().len() > 127 {
return Err(Error);
}

let mut offset = field::ADDRESSING.start
+ if let Some((dst_pan_id, dst_addr, src_pan_id, src_addr)) = self.addr_present_flags()
{
let mut offset = if dst_pan_id { 2 } else { 0 };
offset += dst_addr.size();
offset += if src_pan_id { 2 } else { 0 };
offset += src_addr.size();

if offset > self.buffer.as_ref().len() {
return Err(Error);
}
offset
} else {
0
};

if self.security_enabled() {
// First check that we can access the security header control bits.
if offset + 1 > self.buffer.as_ref().len() {
Expand Down Expand Up @@ -402,103 +428,140 @@ impl<T: AsRef<[u8]>> Frame<T> {
| FrameType::Unknown(_) => return None,
}

let mut offset = 2;

// Calculate the size of the addressing field.
offset += self.dst_addressing_mode().size();
offset += self.src_addressing_mode().size();
if let Some((dst_pan_id, dst_addr, src_pan_id, src_addr)) = self.addr_present_flags() {
let mut offset = if dst_pan_id { 2 } else { 0 };
offset += dst_addr.size();
offset += if src_pan_id { 2 } else { 0 };
offset += src_addr.size();

if !self.pan_id_compression() {
offset += 2;
let data = self.buffer.as_ref();
Some(&data[field::ADDRESSING][..offset])
} else {
None
}
}

fn addr_present_flags(&self) -> Option<(bool, AddressingMode, bool, AddressingMode)> {
let dst_addr_mode = self.dst_addressing_mode();
let src_addr_mode = self.src_addressing_mode();
let pan_id_compression = self.pan_id_compression();

Some(&self.buffer.as_ref()[field::ADDRESSING][..offset])
use AddressingMode::*;
match self.frame_version() {
FrameVersion::Ieee802154_2003 | FrameVersion::Ieee802154_2006 => {
match (dst_addr_mode, src_addr_mode) {
(Absent, src) => Some((false, Absent, true, src)),
(dst, Absent) => Some((true, dst, false, Absent)),

(dst, src) if pan_id_compression => Some((true, dst, false, src)),
(dst, src) if !pan_id_compression => Some((true, dst, true, src)),
_ => None,
}
}
FrameVersion::Ieee802154 => {
Some(match (dst_addr_mode, src_addr_mode, pan_id_compression) {
(Absent, Absent, false) => (false, Absent, false, Absent),
(Absent, Absent, true) => (true, Absent, false, Absent),
(dst, Absent, false) if !matches!(dst, Absent) => (true, dst, false, Absent),
(dst, Absent, true) if !matches!(dst, Absent) => (false, dst, false, Absent),
(Absent, src, false) if !matches!(src, Absent) => (false, Absent, true, src),
(Absent, src, true) if !matches!(src, Absent) => (false, Absent, true, src),
(Extended, Extended, false) => (true, Extended, false, Extended),
(Extended, Extended, true) => (false, Extended, false, Extended),
(Short, Short, false) => (true, Short, true, Short),
(Short, Extended, false) => (true, Short, true, Extended),
(Extended, Short, false) => (true, Extended, true, Short),
(Short, Extended, true) => (true, Short, false, Extended),
(Extended, Short, true) => (true, Extended, false, Short),
(Short, Short, true) => (true, Short, false, Short),
_ => return None,
})
}
_ => None,
}
}

/// Return the destination PAN field.
#[inline]
pub fn dst_pan_id(&self) -> Option<Pan> {
let addressing_fields = self.addressing_fields()?;
match self.dst_addressing_mode() {
AddressingMode::Absent => None,
AddressingMode::Short | AddressingMode::Extended => {
Some(Pan(LittleEndian::read_u16(&addressing_fields[0..2])))
}
AddressingMode::Unknown(_) => None,
if let Some((true, _, _, _)) = self.addr_present_flags() {
let addressing_fields = self.addressing_fields()?;
Some(Pan(LittleEndian::read_u16(&addressing_fields[..2])))
} else {
None
}
}

/// Return the destination address field.
#[inline]
pub fn dst_addr(&self) -> Option<Address> {
let addressing_fields = self.addressing_fields()?;
match self.dst_addressing_mode() {
AddressingMode::Absent => Some(Address::Absent),
AddressingMode::Short => {
let mut raw = [0u8; 2];
raw.clone_from_slice(&addressing_fields[2..4]);
raw.reverse();
Some(Address::short_from_bytes(raw))
}
AddressingMode::Extended => {
let mut raw = [0u8; 8];
raw.clone_from_slice(&addressing_fields[2..10]);
raw.reverse();
Some(Address::extended_from_bytes(raw))
if let Some((dst_pan_id, dst_addr, _, _)) = self.addr_present_flags() {
let addressing_fields = self.addressing_fields()?;
let offset = if dst_pan_id { 2 } else { 0 };

match dst_addr {
AddressingMode::Absent => Some(Address::Absent),
AddressingMode::Short => {
let mut raw = [0u8; 2];
raw.clone_from_slice(&addressing_fields[offset..offset + 2]);
raw.reverse();
Some(Address::short_from_bytes(raw))
}
AddressingMode::Extended => {
let mut raw = [0u8; 8];
raw.clone_from_slice(&addressing_fields[offset..offset + 8]);
raw.reverse();
Some(Address::extended_from_bytes(raw))
}
AddressingMode::Unknown(_) => None,
}
AddressingMode::Unknown(_) => None,
} else {
None
}
}

/// Return the destination PAN field.
#[inline]
pub fn src_pan_id(&self) -> Option<Pan> {
if self.pan_id_compression() {
return None;
}

let addressing_fields = self.addressing_fields()?;
let offset = self.dst_addressing_mode().size() + 2;

match self.src_addressing_mode() {
AddressingMode::Absent => None,
AddressingMode::Short | AddressingMode::Extended => Some(Pan(LittleEndian::read_u16(
&addressing_fields[offset..offset + 2],
))),
AddressingMode::Unknown(_) => None,
if let Some((dst_pan_id, dst_addr, true, _)) = self.addr_present_flags() {
let mut offset = if dst_pan_id { 2 } else { 0 };
offset += dst_addr.size();
let addressing_fields = self.addressing_fields()?;
Some(Pan(LittleEndian::read_u16(
&addressing_fields[offset..][..2],
)))
} else {
None
}
}

/// Return the source address field.
#[inline]
pub fn src_addr(&self) -> Option<Address> {
let addressing_fields = self.addressing_fields()?;
let mut offset = match self.dst_addressing_mode() {
AddressingMode::Absent => 0,
AddressingMode::Short => 2,
AddressingMode::Extended => 8,
_ => return None, // TODO(thvdveld): what do we do here?
} + 2;

if !self.pan_id_compression() {
offset += 2;
}

match self.src_addressing_mode() {
AddressingMode::Absent => Some(Address::Absent),
AddressingMode::Short => {
let mut raw = [0u8; 2];
raw.clone_from_slice(&addressing_fields[offset..offset + 2]);
raw.reverse();
Some(Address::short_from_bytes(raw))
}
AddressingMode::Extended => {
let mut raw = [0u8; 8];
raw.clone_from_slice(&addressing_fields[offset..offset + 8]);
raw.reverse();
Some(Address::extended_from_bytes(raw))
if let Some((dst_pan_id, dst_addr, src_pan_id, src_addr)) = self.addr_present_flags() {
let addressing_fields = self.addressing_fields()?;
let mut offset = if dst_pan_id { 2 } else { 0 };
offset += dst_addr.size();
offset += if src_pan_id { 2 } else { 0 };

match src_addr {
AddressingMode::Absent => Some(Address::Absent),
AddressingMode::Short => {
let mut raw = [0u8; 2];
raw.clone_from_slice(&addressing_fields[offset..offset + 2]);
raw.reverse();
Some(Address::short_from_bytes(raw))
}
AddressingMode::Extended => {
let mut raw = [0u8; 8];
raw.clone_from_slice(&addressing_fields[offset..offset + 8]);
raw.reverse();
Some(Address::extended_from_bytes(raw))
}
AddressingMode::Unknown(_) => None,
}
AddressingMode::Unknown(_) => None,
} else {
None
}
}

Expand Down
Loading