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