ipv6.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. use super::check;
  2. use super::icmp_reply_payload_len;
  3. use super::InterfaceInner;
  4. use super::IpPacket;
  5. use super::SocketSet;
  6. #[cfg(feature = "socket-icmp")]
  7. use crate::socket::icmp;
  8. use crate::socket::AnySocket;
  9. use crate::wire::*;
  10. impl InterfaceInner {
  11. #[cfg(feature = "proto-ipv6")]
  12. pub(super) fn process_ipv6<'frame, T: AsRef<[u8]> + ?Sized>(
  13. &mut self,
  14. sockets: &mut SocketSet,
  15. ipv6_packet: &Ipv6Packet<&'frame T>,
  16. ) -> Option<IpPacket<'frame>> {
  17. let ipv6_repr = check!(Ipv6Repr::parse(ipv6_packet));
  18. if !ipv6_repr.src_addr.is_unicast() {
  19. // Discard packets with non-unicast source addresses.
  20. net_debug!("non-unicast source address");
  21. return None;
  22. }
  23. let ip_payload = ipv6_packet.payload();
  24. #[cfg(feature = "socket-raw")]
  25. let handled_by_raw_socket = self.raw_socket_filter(sockets, &ipv6_repr.into(), ip_payload);
  26. #[cfg(not(feature = "socket-raw"))]
  27. let handled_by_raw_socket = false;
  28. self.process_nxt_hdr(
  29. sockets,
  30. ipv6_repr,
  31. ipv6_repr.next_header,
  32. handled_by_raw_socket,
  33. ip_payload,
  34. )
  35. }
  36. /// Given the next header value forward the payload onto the correct process
  37. /// function.
  38. #[cfg(feature = "proto-ipv6")]
  39. pub(super) fn process_nxt_hdr<'frame>(
  40. &mut self,
  41. sockets: &mut SocketSet,
  42. ipv6_repr: Ipv6Repr,
  43. nxt_hdr: IpProtocol,
  44. handled_by_raw_socket: bool,
  45. ip_payload: &'frame [u8],
  46. ) -> Option<IpPacket<'frame>> {
  47. match nxt_hdr {
  48. IpProtocol::Icmpv6 => self.process_icmpv6(sockets, ipv6_repr.into(), ip_payload),
  49. #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
  50. IpProtocol::Udp => {
  51. let udp_packet = check!(UdpPacket::new_checked(ip_payload));
  52. let udp_repr = check!(UdpRepr::parse(
  53. &udp_packet,
  54. &ipv6_repr.src_addr.into(),
  55. &ipv6_repr.dst_addr.into(),
  56. &self.checksum_caps(),
  57. ));
  58. self.process_udp(
  59. sockets,
  60. ipv6_repr.into(),
  61. udp_repr,
  62. handled_by_raw_socket,
  63. udp_packet.payload(),
  64. ip_payload,
  65. )
  66. }
  67. #[cfg(feature = "socket-tcp")]
  68. IpProtocol::Tcp => self.process_tcp(sockets, ipv6_repr.into(), ip_payload),
  69. IpProtocol::HopByHop => {
  70. self.process_hopbyhop(sockets, ipv6_repr, handled_by_raw_socket, ip_payload)
  71. }
  72. #[cfg(feature = "socket-raw")]
  73. _ if handled_by_raw_socket => None,
  74. _ => {
  75. // Send back as much of the original payload as we can.
  76. let payload_len =
  77. icmp_reply_payload_len(ip_payload.len(), IPV6_MIN_MTU, ipv6_repr.buffer_len());
  78. let icmp_reply_repr = Icmpv6Repr::ParamProblem {
  79. reason: Icmpv6ParamProblem::UnrecognizedNxtHdr,
  80. // The offending packet is after the IPv6 header.
  81. pointer: ipv6_repr.buffer_len() as u32,
  82. header: ipv6_repr,
  83. data: &ip_payload[0..payload_len],
  84. };
  85. self.icmpv6_reply(ipv6_repr, icmp_reply_repr)
  86. }
  87. }
  88. }
  89. #[cfg(feature = "proto-ipv6")]
  90. pub(super) fn process_icmpv6<'frame>(
  91. &mut self,
  92. _sockets: &mut SocketSet,
  93. ip_repr: IpRepr,
  94. ip_payload: &'frame [u8],
  95. ) -> Option<IpPacket<'frame>> {
  96. let icmp_packet = check!(Icmpv6Packet::new_checked(ip_payload));
  97. let icmp_repr = check!(Icmpv6Repr::parse(
  98. &ip_repr.src_addr(),
  99. &ip_repr.dst_addr(),
  100. &icmp_packet,
  101. &self.caps.checksum,
  102. ));
  103. #[cfg(feature = "socket-icmp")]
  104. let mut handled_by_icmp_socket = false;
  105. #[cfg(all(feature = "socket-icmp", feature = "proto-ipv6"))]
  106. for icmp_socket in _sockets
  107. .items_mut()
  108. .filter_map(|i| icmp::Socket::downcast_mut(&mut i.socket))
  109. {
  110. if icmp_socket.accepts(self, &ip_repr, &icmp_repr.into()) {
  111. icmp_socket.process(self, &ip_repr, &icmp_repr.into());
  112. handled_by_icmp_socket = true;
  113. }
  114. }
  115. match icmp_repr {
  116. // Respond to echo requests.
  117. Icmpv6Repr::EchoRequest {
  118. ident,
  119. seq_no,
  120. data,
  121. } => match ip_repr {
  122. IpRepr::Ipv6(ipv6_repr) => {
  123. let icmp_reply_repr = Icmpv6Repr::EchoReply {
  124. ident,
  125. seq_no,
  126. data,
  127. };
  128. self.icmpv6_reply(ipv6_repr, icmp_reply_repr)
  129. }
  130. #[allow(unreachable_patterns)]
  131. _ => unreachable!(),
  132. },
  133. // Ignore any echo replies.
  134. Icmpv6Repr::EchoReply { .. } => None,
  135. // Forward any NDISC packets to the ndisc packet handler
  136. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  137. Icmpv6Repr::Ndisc(repr) if ip_repr.hop_limit() == 0xff => match ip_repr {
  138. IpRepr::Ipv6(ipv6_repr) => self.process_ndisc(ipv6_repr, repr),
  139. #[allow(unreachable_patterns)]
  140. _ => unreachable!(),
  141. },
  142. // Don't report an error if a packet with unknown type
  143. // has been handled by an ICMP socket
  144. #[cfg(feature = "socket-icmp")]
  145. _ if handled_by_icmp_socket => None,
  146. // FIXME: do something correct here?
  147. _ => None,
  148. }
  149. }
  150. #[cfg(all(
  151. any(feature = "medium-ethernet", feature = "medium-ieee802154"),
  152. feature = "proto-ipv6"
  153. ))]
  154. pub(super) fn process_ndisc<'frame>(
  155. &mut self,
  156. ip_repr: Ipv6Repr,
  157. repr: NdiscRepr<'frame>,
  158. ) -> Option<IpPacket<'frame>> {
  159. match repr {
  160. NdiscRepr::NeighborAdvert {
  161. lladdr,
  162. target_addr,
  163. flags,
  164. } => {
  165. let ip_addr = ip_repr.src_addr.into();
  166. if let Some(lladdr) = lladdr {
  167. let lladdr = check!(lladdr.parse(self.caps.medium));
  168. if !lladdr.is_unicast() || !target_addr.is_unicast() {
  169. return None;
  170. }
  171. if flags.contains(NdiscNeighborFlags::OVERRIDE)
  172. || !self.neighbor_cache.lookup(&ip_addr, self.now).found()
  173. {
  174. self.neighbor_cache.fill(ip_addr, lladdr, self.now)
  175. }
  176. }
  177. None
  178. }
  179. NdiscRepr::NeighborSolicit {
  180. target_addr,
  181. lladdr,
  182. ..
  183. } => {
  184. if let Some(lladdr) = lladdr {
  185. let lladdr = check!(lladdr.parse(self.caps.medium));
  186. if !lladdr.is_unicast() || !target_addr.is_unicast() {
  187. return None;
  188. }
  189. self.neighbor_cache
  190. .fill(ip_repr.src_addr.into(), lladdr, self.now);
  191. }
  192. if self.has_solicited_node(ip_repr.dst_addr) && self.has_ip_addr(target_addr) {
  193. let advert = Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
  194. flags: NdiscNeighborFlags::SOLICITED,
  195. target_addr,
  196. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  197. lladdr: Some(self.hardware_addr.into()),
  198. });
  199. let ip_repr = Ipv6Repr {
  200. src_addr: target_addr,
  201. dst_addr: ip_repr.src_addr,
  202. next_header: IpProtocol::Icmpv6,
  203. hop_limit: 0xff,
  204. payload_len: advert.buffer_len(),
  205. };
  206. Some(IpPacket::Icmpv6((ip_repr, advert)))
  207. } else {
  208. None
  209. }
  210. }
  211. _ => None,
  212. }
  213. }
  214. #[cfg(feature = "proto-ipv6")]
  215. pub(super) fn process_hopbyhop<'frame>(
  216. &mut self,
  217. sockets: &mut SocketSet,
  218. ipv6_repr: Ipv6Repr,
  219. handled_by_raw_socket: bool,
  220. ip_payload: &'frame [u8],
  221. ) -> Option<IpPacket<'frame>> {
  222. let hbh_pkt = check!(Ipv6HopByHopHeader::new_checked(ip_payload));
  223. let hbh_repr = check!(Ipv6HopByHopRepr::parse(&hbh_pkt));
  224. for opt_repr in hbh_repr.options() {
  225. let opt_repr = check!(opt_repr);
  226. match opt_repr {
  227. Ipv6OptionRepr::Pad1 | Ipv6OptionRepr::PadN(_) => (),
  228. #[cfg(feature = "proto-rpl")]
  229. Ipv6OptionRepr::Rpl(_) => {}
  230. Ipv6OptionRepr::Unknown { type_, .. } => {
  231. match Ipv6OptionFailureType::from(type_) {
  232. Ipv6OptionFailureType::Skip => (),
  233. Ipv6OptionFailureType::Discard => {
  234. return None;
  235. }
  236. _ => {
  237. // FIXME(dlrobertson): Send an ICMPv6 parameter problem message
  238. // here.
  239. return None;
  240. }
  241. }
  242. }
  243. }
  244. }
  245. self.process_nxt_hdr(
  246. sockets,
  247. ipv6_repr,
  248. hbh_repr.next_header,
  249. handled_by_raw_socket,
  250. &ip_payload[hbh_repr.buffer_len()..],
  251. )
  252. }
  253. #[cfg(feature = "proto-ipv6")]
  254. pub(super) fn icmpv6_reply<'frame, 'icmp: 'frame>(
  255. &self,
  256. ipv6_repr: Ipv6Repr,
  257. icmp_repr: Icmpv6Repr<'icmp>,
  258. ) -> Option<IpPacket<'frame>> {
  259. if ipv6_repr.dst_addr.is_unicast() {
  260. let ipv6_reply_repr = Ipv6Repr {
  261. src_addr: ipv6_repr.dst_addr,
  262. dst_addr: ipv6_repr.src_addr,
  263. next_header: IpProtocol::Icmpv6,
  264. payload_len: icmp_repr.buffer_len(),
  265. hop_limit: 64,
  266. };
  267. Some(IpPacket::Icmpv6((ipv6_reply_repr, icmp_repr)))
  268. } else {
  269. // Do not send any ICMP replies to a broadcast destination address.
  270. None
  271. }
  272. }
  273. }