use crate::MacAddress;
const OUI_SUBTABLE: &str = "Ieee Registration Authority";
const OUI_VIRTUAL: [&'static str; 6] = [
"VMware",
"QEMU virtual NIC",
"Bochs virtual NIC",
"PearPC virtual NIC",
"Cooperative Linux virtual NIC",
"Oracle VirtualBox virtual NIC",
];
pub struct OuiDb {
pub(crate) names: &'static str,
pub(crate) oui_24: &'static OuiTable<3>,
pub(crate) oui_28: &'static [OuiSubtable<u8>],
pub(crate) oui_36: &'static [OuiSubtable<u16>],
}
type OuiLoc = u32;
pub(crate) struct OuiTable<const N: usize> {
pub(crate) prefix: &'static [[u8; N]],
pub(crate) loc: &'static [OuiLoc],
}
pub(crate) struct OuiSubtable<T: 'static> {
pub(crate) prefix: &'static [T],
pub(crate) loc: &'static [OuiLoc],
}
impl OuiDb {
pub fn is_virtual_nic(name: &str) -> bool {
OUI_VIRTUAL.contains(&name)
}
pub fn oui_subtable_name() -> &'static str {
OUI_SUBTABLE
}
pub fn lookup_mac(&self, mac: MacAddress) -> Option<&'static str> {
self.lookup(mac.octets())
}
pub fn lookup(&self, mac: [u8; 6]) -> Option<&'static str> {
let key3 = [mac[0], mac[1], mac[2]];
let idx = match self.oui_24.prefix.binary_search(&key3) {
Ok(idx) => idx,
Err(_) => return None,
};
let loc = self.oui_24.loc[idx];
match (loc >> 30) & 0x03 {
0 => {
let offset = ((loc >> 8) & 0x3FFFFF) as usize;
let length = (loc & 0xFF) as usize;
self.names.get(offset..offset + length)
}
1 => {
let sub_idx = (loc & 0xFFFF) as usize;
let key4 = mac[3] & 0xF0;
self.lookup_subtable(&self.oui_28[sub_idx], key4)
}
2 => {
let sub_idx = (loc & 0xFFFF) as usize;
let key5 = ((mac[3] as u16) << 8) | ((mac[4] & 0xF0) as u16);
self.lookup_subtable(&self.oui_36[sub_idx], key5)
}
_ => None,
}
}
fn lookup_subtable<T: Ord + Copy>(
&self,
subtable: &OuiSubtable<T>,
key: T,
) -> Option<&'static str> {
let idx = match subtable.prefix.binary_search(&key) {
Ok(idx) => idx,
Err(_) => return None,
};
let loc = subtable.loc[idx];
let offset = ((loc >> 8) & 0x3FFFFF) as usize;
let length = (loc & 0xFF) as usize;
self.names.get(offset..offset + length)
}
}