mod.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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 core::fmt;
  115. use crate::phy::Medium;
  116. pub use self::pretty_print::PrettyPrinter;
  117. #[cfg(feature = "medium-ethernet")]
  118. pub use self::ethernet::{
  119. Address as EthernetAddress, EtherType as EthernetProtocol, Frame as EthernetFrame,
  120. Repr as EthernetRepr, HEADER_LEN as ETHERNET_HEADER_LEN,
  121. };
  122. #[cfg(all(feature = "proto-ipv4", feature = "medium-ethernet"))]
  123. pub use self::arp::{
  124. Hardware as ArpHardware, Operation as ArpOperation, Packet as ArpPacket, Repr as ArpRepr,
  125. };
  126. #[cfg(all(feature = "proto-sixlowpan", feature = "medium-ieee802154"))]
  127. pub use self::sixlowpan::{
  128. frag::{Key as SixlowpanFragKey, Packet as SixlowpanFragPacket, Repr as SixlowpanFragRepr},
  129. iphc::{Packet as SixlowpanIphcPacket, Repr as SixlowpanIphcRepr},
  130. nhc::{
  131. ExtHeaderPacket as SixlowpanExtHeaderPacket, ExtHeaderRepr as SixlowpanExtHeaderRepr,
  132. NhcPacket as SixlowpanNhcPacket, UdpNhcPacket as SixlowpanUdpNhcPacket,
  133. UdpNhcRepr as SixlowpanUdpNhcRepr,
  134. },
  135. NextHeader as SixlowpanNextHeader, SixlowpanPacket,
  136. };
  137. #[cfg(feature = "medium-ieee802154")]
  138. pub use self::ieee802154::{
  139. Address as Ieee802154Address, AddressingMode as Ieee802154AddressingMode,
  140. Frame as Ieee802154Frame, FrameType as Ieee802154FrameType,
  141. FrameVersion as Ieee802154FrameVersion, Pan as Ieee802154Pan, Repr as Ieee802154Repr,
  142. };
  143. pub use self::ip::{
  144. Address as IpAddress, Cidr as IpCidr, Endpoint as IpEndpoint,
  145. ListenEndpoint as IpListenEndpoint, Protocol as IpProtocol, Repr as IpRepr,
  146. Version as IpVersion,
  147. };
  148. #[cfg(feature = "proto-ipv4")]
  149. pub use self::ipv4::{
  150. Address as Ipv4Address, Cidr as Ipv4Cidr, Key as Ipv4FragKey, Packet as Ipv4Packet,
  151. Repr as Ipv4Repr, HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
  152. };
  153. #[cfg(feature = "proto-ipv6")]
  154. pub use self::ipv6::{
  155. Address as Ipv6Address, Cidr as Ipv6Cidr, Packet as Ipv6Packet, Repr as Ipv6Repr,
  156. HEADER_LEN as IPV6_HEADER_LEN, MIN_MTU as IPV6_MIN_MTU,
  157. };
  158. #[cfg(feature = "proto-ipv6")]
  159. pub use self::ipv6option::{
  160. FailureType as Ipv6OptionFailureType, Ipv6Option, Repr as Ipv6OptionRepr,
  161. Type as Ipv6OptionType,
  162. };
  163. #[cfg(feature = "proto-ipv6")]
  164. pub use self::ipv6hopbyhop::{Header as Ipv6HopByHopHeader, Repr as Ipv6HopByHopRepr};
  165. #[cfg(feature = "proto-ipv6")]
  166. pub use self::ipv6fragment::{Header as Ipv6FragmentHeader, Repr as Ipv6FragmentRepr};
  167. #[cfg(feature = "proto-ipv6")]
  168. pub use self::ipv6routing::{Header as Ipv6RoutingHeader, Repr as Ipv6RoutingRepr};
  169. #[cfg(feature = "proto-ipv4")]
  170. pub use self::icmpv4::{
  171. DstUnreachable as Icmpv4DstUnreachable, Message as Icmpv4Message, Packet as Icmpv4Packet,
  172. ParamProblem as Icmpv4ParamProblem, Redirect as Icmpv4Redirect, Repr as Icmpv4Repr,
  173. TimeExceeded as Icmpv4TimeExceeded,
  174. };
  175. #[cfg(feature = "proto-igmp")]
  176. pub use self::igmp::{IgmpVersion, Packet as IgmpPacket, Repr as IgmpRepr};
  177. #[cfg(feature = "proto-ipv6")]
  178. pub use self::icmpv6::{
  179. DstUnreachable as Icmpv6DstUnreachable, Message as Icmpv6Message, Packet as Icmpv6Packet,
  180. ParamProblem as Icmpv6ParamProblem, Repr as Icmpv6Repr, TimeExceeded as Icmpv6TimeExceeded,
  181. };
  182. #[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
  183. pub use self::icmp::Repr as IcmpRepr;
  184. #[cfg(all(
  185. feature = "proto-ipv6",
  186. any(feature = "medium-ethernet", feature = "medium-ieee802154")
  187. ))]
  188. pub use self::ndisc::{
  189. NeighborFlags as NdiscNeighborFlags, Repr as NdiscRepr, RouterFlags as NdiscRouterFlags,
  190. };
  191. #[cfg(all(
  192. feature = "proto-ipv6",
  193. any(feature = "medium-ethernet", feature = "medium-ieee802154")
  194. ))]
  195. pub use self::ndiscoption::{
  196. NdiscOption, PrefixInfoFlags as NdiscPrefixInfoFlags,
  197. PrefixInformation as NdiscPrefixInformation, RedirectedHeader as NdiscRedirectedHeader,
  198. Repr as NdiscOptionRepr, Type as NdiscOptionType,
  199. };
  200. #[cfg(feature = "proto-ipv6")]
  201. pub use self::mld::{AddressRecord as MldAddressRecord, Repr as MldRepr};
  202. pub use self::udp::{Packet as UdpPacket, Repr as UdpRepr, HEADER_LEN as UDP_HEADER_LEN};
  203. pub use self::tcp::{
  204. Control as TcpControl, Packet as TcpPacket, Repr as TcpRepr, SeqNumber as TcpSeqNumber,
  205. TcpOption, HEADER_LEN as TCP_HEADER_LEN,
  206. };
  207. #[cfg(feature = "proto-dhcpv4")]
  208. pub use self::dhcpv4::{
  209. MessageType as DhcpMessageType, Packet as DhcpPacket, Repr as DhcpRepr,
  210. CLIENT_PORT as DHCP_CLIENT_PORT, MAX_DNS_SERVER_COUNT as DHCP_MAX_DNS_SERVER_COUNT,
  211. SERVER_PORT as DHCP_SERVER_PORT,
  212. };
  213. /// Parsing a packet failed.
  214. ///
  215. /// Either it is malformed, or it is not supported by smoltcp.
  216. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  217. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  218. pub struct Error;
  219. #[cfg(feature = "std")]
  220. impl std::error::Error for Error {}
  221. impl fmt::Display for Error {
  222. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  223. write!(f, "wire::Error")
  224. }
  225. }
  226. pub type Result<T> = core::result::Result<T, Error>;
  227. /// Representation of an hardware address, such as an Ethernet address or an IEEE802.15.4 address.
  228. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  229. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  230. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  231. pub enum HardwareAddress {
  232. #[cfg(feature = "medium-ethernet")]
  233. Ethernet(EthernetAddress),
  234. #[cfg(feature = "medium-ieee802154")]
  235. Ieee802154(Ieee802154Address),
  236. }
  237. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  238. impl HardwareAddress {
  239. pub fn as_bytes(&self) -> &[u8] {
  240. match self {
  241. #[cfg(feature = "medium-ethernet")]
  242. HardwareAddress::Ethernet(addr) => addr.as_bytes(),
  243. #[cfg(feature = "medium-ieee802154")]
  244. HardwareAddress::Ieee802154(addr) => addr.as_bytes(),
  245. }
  246. }
  247. /// Query wether the address is an unicast address.
  248. pub fn is_unicast(&self) -> bool {
  249. match self {
  250. #[cfg(feature = "medium-ethernet")]
  251. HardwareAddress::Ethernet(addr) => addr.is_unicast(),
  252. #[cfg(feature = "medium-ieee802154")]
  253. HardwareAddress::Ieee802154(addr) => addr.is_unicast(),
  254. }
  255. }
  256. /// Query wether the address is a broadcast address.
  257. pub fn is_broadcast(&self) -> bool {
  258. match self {
  259. #[cfg(feature = "medium-ethernet")]
  260. HardwareAddress::Ethernet(addr) => addr.is_broadcast(),
  261. #[cfg(feature = "medium-ieee802154")]
  262. HardwareAddress::Ieee802154(addr) => addr.is_broadcast(),
  263. }
  264. }
  265. }
  266. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  267. impl core::fmt::Display for HardwareAddress {
  268. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
  269. match self {
  270. #[cfg(feature = "medium-ethernet")]
  271. HardwareAddress::Ethernet(addr) => write!(f, "{}", addr),
  272. #[cfg(feature = "medium-ieee802154")]
  273. HardwareAddress::Ieee802154(addr) => write!(f, "{}", addr),
  274. }
  275. }
  276. }
  277. #[cfg(feature = "medium-ethernet")]
  278. impl From<EthernetAddress> for HardwareAddress {
  279. fn from(addr: EthernetAddress) -> Self {
  280. HardwareAddress::Ethernet(addr)
  281. }
  282. }
  283. #[cfg(feature = "medium-ieee802154")]
  284. impl From<Ieee802154Address> for HardwareAddress {
  285. fn from(addr: Ieee802154Address) -> Self {
  286. HardwareAddress::Ieee802154(addr)
  287. }
  288. }
  289. #[cfg(not(feature = "medium-ieee802154"))]
  290. pub const MAX_HARDWARE_ADDRESS_LEN: usize = 6;
  291. #[cfg(feature = "medium-ieee802154")]
  292. pub const MAX_HARDWARE_ADDRESS_LEN: usize = 8;
  293. /// Unparsed hardware address.
  294. ///
  295. /// Used to make NDISC parsing agnostic of the hardware medium in use.
  296. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  297. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  298. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  299. pub struct RawHardwareAddress {
  300. len: u8,
  301. data: [u8; MAX_HARDWARE_ADDRESS_LEN],
  302. }
  303. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  304. impl RawHardwareAddress {
  305. pub fn from_bytes(addr: &[u8]) -> Self {
  306. let mut data = [0u8; MAX_HARDWARE_ADDRESS_LEN];
  307. data[..addr.len()].copy_from_slice(addr);
  308. Self {
  309. len: addr.len() as u8,
  310. data,
  311. }
  312. }
  313. pub fn as_bytes(&self) -> &[u8] {
  314. &self.data[..self.len as usize]
  315. }
  316. pub fn len(&self) -> usize {
  317. self.len as usize
  318. }
  319. pub fn is_empty(&self) -> bool {
  320. self.len == 0
  321. }
  322. pub fn parse(&self, medium: Medium) -> Result<HardwareAddress> {
  323. match medium {
  324. #[cfg(feature = "medium-ethernet")]
  325. Medium::Ethernet => {
  326. if self.len() < 6 {
  327. return Err(Error);
  328. }
  329. Ok(HardwareAddress::Ethernet(EthernetAddress::from_bytes(
  330. self.as_bytes(),
  331. )))
  332. }
  333. #[cfg(feature = "medium-ieee802154")]
  334. Medium::Ieee802154 => {
  335. if self.len() < 8 {
  336. return Err(Error);
  337. }
  338. Ok(HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(
  339. self.as_bytes(),
  340. )))
  341. }
  342. #[cfg(feature = "medium-ip")]
  343. Medium::Ip => unreachable!(),
  344. }
  345. }
  346. }
  347. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  348. impl core::fmt::Display for RawHardwareAddress {
  349. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
  350. for (i, &b) in self.as_bytes().iter().enumerate() {
  351. if i != 0 {
  352. write!(f, ":")?;
  353. }
  354. write!(f, "{:02x}", b)?;
  355. }
  356. Ok(())
  357. }
  358. }
  359. #[cfg(feature = "medium-ethernet")]
  360. impl From<EthernetAddress> for RawHardwareAddress {
  361. fn from(addr: EthernetAddress) -> Self {
  362. Self::from_bytes(addr.as_bytes())
  363. }
  364. }
  365. #[cfg(feature = "medium-ieee802154")]
  366. impl From<Ieee802154Address> for RawHardwareAddress {
  367. fn from(addr: Ieee802154Address) -> Self {
  368. Self::from_bytes(addr.as_bytes())
  369. }
  370. }
  371. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  372. impl From<HardwareAddress> for RawHardwareAddress {
  373. fn from(addr: HardwareAddress) -> Self {
  374. Self::from_bytes(addr.as_bytes())
  375. }
  376. }