mod.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*! Low-level packet access and construction.
  2. The `wire` module deals with the packet *representation*. It provides two levels
  3. of functionality.
  4. * First, it provides functions to extract fields from sequences of octets,
  5. and to insert fields into sequences of octets. This happens `Packet` family of
  6. structures, e.g. [EthernetFrame] or [Ipv4Packet].
  7. * Second, in cases where the space of valid field values is much smaller than the space
  8. of possible field values, it provides a compact, high-level representation
  9. of packet data that can be parsed from and emitted into a sequence of octets.
  10. This happens through the `Repr` family of structs and enums, e.g. [ArpRepr] or [Ipv4Repr].
  11. [EthernetFrame]: struct.EthernetFrame.html
  12. [Ipv4Packet]: struct.Ipv4Packet.html
  13. [ArpRepr]: enum.ArpRepr.html
  14. [Ipv4Repr]: struct.Ipv4Repr.html
  15. The functions in the `wire` module are designed for use together with `-Cpanic=abort`.
  16. The `Packet` family of data structures guarantees that, if the `Packet::check_len()` method
  17. returned `Ok(())`, then no accessor or setter method will panic; however, the guarantee
  18. provided by `Packet::check_len()` may no longer hold after changing certain fields,
  19. which are listed in the documentation for the specific packet.
  20. The `Packet::new_checked` method is a shorthand for a combination of `Packet::new_unchecked`
  21. and `Packet::check_len`.
  22. When parsing untrusted input, it is *necessary* to use `Packet::new_checked()`;
  23. so long as the buffer is not modified, no accessor will fail.
  24. When emitting output, though, it is *incorrect* to use `Packet::new_checked()`;
  25. the length check is likely to succeed on a zeroed buffer, but fail on a buffer
  26. filled with data from a previous packet, such as when reusing buffers, resulting
  27. in nondeterministic panics with some network devices but not others.
  28. The buffer length for emission is not calculated by the `Packet` layer.
  29. In the `Repr` family of data structures, the `Repr::parse()` method never panics
  30. as long as `Packet::new_checked()` (or `Packet::check_len()`) has succeeded, and
  31. the `Repr::emit()` method never panics as long as the underlying buffer is exactly
  32. `Repr::buffer_len()` octets long.
  33. # Examples
  34. To emit an IP packet header into an octet buffer, and then parse it back:
  35. ```rust
  36. # #[cfg(feature = "proto-ipv4")]
  37. # {
  38. use smoltcp::phy::ChecksumCapabilities;
  39. use smoltcp::wire::*;
  40. let repr = Ipv4Repr {
  41. src_addr: Ipv4Address::new(10, 0, 0, 1),
  42. dst_addr: Ipv4Address::new(10, 0, 0, 2),
  43. next_header: IpProtocol::Tcp,
  44. payload_len: 10,
  45. hop_limit: 64
  46. };
  47. let mut buffer = vec![0; repr.buffer_len() + repr.payload_len];
  48. { // emission
  49. let mut packet = Ipv4Packet::new_unchecked(&mut buffer);
  50. repr.emit(&mut packet, &ChecksumCapabilities::default());
  51. }
  52. { // parsing
  53. let packet = Ipv4Packet::new_checked(&buffer)
  54. .expect("truncated packet");
  55. let parsed = Ipv4Repr::parse(&packet, &ChecksumCapabilities::default())
  56. .expect("malformed packet");
  57. assert_eq!(repr, parsed);
  58. }
  59. # }
  60. ```
  61. */
  62. mod field {
  63. pub type Field = ::core::ops::Range<usize>;
  64. pub type Rest = ::core::ops::RangeFrom<usize>;
  65. }
  66. pub mod pretty_print;
  67. #[cfg(all(feature = "proto-ipv4", feature = "medium-ethernet"))]
  68. mod arp;
  69. #[cfg(feature = "proto-dhcpv4")]
  70. pub(crate) mod dhcpv4;
  71. #[cfg(feature = "proto-dns")]
  72. pub(crate) mod dns;
  73. #[cfg(feature = "medium-ethernet")]
  74. mod ethernet;
  75. #[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
  76. mod icmp;
  77. #[cfg(feature = "proto-ipv4")]
  78. mod icmpv4;
  79. #[cfg(feature = "proto-ipv6")]
  80. mod icmpv6;
  81. #[cfg(feature = "medium-ieee802154")]
  82. pub mod ieee802154;
  83. #[cfg(feature = "proto-igmp")]
  84. mod igmp;
  85. pub(crate) mod ip;
  86. #[cfg(feature = "proto-ipv4")]
  87. mod ipv4;
  88. #[cfg(feature = "proto-ipv6")]
  89. mod ipv6;
  90. #[cfg(feature = "proto-ipv6")]
  91. mod ipv6fragment;
  92. #[cfg(feature = "proto-ipv6")]
  93. mod ipv6hopbyhop;
  94. #[cfg(feature = "proto-ipv6")]
  95. mod ipv6option;
  96. #[cfg(feature = "proto-ipv6")]
  97. mod ipv6routing;
  98. #[cfg(feature = "proto-ipv6")]
  99. mod mld;
  100. #[cfg(all(
  101. feature = "proto-ipv6",
  102. any(feature = "medium-ethernet", feature = "medium-ieee802154")
  103. ))]
  104. mod ndisc;
  105. #[cfg(all(
  106. feature = "proto-ipv6",
  107. any(feature = "medium-ethernet", feature = "medium-ieee802154")
  108. ))]
  109. mod ndiscoption;
  110. #[cfg(all(feature = "proto-sixlowpan", feature = "medium-ieee802154"))]
  111. mod sixlowpan;
  112. mod tcp;
  113. mod udp;
  114. use crate::{phy::Medium, Error};
  115. pub use self::pretty_print::PrettyPrinter;
  116. #[cfg(feature = "medium-ethernet")]
  117. pub use self::ethernet::{
  118. Address as EthernetAddress, EtherType as EthernetProtocol, Frame as EthernetFrame,
  119. Repr as EthernetRepr, HEADER_LEN as ETHERNET_HEADER_LEN,
  120. };
  121. #[cfg(all(feature = "proto-ipv4", feature = "medium-ethernet"))]
  122. pub use self::arp::{
  123. Hardware as ArpHardware, Operation as ArpOperation, Packet as ArpPacket, Repr as ArpRepr,
  124. };
  125. #[cfg(all(feature = "proto-sixlowpan", feature = "medium-ieee802154"))]
  126. pub use self::sixlowpan::{
  127. iphc::{Packet as SixlowpanIphcPacket, Repr as SixlowpanIphcRepr},
  128. nhc::{
  129. ExtensionHeaderPacket as SixlowpanExtHeaderPacket,
  130. ExtensionHeaderRepr as SixlowpanExtHeaderRepr, Packet as SixlowpanNhcPacket,
  131. UdpNhcRepr as SixlowpanUdpRepr, UdpPacket as SixlowpanUdpPacket,
  132. },
  133. NextHeader as SixlowpanNextHeader,
  134. };
  135. #[cfg(feature = "medium-ieee802154")]
  136. pub use self::ieee802154::{
  137. Address as Ieee802154Address, AddressingMode as Ieee802154AddressingMode,
  138. Frame as Ieee802154Frame, FrameType as Ieee802154FrameType,
  139. FrameVersion as Ieee802154FrameVersion, Pan as Ieee802154Pan, Repr as Ieee802154Repr,
  140. };
  141. pub use self::ip::{
  142. Address as IpAddress, Cidr as IpCidr, Endpoint as IpEndpoint,
  143. ListenEndpoint as IpListenEndpoint, Protocol as IpProtocol, Repr as IpRepr,
  144. Version as IpVersion,
  145. };
  146. #[cfg(feature = "proto-ipv4")]
  147. pub use self::ipv4::{
  148. Address as Ipv4Address, Cidr as Ipv4Cidr, Packet as Ipv4Packet, Repr as Ipv4Repr,
  149. HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
  150. };
  151. #[cfg(feature = "proto-ipv6")]
  152. pub use self::ipv6::{
  153. Address as Ipv6Address, Cidr as Ipv6Cidr, Packet as Ipv6Packet, Repr as Ipv6Repr,
  154. HEADER_LEN as IPV6_HEADER_LEN, MIN_MTU as IPV6_MIN_MTU,
  155. };
  156. #[cfg(feature = "proto-ipv6")]
  157. pub use self::ipv6option::{
  158. FailureType as Ipv6OptionFailureType, Ipv6Option, Repr as Ipv6OptionRepr,
  159. Type as Ipv6OptionType,
  160. };
  161. #[cfg(feature = "proto-ipv6")]
  162. pub use self::ipv6hopbyhop::{Header as Ipv6HopByHopHeader, Repr as Ipv6HopByHopRepr};
  163. #[cfg(feature = "proto-ipv6")]
  164. pub use self::ipv6fragment::{Header as Ipv6FragmentHeader, Repr as Ipv6FragmentRepr};
  165. #[cfg(feature = "proto-ipv6")]
  166. pub use self::ipv6routing::{Header as Ipv6RoutingHeader, Repr as Ipv6RoutingRepr};
  167. #[cfg(feature = "proto-ipv4")]
  168. pub use self::icmpv4::{
  169. DstUnreachable as Icmpv4DstUnreachable, Message as Icmpv4Message, Packet as Icmpv4Packet,
  170. ParamProblem as Icmpv4ParamProblem, Redirect as Icmpv4Redirect, Repr as Icmpv4Repr,
  171. TimeExceeded as Icmpv4TimeExceeded,
  172. };
  173. #[cfg(feature = "proto-igmp")]
  174. pub use self::igmp::{IgmpVersion, Packet as IgmpPacket, Repr as IgmpRepr};
  175. #[cfg(feature = "proto-ipv6")]
  176. pub use self::icmpv6::{
  177. DstUnreachable as Icmpv6DstUnreachable, Message as Icmpv6Message, Packet as Icmpv6Packet,
  178. ParamProblem as Icmpv6ParamProblem, Repr as Icmpv6Repr, TimeExceeded as Icmpv6TimeExceeded,
  179. };
  180. #[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
  181. pub use self::icmp::Repr as IcmpRepr;
  182. #[cfg(all(
  183. feature = "proto-ipv6",
  184. any(feature = "medium-ethernet", feature = "medium-ieee802154")
  185. ))]
  186. pub use self::ndisc::{
  187. NeighborFlags as NdiscNeighborFlags, Repr as NdiscRepr, RouterFlags as NdiscRouterFlags,
  188. };
  189. #[cfg(all(
  190. feature = "proto-ipv6",
  191. any(feature = "medium-ethernet", feature = "medium-ieee802154")
  192. ))]
  193. pub use self::ndiscoption::{
  194. NdiscOption, PrefixInfoFlags as NdiscPrefixInfoFlags,
  195. PrefixInformation as NdiscPrefixInformation, RedirectedHeader as NdiscRedirectedHeader,
  196. Repr as NdiscOptionRepr, Type as NdiscOptionType,
  197. };
  198. #[cfg(feature = "proto-ipv6")]
  199. pub use self::mld::{AddressRecord as MldAddressRecord, Repr as MldRepr};
  200. pub use self::udp::{Packet as UdpPacket, Repr as UdpRepr, HEADER_LEN as UDP_HEADER_LEN};
  201. pub use self::tcp::{
  202. Control as TcpControl, Packet as TcpPacket, Repr as TcpRepr, SeqNumber as TcpSeqNumber,
  203. TcpOption, HEADER_LEN as TCP_HEADER_LEN,
  204. };
  205. #[cfg(feature = "proto-dhcpv4")]
  206. pub use self::dhcpv4::{
  207. MessageType as DhcpMessageType, Packet as DhcpPacket, Repr as DhcpRepr,
  208. CLIENT_PORT as DHCP_CLIENT_PORT, MAX_DNS_SERVER_COUNT as DHCP_MAX_DNS_SERVER_COUNT,
  209. SERVER_PORT as DHCP_SERVER_PORT,
  210. };
  211. /// Representation of an hardware address, such as an Ethernet address or an IEEE802.15.4 address.
  212. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  213. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  214. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  215. pub enum HardwareAddress {
  216. #[cfg(feature = "medium-ethernet")]
  217. Ethernet(EthernetAddress),
  218. #[cfg(feature = "medium-ieee802154")]
  219. Ieee802154(Ieee802154Address),
  220. }
  221. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  222. impl HardwareAddress {
  223. pub fn as_bytes(&self) -> &[u8] {
  224. match self {
  225. #[cfg(feature = "medium-ethernet")]
  226. HardwareAddress::Ethernet(addr) => addr.as_bytes(),
  227. #[cfg(feature = "medium-ieee802154")]
  228. HardwareAddress::Ieee802154(addr) => addr.as_bytes(),
  229. }
  230. }
  231. /// Query wether the address is an unicast address.
  232. pub fn is_unicast(&self) -> bool {
  233. match self {
  234. #[cfg(feature = "medium-ethernet")]
  235. HardwareAddress::Ethernet(addr) => addr.is_unicast(),
  236. #[cfg(feature = "medium-ieee802154")]
  237. HardwareAddress::Ieee802154(addr) => addr.is_unicast(),
  238. }
  239. }
  240. /// Query wether the address is a broadcast address.
  241. pub fn is_broadcast(&self) -> bool {
  242. match self {
  243. #[cfg(feature = "medium-ethernet")]
  244. HardwareAddress::Ethernet(addr) => addr.is_broadcast(),
  245. #[cfg(feature = "medium-ieee802154")]
  246. HardwareAddress::Ieee802154(addr) => addr.is_broadcast(),
  247. }
  248. }
  249. }
  250. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  251. impl core::fmt::Display for HardwareAddress {
  252. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
  253. match self {
  254. #[cfg(feature = "medium-ethernet")]
  255. HardwareAddress::Ethernet(addr) => write!(f, "{}", addr),
  256. #[cfg(feature = "medium-ieee802154")]
  257. HardwareAddress::Ieee802154(addr) => write!(f, "{}", addr),
  258. }
  259. }
  260. }
  261. #[cfg(feature = "medium-ethernet")]
  262. impl From<EthernetAddress> for HardwareAddress {
  263. fn from(addr: EthernetAddress) -> Self {
  264. HardwareAddress::Ethernet(addr)
  265. }
  266. }
  267. #[cfg(feature = "medium-ieee802154")]
  268. impl From<Ieee802154Address> for HardwareAddress {
  269. fn from(addr: Ieee802154Address) -> Self {
  270. HardwareAddress::Ieee802154(addr)
  271. }
  272. }
  273. #[cfg(not(feature = "medium-ieee802154"))]
  274. pub const MAX_HARDWARE_ADDRESS_LEN: usize = 6;
  275. #[cfg(feature = "medium-ieee802154")]
  276. pub const MAX_HARDWARE_ADDRESS_LEN: usize = 8;
  277. /// Unparsed hardware address.
  278. ///
  279. /// Used to make NDISC parsing agnostic of the hardware medium in use.
  280. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  281. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  282. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  283. pub struct RawHardwareAddress {
  284. len: u8,
  285. data: [u8; MAX_HARDWARE_ADDRESS_LEN],
  286. }
  287. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  288. impl RawHardwareAddress {
  289. pub fn from_bytes(addr: &[u8]) -> Self {
  290. let mut data = [0u8; MAX_HARDWARE_ADDRESS_LEN];
  291. data[..addr.len()].copy_from_slice(addr);
  292. Self {
  293. len: addr.len() as u8,
  294. data,
  295. }
  296. }
  297. pub fn as_bytes(&self) -> &[u8] {
  298. &self.data[..self.len as usize]
  299. }
  300. pub fn len(&self) -> usize {
  301. self.len as usize
  302. }
  303. pub fn is_empty(&self) -> bool {
  304. self.len == 0
  305. }
  306. pub fn parse(&self, medium: Medium) -> Result<HardwareAddress, Error> {
  307. match medium {
  308. #[cfg(feature = "medium-ethernet")]
  309. Medium::Ethernet => {
  310. if self.len() < 6 {
  311. return Err(Error::Malformed);
  312. }
  313. Ok(HardwareAddress::Ethernet(EthernetAddress::from_bytes(
  314. self.as_bytes(),
  315. )))
  316. }
  317. #[cfg(feature = "medium-ieee802154")]
  318. Medium::Ieee802154 => {
  319. if self.len() < 8 {
  320. return Err(Error::Malformed);
  321. }
  322. Ok(HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(
  323. self.as_bytes(),
  324. )))
  325. }
  326. #[cfg(feature = "medium-ip")]
  327. Medium::Ip => unreachable!(),
  328. }
  329. }
  330. }
  331. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  332. impl core::fmt::Display for RawHardwareAddress {
  333. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
  334. for (i, &b) in self.as_bytes().iter().enumerate() {
  335. if i != 0 {
  336. write!(f, ":")?;
  337. }
  338. write!(f, "{:02x}", b)?;
  339. }
  340. Ok(())
  341. }
  342. }
  343. #[cfg(feature = "medium-ethernet")]
  344. impl From<EthernetAddress> for RawHardwareAddress {
  345. fn from(addr: EthernetAddress) -> Self {
  346. Self::from_bytes(addr.as_bytes())
  347. }
  348. }
  349. #[cfg(feature = "medium-ieee802154")]
  350. impl From<Ieee802154Address> for RawHardwareAddress {
  351. fn from(addr: Ieee802154Address) -> Self {
  352. Self::from_bytes(addr.as_bytes())
  353. }
  354. }
  355. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  356. impl From<HardwareAddress> for RawHardwareAddress {
  357. fn from(addr: HardwareAddress) -> Self {
  358. Self::from_bytes(addr.as_bytes())
  359. }
  360. }