This commit is contained in:
John Goerzen 2020-09-24 23:06:33 -05:00
parent d0019d718e
commit a7feabb93b

View File

@ -29,10 +29,9 @@ use crossbeam_channel;
use etherparse::*; use etherparse::*;
use log::*; use log::*;
use std::convert::TryInto; use std::convert::TryInto;
use std::collections::HashMap;
use std::io; use std::io;
use std::io::{Read, Write}; use std::sync::{Arc, Mutex};
use std::mem::drop;
use std::sync::Arc;
use ifstructs::ifreq; use ifstructs::ifreq;
use libc; use libc;
@ -46,6 +45,12 @@ pub struct XBTap {
pub myethermacstr: String, pub myethermacstr: String,
pub name: String, pub name: String,
pub tap: Arc<Iface>, pub tap: Arc<Iface>,
/** We can't just blindly generate destination MACs because there is a bug
in the firmware that causes the radio to lock up if we send too many
packets to a MAC that's not online. So, we keep a translation map of
MACs we've seen. */
pub dests: Arc<Mutex<HashMap<[u8; 6], u64>>>,
} }
impl XBTap { impl XBTap {
@ -82,14 +87,17 @@ impl XBTap {
myxbmac myxbmac
); );
let name = String::from(tap.name()); let mut desthm = HashMap::new();
desthm.insert(ETHER_BROADCAST, XB_BROADCAST);
Ok(XBTap { Ok(XBTap {
myxbmac, myxbmac,
myethermac, myethermac,
myethermacstr, myethermacstr,
name, name: String::from(name),
tap: Arc::new(tap), tap: Arc::new(tap),
dests: Arc::new(Mutex::new(desthm)),
}) })
} }
@ -109,30 +117,30 @@ impl XBTap {
} }
Ok(packet) => { Ok(packet) => {
if let Some(LinkSlice::Ethernet2(header)) = packet.link { if let Some(LinkSlice::Ethernet2(header)) = packet.link {
trace!("TAPIN: Packet is {} -> {}", hex::encode(header.source()), hex::encode(header.destination()));
if header.source() != &self.myethermac { if header.source() != &self.myethermac {
warn!("Packet from tap with MAC address {} mismatches my own MAC address of {}; proceeding anyway", warn!("Packet from tap with MAC address {} mismatches my own MAC address of {}; proceeding anyway",
showmac(header.source().try_into().unwrap()), self.myethermacstr); showmac(header.source().try_into().unwrap()), self.myethermacstr);
} }
let destxbmac = if header.destination() == ETHER_BROADCAST { match self.dests.lock().unwrap().get(header.destination()) {
XB_BROADCAST None =>
} else { warn!("Destination MAC address unknown; discarding packet"),
mac48to64(header.destination().try_into().unwrap(), self.myxbmac) Some(destxbmac) =>
}; {
trace!("TAPIN: Packet is {} -> {}", hex::encode(header.source()), hex::encode(header.destination()));
let res = let res =
sender sender
.try_send(XBTX::TXData( .try_send(XBTX::TXData(
XBDestAddr::U64(destxbmac), XBDestAddr::U64(*destxbmac),
Bytes::copy_from_slice(tapdata), Bytes::copy_from_slice(tapdata),
)); ));
match res { match res {
Ok(()) => (), Ok(()) => (),
Err(crossbeam_channel::TrySendError::Full(_)) => Err(crossbeam_channel::TrySendError::Full(_)) =>
debug!("Dropped packet due to full TX buffer") debug!("Dropped packet due to full TX buffer"),
,
Err(e) => Err(e).unwrap(), Err(e) => Err(e).unwrap(),
} }
}
}
} else { } else {
warn!("Unable to get Ethernet2 header from tap packet; discarding"); warn!("Unable to get Ethernet2 header from tap packet; discarding");
} }
@ -145,7 +153,21 @@ impl XBTap {
xbreframer: &mut XBReframer, xbreframer: &mut XBReframer,
ser: &mut XBSerReader) -> io::Result<()> { ser: &mut XBSerReader) -> io::Result<()> {
loop { loop {
let (_fromu64, _fromu16, payload) = xbreframer.rxframe(ser); let (fromu64, _fromu16, payload) = xbreframer.rxframe(ser);
// Register the sender in our map of known MACs
match SlicedPacket::from_ethernet(&payload) {
Err(x) => {
warn!("Packet from XBee wasn't valid Ethernet; continueing anyhow: {:?}", x);
}
Ok(packet) => {
if let Some(LinkSlice::Ethernet2(header)) = packet.link {
trace!("SERIN: Packet Ethernet header is {} -> {}", hex::encode(header.source()), hex::encode(header.destination()));
self.dests.lock().unwrap().insert(header.source().try_into().unwrap(), fromu64);
}
}
}
self.tap.send(&payload)?; self.tap.send(&payload)?;
} }
} }