diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs index 0115f3a35cd0fc..50aba4b2e82350 100644 --- a/rust/kernel/net.rs +++ b/rust/kernel/net.rs @@ -9,6 +9,7 @@ use crate::{bindings, str::CStr, to_result, ARef, AlwaysRefCounted, Error, Result}; use core::{cell::UnsafeCell, ptr::NonNull}; +pub mod ethernet; #[cfg(CONFIG_NETFILTER)] pub mod filter; diff --git a/rust/kernel/net/ethernet.rs b/rust/kernel/net/ethernet.rs new file mode 100644 index 00000000000000..f1f93f95ed1ff9 --- /dev/null +++ b/rust/kernel/net/ethernet.rs @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Ethernet Module +//! +//! C headers: [`include/uapi/linux/if_ether.h`](../../../../include/uapi/linux/if_ether.h) + +use crate::bindings; + +// IEEE 802.3 Ethernet magic constants +// +// Taken from the original tree at `include/uapi/linux/if_ether.h`. + +/// Octets in one ethernet address +pub const ALEN: usize = bindings::ETH_ALEN as usize; + +/// Octets in ethernet type field +pub const TLEN: usize = bindings::ETH_TLEN as usize; + +/// Total octets in header +pub const HLEN: usize = bindings::ETH_HLEN as usize; + +/// Minimal octet count in frame without the FCS +pub const ZLEN: usize = bindings::ETH_ZLEN as usize; + +/// Maximal octet count in payload +pub const DATA_LEN: usize = bindings::ETH_DATA_LEN as usize; + +/// Maximal octet count in frame without the FCS +pub const FRAME_LEN: usize = bindings::ETH_FRAME_LEN as usize; + +/// Octets in the Frame Check Sum (FCS) +pub const FCS_LEN: usize = bindings::ETH_FCS_LEN as usize; + +/// Minimal MTU +/// +/// RFC791 fixes it to be at 68 octets for IPv4 +pub const MIN_MTU: usize = bindings::ETH_MIN_MTU as usize; + +/// Maximal MTU +pub const MAX_MTU: usize = bindings::ETH_MAX_MTU as usize; + +/// Ethernet Protocol Identifiers +/// +/// These were taken from the original tree at `include/uapi/linux/if_ether.h`. +/// Memory-wise, they are represented as machine-endian `u16`. That size is +/// convenient because it corresponds to the ethertype size in Ethernet II +/// headers. +#[derive(Copy, Clone, Debug)] +#[repr(u16)] +pub enum Proto { + /// Ethernet loopback protocol + Loop = bindings::ETH_P_LOOP as u16, + /// Xerox PUP Packet + Pup = bindings::ETH_P_PUP as u16, + /// Xexor PUP Address Transfer packet + PupAddrTrans = bindings::ETH_P_PUPAT as u16, + /// TSN (IEEE 1722) packet + Tsn = bindings::ETH_P_TSN as u16, + /// ERSPAN version 2 (type III) + Erspan2 = bindings::ETH_P_ERSPAN2 as u16, + /// Internet Protocol v4 packet + Ip = bindings::ETH_P_IP as u16, + /// CCITT X.25 + X25 = bindings::ETH_P_X25 as u16, + /// Address resolution protocol + Arp = bindings::ETH_P_ARP as u16, + /// G8BPQ AX.25 Ethernet Packet *[ NOT AN OFFICIALLY REGISTERED ID ]* + Bpq = bindings::ETH_P_BPQ as u16, + /// Xerox IEEE802.3 PUP packet + IeeePup = bindings::ETH_P_IEEEPUP as u16, + /// Xerox IEEE802.3 PUP Address Transfer packet + IeeePupAddrTrans = bindings::ETH_P_IEEEPUPAT as u16, + /// B.A.T.M.A.N. - advanced packet *[ NOT AN OFFICIALLY REGISTERED ID ]* + Batman = bindings::ETH_P_BATMAN as u16, + + /// DEC Assigned Protocol + Dec = bindings::ETH_P_DEC as u16, + /// DEC DNA Dump/Load + DNADumpLoad = bindings::ETH_P_DNA_DL as u16, + /// DEC DNA Remote Control + DNARemoteControl = bindings::ETH_P_DNA_RC as u16, + /// DEC DNA Routing + DNARouting = bindings::ETH_P_DNA_RT as u16, + /// DEC LAT + Lat = bindings::ETH_P_LAT as u16, + /// DEC Diagnostics + Diag = bindings::ETH_P_DIAG as u16, + /// DEC Customer Use + Cust = bindings::ETH_P_CUST as u16, + /// DEC Systems Comms Arch + Sca = bindings::ETH_P_SCA as u16, + + /// Trans Ethernet Bridging + Teb = bindings::ETH_P_TEB as u16, + /// Reverse Address Resolution Packet + Rarp = bindings::ETH_P_RARP as u16, + + /// Appletalk DDP + ATalk = bindings::ETH_P_ATALK as u16, + /// Appletakl AARP + AArp = bindings::ETH_P_AARP as u16, + + /// 802.1Q VLAN Extended Header + IEEE8021Q = bindings::ETH_P_8021Q as u16, + /// ERSPAN Type II + Erspan = bindings::ETH_P_ERSPAN as u16, + /// IPX over IDX + Ipx = bindings::ETH_P_IPX as u16, + /// Internet Protocol v6 + IpV6 = bindings::ETH_P_IPV6 as u16, + + /// IEEE Pause frames. See 802.3 31B + Pause = bindings::ETH_P_PAUSE as u16, + /// Slow protocol, see 802.3ad 43B + Slow = bindings::ETH_P_SLOW as u16, + + /// Web Cache Coordination Protocol + /// Defined in draft-wilson-wrec-wccp-v2-00.txt + Wccp = bindings::ETH_P_WCCP as u16, + + /// MPLS Unicast Traffic + MplsUnicast = bindings::ETH_P_MPLS_UC as u16, + /// MPLS Multicast Traffic + MplsMulticast = bindings::ETH_P_MPLS_MC as u16, + + /// Multi-Protocol over ATM + AtmMpOa = bindings::ETH_P_ATMMPOA as u16, + + /// PPPoE Discovery Message + PppDisc = bindings::ETH_P_PPP_DISC as u16, + /// PPPoE Session Messages + PppSes = bindings::ETH_P_PPP_SES as u16, + + /// HPNA, wlan link-local tunnel + LinkCtl = bindings::ETH_P_LINK_CTL as u16, + /// Frame-based ATM Transport over Ethernet + AtmFate = bindings::ETH_P_ATMFATE as u16, + /// Port Access Entity (IEEE 802.1X) + Pae = bindings::ETH_P_PAE as u16, + /// PROFINET + Profinet = bindings::ETH_P_PROFINET as u16, + /// Multiple Proprietary Protocols + Realtek = bindings::ETH_P_REALTEK as u16, + /// ATA Over Ethernet + Aoe = bindings::ETH_P_AOE as u16, + /// EtherCat + EtherCat = bindings::ETH_P_ETHERCAT as u16, + /// 802.1ad Service VLAN + _8021ad = bindings::ETH_P_8021AD as u16, + /// 802.1 Local Experimental 1 + _802Ex1 = bindings::ETH_P_802_EX1 as u16, + /// 802.11 Pre Authentication + PreAuth = bindings::ETH_P_PREAUTH as u16, + /// TIPC + Tipc = bindings::ETH_P_TIPC as u16, + /// Link Layer Discovery Protocol (LLDP) + Lldp = bindings::ETH_P_LLDP as u16, + /// Media Redundancy Protocol + Mrp = bindings::ETH_P_MRP as u16, + /// 802.1ae MACSec + MacSec = bindings::ETH_P_MACSEC as u16, + /// 802.1ah Backbone Service Tag + _8021ah = bindings::ETH_P_8021AH as u16, + /// 802.1Q Multiple Vlan Registration Protocol + Mvrp = bindings::ETH_P_MVRP as u16, + /// IEEE 1588 Timesync + _1588 = bindings::ETH_P_1588 as u16, + /// NCSI Protocol + Ncsi = bindings::ETH_P_NCSI as u16, + /// IEC 62439-3 PRP/HSRv0 + Prp = bindings::ETH_P_PRP as u16, + /// Connectivity Fault Management + Cfm = bindings::ETH_P_CFM as u16, + /// Fiber Channel over Ethernet + FcoE = bindings::ETH_P_FCOE as u16, + /// InfiniBand over Ethernet + IboE = bindings::ETH_P_IBOE as u16, + /// TDLS + Tdls = bindings::ETH_P_TDLS as u16, + /// FCoE Initialization protocol + Fip = bindings::ETH_P_FIP as u16, + /// 802.21 Media Independant Handover Protocol + _80221 = bindings::ETH_P_80221 as u16, + /// IEC 62439-3 HSRv1 + Hsr = bindings::ETH_P_HSR as u16, + /// Network Service Header + Nsh = bindings::ETH_P_NSH as u16, + /// Ethernet Loopback Packet (per IEEE 802.3) + Loopback = bindings::ETH_P_LOOPBACK as u16, + + /// Deprecated QinQ VLAN 1 [ NOT AN OFFICIALLY REGISTERED ID ] + QinQ1 = bindings::ETH_P_QINQ1 as u16, + /// Deprecated QinQ VLAN 2 [ NOT AN OFFICIALLY REGISTERED ID ] + QinQ2 = bindings::ETH_P_QINQ2 as u16, + /// Deprecated QinQ VLAN 3 [ NOT AN OFFICIALLY REGISTERED ID ] + QinQ3 = bindings::ETH_P_QINQ3 as u16, + + /// Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] + Edsa = bindings::ETH_P_EDSA as u16, + /// Fake VLAN Header Tag for DSA [ NOT AN OFFICIALLY REGISTERED ID ] + Dsa8021Q = bindings::ETH_P_DSA_8021Q as u16, + /// A5PSW Tag Value [ NOT AN OFFICIALLY REGISTERED ID ] + DsaA5Psw = bindings::ETH_P_DSA_A5PSW as u16, + /// ForCES inter-FE LFB type + Ife = bindings::ETH_P_IFE as u16, + /// IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] + AfIucv = bindings::ETH_P_AF_IUCV as u16, + /// Minimal Ethernet II protocol value + /// Any protocol value below that is 802.3 + Min8023 = bindings::ETH_P_802_3_MIN as u16, + + // Starting here it's just non DIX types. + // They won't clash for 1500 types. + /// Dummy type for 802.3 frames + _8023 = bindings::ETH_P_802_3 as u16, + /// Dummy protocol id for AX25 + Ax25 = bindings::ETH_P_AX25 as u16, + /// Every packet (be careful!) + All = bindings::ETH_P_ALL as u16, + /// 802.2 frames + _8022 = bindings::ETH_P_802_2 as u16, + /// Internal only + Snap = bindings::ETH_P_SNAP as u16, + /// DEC DDCMP: Internal Only + DDcmp = bindings::ETH_P_DDCMP as u16, + /// Dummy type for WAN PPP frames + WanPpp = bindings::ETH_P_WAN_PPP as u16, + /// Dummy type for PPP MP frames + PppMp = bindings::ETH_P_PPP_MP as u16, + /// Localtalk pseudo type + LocalTalk = bindings::ETH_P_LOCALTALK as u16, + /// CAN: Controlled Area Network + Can = bindings::ETH_P_CAN as u16, + /// CANFD: CAN Flexible Data Rate + CanFd = bindings::ETH_P_CANFD as u16, + /// CANXL: CAN eXtended Frame Length + CanXl = bindings::ETH_P_CANXL as u16, + /// Dummy type for Atalk over PPP + PppTalk = bindings::ETH_P_PPPTALK as u16, + /// 802.2 frames + Tr8022 = bindings::ETH_P_TR_802_2 as u16, + /// Mobitex (kaz@cafe.net) + Mobitex = bindings::ETH_P_MOBITEX as u16, + /// Card specific control frames + Control = bindings::ETH_P_CONTROL as u16, + /// Linux IrDA + Irda = bindings::ETH_P_IRDA as u16, + /// Acorn Econet + Econet = bindings::ETH_P_ECONET as u16, + /// HDLC frames + Hdlc = bindings::ETH_P_HDLC as u16, + /// 1A for ArcNet :-) + ArcNet = bindings::ETH_P_ARCNET as u16, + /// Distributed Switch Arch. + Dsa = bindings::ETH_P_DSA as u16, + /// Trailer Switch Tagging as u16, + Trailer = bindings::ETH_P_TRAILER as u16, + /// Nokia Phonet frames + Phonet = bindings::ETH_P_PHONET as u16, + /// IEEE802.15.4 frame + IEEE802154 = bindings::ETH_P_IEEE802154 as u16, + /// ST-Ericsson CAIF protocol + Caif = bindings::ETH_P_CAIF as u16, + /// Multiplexed DSA protocol + XDsa = bindings::ETH_P_XDSA as u16, + /// Qalcomm Multiplexing and Aggregation Protocol (MAP) + Map = bindings::ETH_P_MAP as u16, + /// Management Component Transport Protocol packets + Mctp = bindings::ETH_P_MCTP as u16, +} + +impl From for u16 { + fn from(p: Proto) -> u16 { + p as u16 + } +} + +/// Unknown Ethernet Protocol Number Error +#[derive(Clone, Copy, Debug)] +pub struct UnknownProtoError(u16); + +impl TryFrom for Proto { + type Error = UnknownProtoError; + fn try_from(u: u16) -> core::result::Result { + match u32::from(u) { + bindings::ETH_P_LOOP => Ok(Self::Loop), + bindings::ETH_P_PUP => Ok(Self::Pup), + bindings::ETH_P_PUPAT => Ok(Self::PupAddrTrans), + bindings::ETH_P_TSN => Ok(Self::Tsn), + bindings::ETH_P_ERSPAN2 => Ok(Self::Erspan2), + bindings::ETH_P_IP => Ok(Self::Ip), + bindings::ETH_P_X25 => Ok(Self::X25), + bindings::ETH_P_ARP => Ok(Self::Arp), + bindings::ETH_P_BPQ => Ok(Self::Bpq), + bindings::ETH_P_IEEEPUP => Ok(Self::IeeePup), + bindings::ETH_P_IEEEPUPAT => Ok(Self::IeeePupAddrTrans), + bindings::ETH_P_BATMAN => Ok(Self::Batman), + bindings::ETH_P_DEC => Ok(Self::Dec), + bindings::ETH_P_DNA_DL => Ok(Self::DNADumpLoad), + bindings::ETH_P_DNA_RC => Ok(Self::DNARemoteControl), + bindings::ETH_P_DNA_RT => Ok(Self::DNARouting), + bindings::ETH_P_LAT => Ok(Self::Lat), + bindings::ETH_P_DIAG => Ok(Self::Diag), + bindings::ETH_P_CUST => Ok(Self::Cust), + bindings::ETH_P_SCA => Ok(Self::Sca), + bindings::ETH_P_TEB => Ok(Self::Teb), + bindings::ETH_P_RARP => Ok(Self::Rarp), + bindings::ETH_P_ATALK => Ok(Self::ATalk), + bindings::ETH_P_AARP => Ok(Self::AArp), + bindings::ETH_P_8021Q => Ok(Self::IEEE8021Q), + bindings::ETH_P_ERSPAN => Ok(Self::Erspan), + bindings::ETH_P_IPX => Ok(Self::Ipx), + bindings::ETH_P_IPV6 => Ok(Self::IpV6), + bindings::ETH_P_PAUSE => Ok(Self::Pause), + bindings::ETH_P_SLOW => Ok(Self::Slow), + bindings::ETH_P_WCCP => Ok(Self::Wccp), + bindings::ETH_P_MPLS_UC => Ok(Self::MplsUnicast), + bindings::ETH_P_MPLS_MC => Ok(Self::MplsMulticast), + bindings::ETH_P_ATMMPOA => Ok(Self::AtmMpOa), + bindings::ETH_P_PPP_DISC => Ok(Self::PppDisc), + bindings::ETH_P_PPP_SES => Ok(Self::PppSes), + bindings::ETH_P_LINK_CTL => Ok(Self::LinkCtl), + bindings::ETH_P_ATMFATE => Ok(Self::AtmFate), + bindings::ETH_P_PAE => Ok(Self::Pae), + bindings::ETH_P_PROFINET => Ok(Self::Profinet), + bindings::ETH_P_REALTEK => Ok(Self::Realtek), + bindings::ETH_P_AOE => Ok(Self::Aoe), + bindings::ETH_P_ETHERCAT => Ok(Self::EtherCat), + bindings::ETH_P_8021AD => Ok(Self::_8021ad), + bindings::ETH_P_802_EX1 => Ok(Self::_802Ex1), + bindings::ETH_P_PREAUTH => Ok(Self::PreAuth), + bindings::ETH_P_TIPC => Ok(Self::Tipc), + bindings::ETH_P_LLDP => Ok(Self::Lldp), + bindings::ETH_P_MRP => Ok(Self::Mrp), + bindings::ETH_P_MACSEC => Ok(Self::MacSec), + bindings::ETH_P_8021AH => Ok(Self::_8021ah), + bindings::ETH_P_MVRP => Ok(Self::Mvrp), + bindings::ETH_P_1588 => Ok(Self::_1588), + bindings::ETH_P_NCSI => Ok(Self::Ncsi), + bindings::ETH_P_PRP => Ok(Self::Prp), + bindings::ETH_P_CFM => Ok(Self::Cfm), + bindings::ETH_P_FCOE => Ok(Self::FcoE), + bindings::ETH_P_IBOE => Ok(Self::IboE), + bindings::ETH_P_TDLS => Ok(Self::Tdls), + bindings::ETH_P_FIP => Ok(Self::Fip), + bindings::ETH_P_80221 => Ok(Self::_80221), + bindings::ETH_P_HSR => Ok(Self::Hsr), + bindings::ETH_P_NSH => Ok(Self::Nsh), + bindings::ETH_P_LOOPBACK => Ok(Self::Loopback), + bindings::ETH_P_QINQ1 => Ok(Self::QinQ1), + bindings::ETH_P_QINQ2 => Ok(Self::QinQ2), + bindings::ETH_P_QINQ3 => Ok(Self::QinQ3), + bindings::ETH_P_EDSA => Ok(Self::Edsa), + bindings::ETH_P_DSA_8021Q => Ok(Self::Dsa8021Q), + bindings::ETH_P_DSA_A5PSW => Ok(Self::DsaA5Psw), + bindings::ETH_P_IFE => Ok(Self::Ife), + bindings::ETH_P_AF_IUCV => Ok(Self::AfIucv), + bindings::ETH_P_802_3_MIN => Ok(Self::Min8023), + bindings::ETH_P_802_3 => Ok(Self::_8023), + bindings::ETH_P_AX25 => Ok(Self::Ax25), + bindings::ETH_P_ALL => Ok(Self::All), + bindings::ETH_P_802_2 => Ok(Self::_8022), + bindings::ETH_P_SNAP => Ok(Self::Snap), + bindings::ETH_P_DDCMP => Ok(Self::DDcmp), + bindings::ETH_P_WAN_PPP => Ok(Self::WanPpp), + bindings::ETH_P_PPP_MP => Ok(Self::PppMp), + bindings::ETH_P_LOCALTALK => Ok(Self::LocalTalk), + bindings::ETH_P_CAN => Ok(Self::Can), + bindings::ETH_P_CANFD => Ok(Self::CanFd), + bindings::ETH_P_CANXL => Ok(Self::CanXl), + bindings::ETH_P_PPPTALK => Ok(Self::PppTalk), + bindings::ETH_P_TR_802_2 => Ok(Self::Tr8022), + bindings::ETH_P_MOBITEX => Ok(Self::Mobitex), + bindings::ETH_P_CONTROL => Ok(Self::Control), + bindings::ETH_P_IRDA => Ok(Self::Irda), + bindings::ETH_P_ECONET => Ok(Self::Econet), + bindings::ETH_P_HDLC => Ok(Self::Hdlc), + bindings::ETH_P_ARCNET => Ok(Self::ArcNet), + bindings::ETH_P_DSA => Ok(Self::Dsa), + bindings::ETH_P_TRAILER => Ok(Self::Trailer), + bindings::ETH_P_PHONET => Ok(Self::Phonet), + bindings::ETH_P_IEEE802154 => Ok(Self::IEEE802154), + bindings::ETH_P_CAIF => Ok(Self::Caif), + bindings::ETH_P_XDSA => Ok(Self::XDsa), + bindings::ETH_P_MAP => Ok(Self::Map), + bindings::ETH_P_MCTP => Ok(Self::Mctp), + _ => Err(UnknownProtoError(u)), + } + } +} + +/// Ethernet Address Type +#[repr(transparent)] +pub struct Address(pub [u8; ALEN]); + +impl Address { + /// Return the unspecified Ethernet address + pub const fn unspecified() -> Self { + Self([0x00; ALEN]) + } + + /// Return the broadcast Ethernet address + pub const fn broadcast() -> Self { + Self([0xff; ALEN]) + } +} + +/// Ethernet II protocol header +#[repr(transparent)] +pub struct Header(bindings::ethhdr); + +impl Header { + /// Build a new Ethernet header from all necessary information + /// + /// This method automatically handles conversion of the ethertype provided + /// into a network-endian u16. + pub fn new(dst: Address, src: Address, proto: Proto) -> Self { + Self(bindings::ethhdr { + h_dest: dst.0, + h_source: src.0, + h_proto: u16::to_be(u16::from(proto)), + }) + } + + /// Return the source address contained in the header + pub fn src_hwaddr(&self) -> Address { + Address(self.0.h_source) + } + + /// Return the destination address contained in the header + pub fn dst_hwaddr(&self) -> Address { + Address(self.0.h_dest) + } + + /// Return the protocol number contained in the header + /// + /// This method does not handle conversion from network endian. + pub fn proto_number(&self) -> u16 { + self.0.h_proto + } +}