1 use core::cmp; 2 #[cfg(feature = "async")] 3 use core::task::Waker; 4 5 use crate::phy::ChecksumCapabilities; 6 #[cfg(feature = "async")] 7 use crate::socket::WakerRegistration; 8 use crate::socket::{Context, PollAt}; 9 10 use crate::storage::Empty; 11 use crate::wire::IcmpRepr; 12 #[cfg(feature = "proto-ipv4")] 13 use crate::wire::{Icmpv4Packet, Icmpv4Repr, Ipv4Repr}; 14 #[cfg(feature = "proto-ipv6")] 15 use crate::wire::{Icmpv6Packet, Icmpv6Repr, Ipv6Repr}; 16 use crate::wire::{IpAddress, IpListenEndpoint, IpProtocol, IpRepr}; 17 use crate::wire::{UdpPacket, UdpRepr}; 18 19 /// Error returned by [`Socket::bind`] 20 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 21 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 22 pub enum BindError { 23 InvalidState, 24 Unaddressable, 25 } 26 27 /// Error returned by [`Socket::send`] 28 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 29 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 30 pub enum SendError { 31 Unaddressable, 32 BufferFull, 33 } 34 35 /// Error returned by [`Socket::recv`] 36 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 37 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 38 pub enum RecvError { 39 Exhausted, 40 } 41 42 /// Type of endpoint to bind the ICMP socket to. See [IcmpSocket::bind] for 43 /// more details. 44 /// 45 /// [IcmpSocket::bind]: struct.IcmpSocket.html#method.bind 46 #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] 47 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 48 pub enum Endpoint { 49 #[default] 50 Unspecified, 51 Ident(u16), 52 Udp(IpListenEndpoint), 53 } 54 55 impl Endpoint { is_specified(&self) -> bool56 pub fn is_specified(&self) -> bool { 57 match *self { 58 Endpoint::Ident(_) => true, 59 Endpoint::Udp(endpoint) => endpoint.port != 0, 60 Endpoint::Unspecified => false, 61 } 62 } 63 } 64 65 /// An ICMP packet metadata. 66 pub type PacketMetadata = crate::storage::PacketMetadata<IpAddress>; 67 68 /// An ICMP packet ring buffer. 69 pub type PacketBuffer<'a> = crate::storage::PacketBuffer<'a, IpAddress>; 70 71 /// A ICMP socket 72 /// 73 /// An ICMP socket is bound to a specific [IcmpEndpoint] which may 74 /// be a specific UDP port to listen for ICMP error messages related 75 /// to the port or a specific ICMP identifier value. See [bind] for 76 /// more details. 77 /// 78 /// [IcmpEndpoint]: enum.IcmpEndpoint.html 79 /// [bind]: #method.bind 80 #[derive(Debug)] 81 pub struct Socket<'a> { 82 rx_buffer: PacketBuffer<'a>, 83 tx_buffer: PacketBuffer<'a>, 84 /// The endpoint this socket is communicating with 85 endpoint: Endpoint, 86 /// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets. 87 hop_limit: Option<u8>, 88 #[cfg(feature = "async")] 89 rx_waker: WakerRegistration, 90 #[cfg(feature = "async")] 91 tx_waker: WakerRegistration, 92 } 93 94 impl<'a> Socket<'a> { 95 /// Create an ICMP socket with the given buffers. new(rx_buffer: PacketBuffer<'a>, tx_buffer: PacketBuffer<'a>) -> Socket<'a>96 pub fn new(rx_buffer: PacketBuffer<'a>, tx_buffer: PacketBuffer<'a>) -> Socket<'a> { 97 Socket { 98 rx_buffer: rx_buffer, 99 tx_buffer: tx_buffer, 100 endpoint: Default::default(), 101 hop_limit: None, 102 #[cfg(feature = "async")] 103 rx_waker: WakerRegistration::new(), 104 #[cfg(feature = "async")] 105 tx_waker: WakerRegistration::new(), 106 } 107 } 108 109 /// Register a waker for receive operations. 110 /// 111 /// The waker is woken on state changes that might affect the return value 112 /// of `recv` method calls, such as receiving data, or the socket closing. 113 /// 114 /// Notes: 115 /// 116 /// - Only one waker can be registered at a time. If another waker was previously registered, 117 /// it is overwritten and will no longer be woken. 118 /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes. 119 /// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has 120 /// necessarily changed. 121 #[cfg(feature = "async")] register_recv_waker(&mut self, waker: &Waker)122 pub fn register_recv_waker(&mut self, waker: &Waker) { 123 self.rx_waker.register(waker) 124 } 125 126 /// Register a waker for send operations. 127 /// 128 /// The waker is woken on state changes that might affect the return value 129 /// of `send` method calls, such as space becoming available in the transmit 130 /// buffer, or the socket closing. 131 /// 132 /// Notes: 133 /// 134 /// - Only one waker can be registered at a time. If another waker was previously registered, 135 /// it is overwritten and will no longer be woken. 136 /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes. 137 /// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has 138 /// necessarily changed. 139 #[cfg(feature = "async")] register_send_waker(&mut self, waker: &Waker)140 pub fn register_send_waker(&mut self, waker: &Waker) { 141 self.tx_waker.register(waker) 142 } 143 144 /// Return the time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets. 145 /// 146 /// See also the [set_hop_limit](#method.set_hop_limit) method hop_limit(&self) -> Option<u8>147 pub fn hop_limit(&self) -> Option<u8> { 148 self.hop_limit 149 } 150 151 /// Set the time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets. 152 /// 153 /// A socket without an explicitly set hop limit value uses the default [IANA recommended] 154 /// value (64). 155 /// 156 /// # Panics 157 /// 158 /// This function panics if a hop limit value of 0 is given. See [RFC 1122 § 3.2.1.7]. 159 /// 160 /// [IANA recommended]: https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml 161 /// [RFC 1122 § 3.2.1.7]: https://tools.ietf.org/html/rfc1122#section-3.2.1.7 set_hop_limit(&mut self, hop_limit: Option<u8>)162 pub fn set_hop_limit(&mut self, hop_limit: Option<u8>) { 163 // A host MUST NOT send a datagram with a hop limit value of 0 164 if let Some(0) = hop_limit { 165 panic!("the time-to-live value of a packet must not be zero") 166 } 167 168 self.hop_limit = hop_limit 169 } 170 171 /// Bind the socket to the given endpoint. 172 /// 173 /// This function returns `Err(Error::Illegal)` if the socket was open 174 /// (see [is_open](#method.is_open)), and `Err(Error::Unaddressable)` 175 /// if `endpoint` is unspecified (see [is_specified]). 176 /// 177 /// # Examples 178 /// 179 /// ## Bind to ICMP Error messages associated with a specific UDP port: 180 /// 181 /// To [recv] ICMP error messages that are associated with a specific local 182 /// UDP port, the socket may be bound to a given port using [IcmpEndpoint::Udp]. 183 /// This may be useful for applications using UDP attempting to detect and/or 184 /// diagnose connection problems. 185 /// 186 /// ``` 187 /// use smoltcp::wire::IpListenEndpoint; 188 /// use smoltcp::socket::icmp; 189 /// # let rx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 20]); 190 /// # let tx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 20]); 191 /// 192 /// let mut icmp_socket = // ... 193 /// # icmp::Socket::new(rx_buffer, tx_buffer); 194 /// 195 /// // Bind to ICMP error responses for UDP packets sent from port 53. 196 /// let endpoint = IpListenEndpoint::from(53); 197 /// icmp_socket.bind(icmp::Endpoint::Udp(endpoint)).unwrap(); 198 /// ``` 199 /// 200 /// ## Bind to a specific ICMP identifier: 201 /// 202 /// To [send] and [recv] ICMP packets that are not associated with a specific UDP 203 /// port, the socket may be bound to a specific ICMP identifier using 204 /// [IcmpEndpoint::Ident]. This is useful for sending and receiving Echo Request/Reply 205 /// messages. 206 /// 207 /// ``` 208 /// use smoltcp::wire::IpListenEndpoint; 209 /// use smoltcp::socket::icmp; 210 /// # let rx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 20]); 211 /// # let tx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 20]); 212 /// 213 /// let mut icmp_socket = // ... 214 /// # icmp::Socket::new(rx_buffer, tx_buffer); 215 /// 216 /// // Bind to ICMP messages with the ICMP identifier 0x1234 217 /// icmp_socket.bind(icmp::Endpoint::Ident(0x1234)).unwrap(); 218 /// ``` 219 /// 220 /// [is_specified]: enum.IcmpEndpoint.html#method.is_specified 221 /// [IcmpEndpoint::Ident]: enum.IcmpEndpoint.html#variant.Ident 222 /// [IcmpEndpoint::Udp]: enum.IcmpEndpoint.html#variant.Udp 223 /// [send]: #method.send 224 /// [recv]: #method.recv bind<T: Into<Endpoint>>(&mut self, endpoint: T) -> Result<(), BindError>225 pub fn bind<T: Into<Endpoint>>(&mut self, endpoint: T) -> Result<(), BindError> { 226 let endpoint = endpoint.into(); 227 if !endpoint.is_specified() { 228 return Err(BindError::Unaddressable); 229 } 230 231 if self.is_open() { 232 return Err(BindError::InvalidState); 233 } 234 235 self.endpoint = endpoint; 236 237 #[cfg(feature = "async")] 238 { 239 self.rx_waker.wake(); 240 self.tx_waker.wake(); 241 } 242 243 Ok(()) 244 } 245 246 /// Check whether the transmit buffer is full. 247 #[inline] can_send(&self) -> bool248 pub fn can_send(&self) -> bool { 249 !self.tx_buffer.is_full() 250 } 251 252 /// Check whether the receive buffer is not empty. 253 #[inline] can_recv(&self) -> bool254 pub fn can_recv(&self) -> bool { 255 !self.rx_buffer.is_empty() 256 } 257 258 /// Return the maximum number packets the socket can receive. 259 #[inline] packet_recv_capacity(&self) -> usize260 pub fn packet_recv_capacity(&self) -> usize { 261 self.rx_buffer.packet_capacity() 262 } 263 264 /// Return the maximum number packets the socket can transmit. 265 #[inline] packet_send_capacity(&self) -> usize266 pub fn packet_send_capacity(&self) -> usize { 267 self.tx_buffer.packet_capacity() 268 } 269 270 /// Return the maximum number of bytes inside the recv buffer. 271 #[inline] payload_recv_capacity(&self) -> usize272 pub fn payload_recv_capacity(&self) -> usize { 273 self.rx_buffer.payload_capacity() 274 } 275 276 /// Return the maximum number of bytes inside the transmit buffer. 277 #[inline] payload_send_capacity(&self) -> usize278 pub fn payload_send_capacity(&self) -> usize { 279 self.tx_buffer.payload_capacity() 280 } 281 282 /// Check whether the socket is open. 283 #[inline] is_open(&self) -> bool284 pub fn is_open(&self) -> bool { 285 self.endpoint != Endpoint::Unspecified 286 } 287 288 /// Enqueue a packet to be sent to a given remote address, and return a pointer 289 /// to its payload. 290 /// 291 /// This function returns `Err(Error::Exhausted)` if the transmit buffer is full, 292 /// `Err(Error::Truncated)` if the requested size is larger than the packet buffer 293 /// size, and `Err(Error::Unaddressable)` if the remote address is unspecified. send(&mut self, size: usize, endpoint: IpAddress) -> Result<&mut [u8], SendError>294 pub fn send(&mut self, size: usize, endpoint: IpAddress) -> Result<&mut [u8], SendError> { 295 if endpoint.is_unspecified() { 296 return Err(SendError::Unaddressable); 297 } 298 299 let packet_buf = self 300 .tx_buffer 301 .enqueue(size, endpoint) 302 .map_err(|_| SendError::BufferFull)?; 303 304 net_trace!("icmp:{}: buffer to send {} octets", endpoint, size); 305 Ok(packet_buf) 306 } 307 308 /// Enqueue a packet to be send to a given remote address and pass the buffer 309 /// to the provided closure. The closure then returns the size of the data written 310 /// into the buffer. 311 /// 312 /// Also see [send](#method.send). send_with<F>( &mut self, max_size: usize, endpoint: IpAddress, f: F, ) -> Result<usize, SendError> where F: FnOnce(&mut [u8]) -> usize,313 pub fn send_with<F>( 314 &mut self, 315 max_size: usize, 316 endpoint: IpAddress, 317 f: F, 318 ) -> Result<usize, SendError> 319 where 320 F: FnOnce(&mut [u8]) -> usize, 321 { 322 if endpoint.is_unspecified() { 323 return Err(SendError::Unaddressable); 324 } 325 326 let size = self 327 .tx_buffer 328 .enqueue_with_infallible(max_size, endpoint, f) 329 .map_err(|_| SendError::BufferFull)?; 330 331 net_trace!("icmp:{}: buffer to send {} octets", endpoint, size); 332 Ok(size) 333 } 334 335 /// Enqueue a packet to be sent to a given remote address, and fill it from a slice. 336 /// 337 /// See also [send](#method.send). send_slice(&mut self, data: &[u8], endpoint: IpAddress) -> Result<(), SendError>338 pub fn send_slice(&mut self, data: &[u8], endpoint: IpAddress) -> Result<(), SendError> { 339 let packet_buf = self.send(data.len(), endpoint)?; 340 packet_buf.copy_from_slice(data); 341 Ok(()) 342 } 343 344 /// Dequeue a packet received from a remote endpoint, and return the `IpAddress` as well 345 /// as a pointer to the payload. 346 /// 347 /// This function returns `Err(Error::Exhausted)` if the receive buffer is empty. recv(&mut self) -> Result<(&[u8], IpAddress), RecvError>348 pub fn recv(&mut self) -> Result<(&[u8], IpAddress), RecvError> { 349 let (endpoint, packet_buf) = self.rx_buffer.dequeue().map_err(|_| RecvError::Exhausted)?; 350 351 net_trace!( 352 "icmp:{}: receive {} buffered octets", 353 endpoint, 354 packet_buf.len() 355 ); 356 Ok((packet_buf, endpoint)) 357 } 358 359 /// Dequeue a packet received from a remote endpoint, copy the payload into the given slice, 360 /// and return the amount of octets copied as well as the `IpAddress` 361 /// 362 /// See also [recv](#method.recv). recv_slice(&mut self, data: &mut [u8]) -> Result<(usize, IpAddress), RecvError>363 pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<(usize, IpAddress), RecvError> { 364 let (buffer, endpoint) = self.recv()?; 365 let length = cmp::min(data.len(), buffer.len()); 366 data[..length].copy_from_slice(&buffer[..length]); 367 Ok((length, endpoint)) 368 } 369 370 /// Filter determining which packets received by the interface are appended to 371 /// the given sockets received buffer. accepts(&self, cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr) -> bool372 pub(crate) fn accepts(&self, cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr) -> bool { 373 match (&self.endpoint, icmp_repr) { 374 // If we are bound to ICMP errors associated to a UDP port, only 375 // accept Destination Unreachable or Time Exceeded messages with 376 // the data containing a UDP packet send from the local port we 377 // are bound to. 378 #[cfg(feature = "proto-ipv4")] 379 ( 380 &Endpoint::Udp(endpoint), 381 &IcmpRepr::Ipv4( 382 Icmpv4Repr::DstUnreachable { data, header, .. } 383 | Icmpv4Repr::TimeExceeded { data, header, .. }, 384 ), 385 ) if endpoint.addr.is_none() || endpoint.addr == Some(ip_repr.dst_addr()) => { 386 let packet = UdpPacket::new_unchecked(data); 387 match UdpRepr::parse( 388 &packet, 389 &header.src_addr.into(), 390 &header.dst_addr.into(), 391 &cx.checksum_caps(), 392 ) { 393 Ok(repr) => endpoint.port == repr.src_port, 394 Err(_) => false, 395 } 396 } 397 #[cfg(feature = "proto-ipv6")] 398 ( 399 &Endpoint::Udp(endpoint), 400 &IcmpRepr::Ipv6( 401 Icmpv6Repr::DstUnreachable { data, header, .. } 402 | Icmpv6Repr::TimeExceeded { data, header, .. }, 403 ), 404 ) if endpoint.addr.is_none() || endpoint.addr == Some(ip_repr.dst_addr()) => { 405 let packet = UdpPacket::new_unchecked(data); 406 match UdpRepr::parse( 407 &packet, 408 &header.src_addr.into(), 409 &header.dst_addr.into(), 410 &cx.checksum_caps(), 411 ) { 412 Ok(repr) => endpoint.port == repr.src_port, 413 Err(_) => false, 414 } 415 } 416 // If we are bound to a specific ICMP identifier value, only accept an 417 // Echo Request/Reply with the identifier field matching the endpoint 418 // port. 419 #[cfg(feature = "proto-ipv4")] 420 ( 421 &Endpoint::Ident(bound_ident), 422 &IcmpRepr::Ipv4(Icmpv4Repr::EchoRequest { ident, .. }), 423 ) 424 | ( 425 &Endpoint::Ident(bound_ident), 426 &IcmpRepr::Ipv4(Icmpv4Repr::EchoReply { ident, .. }), 427 ) => ident == bound_ident, 428 #[cfg(feature = "proto-ipv6")] 429 ( 430 &Endpoint::Ident(bound_ident), 431 &IcmpRepr::Ipv6(Icmpv6Repr::EchoRequest { ident, .. }), 432 ) 433 | ( 434 &Endpoint::Ident(bound_ident), 435 &IcmpRepr::Ipv6(Icmpv6Repr::EchoReply { ident, .. }), 436 ) => ident == bound_ident, 437 _ => false, 438 } 439 } 440 process(&mut self, _cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr)441 pub(crate) fn process(&mut self, _cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr) { 442 match *icmp_repr { 443 #[cfg(feature = "proto-ipv4")] 444 IcmpRepr::Ipv4(icmp_repr) => { 445 net_trace!("icmp: receiving {} octets", icmp_repr.buffer_len()); 446 447 match self 448 .rx_buffer 449 .enqueue(icmp_repr.buffer_len(), ip_repr.src_addr()) 450 { 451 Ok(packet_buf) => { 452 icmp_repr.emit( 453 &mut Icmpv4Packet::new_unchecked(packet_buf), 454 &ChecksumCapabilities::default(), 455 ); 456 } 457 Err(_) => net_trace!("icmp: buffer full, dropped incoming packet"), 458 } 459 } 460 #[cfg(feature = "proto-ipv6")] 461 IcmpRepr::Ipv6(icmp_repr) => { 462 net_trace!("icmp: receiving {} octets", icmp_repr.buffer_len()); 463 464 match self 465 .rx_buffer 466 .enqueue(icmp_repr.buffer_len(), ip_repr.src_addr()) 467 { 468 Ok(packet_buf) => icmp_repr.emit( 469 &ip_repr.src_addr(), 470 &ip_repr.dst_addr(), 471 &mut Icmpv6Packet::new_unchecked(packet_buf), 472 &ChecksumCapabilities::default(), 473 ), 474 Err(_) => net_trace!("icmp: buffer full, dropped incoming packet"), 475 } 476 } 477 } 478 479 #[cfg(feature = "async")] 480 self.rx_waker.wake(); 481 } 482 dispatch<F, E>(&mut self, cx: &mut Context, emit: F) -> Result<(), E> where F: FnOnce(&mut Context, (IpRepr, IcmpRepr)) -> Result<(), E>,483 pub(crate) fn dispatch<F, E>(&mut self, cx: &mut Context, emit: F) -> Result<(), E> 484 where 485 F: FnOnce(&mut Context, (IpRepr, IcmpRepr)) -> Result<(), E>, 486 { 487 let hop_limit = self.hop_limit.unwrap_or(64); 488 let res = self.tx_buffer.dequeue_with(|remote_endpoint, packet_buf| { 489 net_trace!( 490 "icmp:{}: sending {} octets", 491 remote_endpoint, 492 packet_buf.len() 493 ); 494 match *remote_endpoint { 495 #[cfg(feature = "proto-ipv4")] 496 IpAddress::Ipv4(dst_addr) => { 497 let src_addr = match cx.get_source_address_ipv4(dst_addr) { 498 Some(addr) => addr, 499 None => { 500 net_trace!( 501 "icmp:{}: not find suitable source address, dropping", 502 remote_endpoint 503 ); 504 return Ok(()); 505 } 506 }; 507 let packet = Icmpv4Packet::new_unchecked(&*packet_buf); 508 let repr = match Icmpv4Repr::parse(&packet, &ChecksumCapabilities::ignored()) { 509 Ok(x) => x, 510 Err(_) => { 511 net_trace!( 512 "icmp:{}: malformed packet in queue, dropping", 513 remote_endpoint 514 ); 515 return Ok(()); 516 } 517 }; 518 let ip_repr = IpRepr::Ipv4(Ipv4Repr { 519 src_addr, 520 dst_addr, 521 next_header: IpProtocol::Icmp, 522 payload_len: repr.buffer_len(), 523 hop_limit: hop_limit, 524 }); 525 emit(cx, (ip_repr, IcmpRepr::Ipv4(repr))) 526 } 527 #[cfg(feature = "proto-ipv6")] 528 IpAddress::Ipv6(dst_addr) => { 529 let src_addr = match cx.get_source_address_ipv6(dst_addr) { 530 Some(addr) => addr, 531 None => { 532 net_trace!( 533 "icmp:{}: not find suitable source address, dropping", 534 remote_endpoint 535 ); 536 return Ok(()); 537 } 538 }; 539 let packet = Icmpv6Packet::new_unchecked(&*packet_buf); 540 let repr = match Icmpv6Repr::parse( 541 &src_addr.into(), 542 &dst_addr.into(), 543 &packet, 544 &ChecksumCapabilities::ignored(), 545 ) { 546 Ok(x) => x, 547 Err(_) => { 548 net_trace!( 549 "icmp:{}: malformed packet in queue, dropping", 550 remote_endpoint 551 ); 552 return Ok(()); 553 } 554 }; 555 let ip_repr = IpRepr::Ipv6(Ipv6Repr { 556 src_addr, 557 dst_addr, 558 next_header: IpProtocol::Icmpv6, 559 payload_len: repr.buffer_len(), 560 hop_limit: hop_limit, 561 }); 562 emit(cx, (ip_repr, IcmpRepr::Ipv6(repr))) 563 } 564 } 565 }); 566 match res { 567 Err(Empty) => Ok(()), 568 Ok(Err(e)) => Err(e), 569 Ok(Ok(())) => { 570 #[cfg(feature = "async")] 571 self.tx_waker.wake(); 572 Ok(()) 573 } 574 } 575 } 576 poll_at(&self, _cx: &mut Context) -> PollAt577 pub(crate) fn poll_at(&self, _cx: &mut Context) -> PollAt { 578 if self.tx_buffer.is_empty() { 579 PollAt::Ingress 580 } else { 581 PollAt::Now 582 } 583 } 584 } 585 586 #[cfg(test)] 587 mod tests_common { 588 pub use super::*; 589 pub use crate::phy::DeviceCapabilities; 590 pub use crate::wire::IpAddress; 591 buffer(packets: usize) -> PacketBuffer<'static>592 pub fn buffer(packets: usize) -> PacketBuffer<'static> { 593 PacketBuffer::new(vec![PacketMetadata::EMPTY; packets], vec![0; 66 * packets]) 594 } 595 socket( rx_buffer: PacketBuffer<'static>, tx_buffer: PacketBuffer<'static>, ) -> Socket<'static>596 pub fn socket( 597 rx_buffer: PacketBuffer<'static>, 598 tx_buffer: PacketBuffer<'static>, 599 ) -> Socket<'static> { 600 Socket::new(rx_buffer, tx_buffer) 601 } 602 603 pub const LOCAL_PORT: u16 = 53; 604 605 pub static UDP_REPR: UdpRepr = UdpRepr { 606 src_port: 53, 607 dst_port: 9090, 608 }; 609 610 pub static UDP_PAYLOAD: &[u8] = &[0xff; 10]; 611 } 612 613 #[cfg(all(test, feature = "proto-ipv4"))] 614 mod test_ipv4 { 615 use super::tests_common::*; 616 use crate::wire::{Icmpv4DstUnreachable, IpEndpoint, Ipv4Address}; 617 618 const REMOTE_IPV4: Ipv4Address = Ipv4Address([192, 168, 1, 2]); 619 const LOCAL_IPV4: Ipv4Address = Ipv4Address([192, 168, 1, 1]); 620 const LOCAL_END_V4: IpEndpoint = IpEndpoint { 621 addr: IpAddress::Ipv4(LOCAL_IPV4), 622 port: LOCAL_PORT, 623 }; 624 625 static ECHOV4_REPR: Icmpv4Repr = Icmpv4Repr::EchoRequest { 626 ident: 0x1234, 627 seq_no: 0x5678, 628 data: &[0xff; 16], 629 }; 630 631 static LOCAL_IPV4_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr { 632 src_addr: LOCAL_IPV4, 633 dst_addr: REMOTE_IPV4, 634 next_header: IpProtocol::Icmp, 635 payload_len: 24, 636 hop_limit: 0x40, 637 }); 638 639 static REMOTE_IPV4_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr { 640 src_addr: REMOTE_IPV4, 641 dst_addr: LOCAL_IPV4, 642 next_header: IpProtocol::Icmp, 643 payload_len: 24, 644 hop_limit: 0x40, 645 }); 646 647 #[test] test_send_unaddressable()648 fn test_send_unaddressable() { 649 let mut socket = socket(buffer(0), buffer(1)); 650 assert_eq!( 651 socket.send_slice(b"abcdef", IpAddress::Ipv4(Ipv4Address::default())), 652 Err(SendError::Unaddressable) 653 ); 654 assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV4.into()), Ok(())); 655 } 656 657 #[test] test_send_dispatch()658 fn test_send_dispatch() { 659 let mut socket = socket(buffer(0), buffer(1)); 660 let mut cx = Context::mock(); 661 let checksum = ChecksumCapabilities::default(); 662 663 assert_eq!( 664 socket.dispatch(&mut cx, |_, _| unreachable!()), 665 Ok::<_, ()>(()) 666 ); 667 668 // This buffer is too long 669 assert_eq!( 670 socket.send_slice(&[0xff; 67], REMOTE_IPV4.into()), 671 Err(SendError::BufferFull) 672 ); 673 assert!(socket.can_send()); 674 675 let mut bytes = [0xff; 24]; 676 let mut packet = Icmpv4Packet::new_unchecked(&mut bytes); 677 ECHOV4_REPR.emit(&mut packet, &checksum); 678 679 assert_eq!( 680 socket.send_slice(&*packet.into_inner(), REMOTE_IPV4.into()), 681 Ok(()) 682 ); 683 assert_eq!( 684 socket.send_slice(b"123456", REMOTE_IPV4.into()), 685 Err(SendError::BufferFull) 686 ); 687 assert!(!socket.can_send()); 688 689 assert_eq!( 690 socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| { 691 assert_eq!(ip_repr, LOCAL_IPV4_REPR); 692 assert_eq!(icmp_repr, ECHOV4_REPR.into()); 693 Err(()) 694 }), 695 Err(()) 696 ); 697 // buffer is not taken off of the tx queue due to the error 698 assert!(!socket.can_send()); 699 700 assert_eq!( 701 socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| { 702 assert_eq!(ip_repr, LOCAL_IPV4_REPR); 703 assert_eq!(icmp_repr, ECHOV4_REPR.into()); 704 Ok::<_, ()>(()) 705 }), 706 Ok(()) 707 ); 708 // buffer is taken off of the queue this time 709 assert!(socket.can_send()); 710 } 711 712 #[test] test_set_hop_limit_v4()713 fn test_set_hop_limit_v4() { 714 let mut s = socket(buffer(0), buffer(1)); 715 let mut cx = Context::mock(); 716 let checksum = ChecksumCapabilities::default(); 717 718 let mut bytes = [0xff; 24]; 719 let mut packet = Icmpv4Packet::new_unchecked(&mut bytes); 720 ECHOV4_REPR.emit(&mut packet, &checksum); 721 722 s.set_hop_limit(Some(0x2a)); 723 724 assert_eq!( 725 s.send_slice(&*packet.into_inner(), REMOTE_IPV4.into()), 726 Ok(()) 727 ); 728 assert_eq!( 729 s.dispatch(&mut cx, |_, (ip_repr, _)| { 730 assert_eq!( 731 ip_repr, 732 IpRepr::Ipv4(Ipv4Repr { 733 src_addr: LOCAL_IPV4, 734 dst_addr: REMOTE_IPV4, 735 next_header: IpProtocol::Icmp, 736 payload_len: ECHOV4_REPR.buffer_len(), 737 hop_limit: 0x2a, 738 }) 739 ); 740 Ok::<_, ()>(()) 741 }), 742 Ok(()) 743 ); 744 } 745 746 #[test] test_recv_process()747 fn test_recv_process() { 748 let mut socket = socket(buffer(1), buffer(1)); 749 let mut cx = Context::mock(); 750 assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(())); 751 752 assert!(!socket.can_recv()); 753 assert_eq!(socket.recv(), Err(RecvError::Exhausted)); 754 755 let checksum = ChecksumCapabilities::default(); 756 757 let mut bytes = [0xff; 24]; 758 let mut packet = Icmpv4Packet::new_unchecked(&mut bytes[..]); 759 ECHOV4_REPR.emit(&mut packet, &checksum); 760 let data = &*packet.into_inner(); 761 762 assert!(socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into())); 763 socket.process(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()); 764 assert!(socket.can_recv()); 765 766 assert!(socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into())); 767 socket.process(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()); 768 769 assert_eq!(socket.recv(), Ok((data, REMOTE_IPV4.into()))); 770 assert!(!socket.can_recv()); 771 } 772 773 #[test] test_accept_bad_id()774 fn test_accept_bad_id() { 775 let mut socket = socket(buffer(1), buffer(1)); 776 let mut cx = Context::mock(); 777 assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(())); 778 779 let checksum = ChecksumCapabilities::default(); 780 let mut bytes = [0xff; 20]; 781 let mut packet = Icmpv4Packet::new_unchecked(&mut bytes); 782 let icmp_repr = Icmpv4Repr::EchoRequest { 783 ident: 0x4321, 784 seq_no: 0x5678, 785 data: &[0xff; 16], 786 }; 787 icmp_repr.emit(&mut packet, &checksum); 788 789 // Ensure that a packet with an identifier that isn't the bound 790 // ID is not accepted 791 assert!(!socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &icmp_repr.into())); 792 } 793 794 #[test] test_accepts_udp()795 fn test_accepts_udp() { 796 let mut socket = socket(buffer(1), buffer(1)); 797 let mut cx = Context::mock(); 798 assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END_V4.into())), Ok(())); 799 800 let checksum = ChecksumCapabilities::default(); 801 802 let mut bytes = [0xff; 18]; 803 let mut packet = UdpPacket::new_unchecked(&mut bytes); 804 UDP_REPR.emit( 805 &mut packet, 806 &REMOTE_IPV4.into(), 807 &LOCAL_IPV4.into(), 808 UDP_PAYLOAD.len(), 809 |buf| buf.copy_from_slice(UDP_PAYLOAD), 810 &checksum, 811 ); 812 813 let data = &*packet.into_inner(); 814 815 let icmp_repr = Icmpv4Repr::DstUnreachable { 816 reason: Icmpv4DstUnreachable::PortUnreachable, 817 header: Ipv4Repr { 818 src_addr: LOCAL_IPV4, 819 dst_addr: REMOTE_IPV4, 820 next_header: IpProtocol::Icmp, 821 payload_len: 12, 822 hop_limit: 0x40, 823 }, 824 data: data, 825 }; 826 let ip_repr = IpRepr::Ipv4(Ipv4Repr { 827 src_addr: REMOTE_IPV4, 828 dst_addr: LOCAL_IPV4, 829 next_header: IpProtocol::Icmp, 830 payload_len: icmp_repr.buffer_len(), 831 hop_limit: 0x40, 832 }); 833 834 assert!(!socket.can_recv()); 835 836 // Ensure we can accept ICMP error response to the bound 837 // UDP port 838 assert!(socket.accepts(&mut cx, &ip_repr, &icmp_repr.into())); 839 socket.process(&mut cx, &ip_repr, &icmp_repr.into()); 840 assert!(socket.can_recv()); 841 842 let mut bytes = [0x00; 46]; 843 let mut packet = Icmpv4Packet::new_unchecked(&mut bytes[..]); 844 icmp_repr.emit(&mut packet, &checksum); 845 assert_eq!( 846 socket.recv(), 847 Ok((&*packet.into_inner(), REMOTE_IPV4.into())) 848 ); 849 assert!(!socket.can_recv()); 850 } 851 } 852 853 #[cfg(all(test, feature = "proto-ipv6"))] 854 mod test_ipv6 { 855 use super::tests_common::*; 856 857 use crate::wire::{Icmpv6DstUnreachable, IpEndpoint, Ipv6Address}; 858 859 const REMOTE_IPV6: Ipv6Address = 860 Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]); 861 const LOCAL_IPV6: Ipv6Address = 862 Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); 863 const LOCAL_END_V6: IpEndpoint = IpEndpoint { 864 addr: IpAddress::Ipv6(LOCAL_IPV6), 865 port: LOCAL_PORT, 866 }; 867 static ECHOV6_REPR: Icmpv6Repr = Icmpv6Repr::EchoRequest { 868 ident: 0x1234, 869 seq_no: 0x5678, 870 data: &[0xff; 16], 871 }; 872 873 static LOCAL_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr { 874 src_addr: LOCAL_IPV6, 875 dst_addr: REMOTE_IPV6, 876 next_header: IpProtocol::Icmpv6, 877 payload_len: 24, 878 hop_limit: 0x40, 879 }); 880 881 static REMOTE_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr { 882 src_addr: REMOTE_IPV6, 883 dst_addr: LOCAL_IPV6, 884 next_header: IpProtocol::Icmpv6, 885 payload_len: 24, 886 hop_limit: 0x40, 887 }); 888 889 #[test] test_send_unaddressable()890 fn test_send_unaddressable() { 891 let mut socket = socket(buffer(0), buffer(1)); 892 assert_eq!( 893 socket.send_slice(b"abcdef", IpAddress::Ipv6(Ipv6Address::default())), 894 Err(SendError::Unaddressable) 895 ); 896 assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV6.into()), Ok(())); 897 } 898 899 #[test] test_send_dispatch()900 fn test_send_dispatch() { 901 let mut socket = socket(buffer(0), buffer(1)); 902 let mut cx = Context::mock(); 903 let checksum = ChecksumCapabilities::default(); 904 905 assert_eq!( 906 socket.dispatch(&mut cx, |_, _| unreachable!()), 907 Ok::<_, ()>(()) 908 ); 909 910 // This buffer is too long 911 assert_eq!( 912 socket.send_slice(&[0xff; 67], REMOTE_IPV6.into()), 913 Err(SendError::BufferFull) 914 ); 915 assert!(socket.can_send()); 916 917 let mut bytes = vec![0xff; 24]; 918 let mut packet = Icmpv6Packet::new_unchecked(&mut bytes); 919 ECHOV6_REPR.emit( 920 &LOCAL_IPV6.into(), 921 &REMOTE_IPV6.into(), 922 &mut packet, 923 &checksum, 924 ); 925 926 assert_eq!( 927 socket.send_slice(&*packet.into_inner(), REMOTE_IPV6.into()), 928 Ok(()) 929 ); 930 assert_eq!( 931 socket.send_slice(b"123456", REMOTE_IPV6.into()), 932 Err(SendError::BufferFull) 933 ); 934 assert!(!socket.can_send()); 935 936 assert_eq!( 937 socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| { 938 assert_eq!(ip_repr, LOCAL_IPV6_REPR); 939 assert_eq!(icmp_repr, ECHOV6_REPR.into()); 940 Err(()) 941 }), 942 Err(()) 943 ); 944 // buffer is not taken off of the tx queue due to the error 945 assert!(!socket.can_send()); 946 947 assert_eq!( 948 socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| { 949 assert_eq!(ip_repr, LOCAL_IPV6_REPR); 950 assert_eq!(icmp_repr, ECHOV6_REPR.into()); 951 Ok::<_, ()>(()) 952 }), 953 Ok(()) 954 ); 955 // buffer is taken off of the queue this time 956 assert!(socket.can_send()); 957 } 958 959 #[test] test_set_hop_limit()960 fn test_set_hop_limit() { 961 let mut s = socket(buffer(0), buffer(1)); 962 let mut cx = Context::mock(); 963 let checksum = ChecksumCapabilities::default(); 964 965 let mut bytes = vec![0xff; 24]; 966 let mut packet = Icmpv6Packet::new_unchecked(&mut bytes); 967 ECHOV6_REPR.emit( 968 &LOCAL_IPV6.into(), 969 &REMOTE_IPV6.into(), 970 &mut packet, 971 &checksum, 972 ); 973 974 s.set_hop_limit(Some(0x2a)); 975 976 assert_eq!( 977 s.send_slice(&*packet.into_inner(), REMOTE_IPV6.into()), 978 Ok(()) 979 ); 980 assert_eq!( 981 s.dispatch(&mut cx, |_, (ip_repr, _)| { 982 assert_eq!( 983 ip_repr, 984 IpRepr::Ipv6(Ipv6Repr { 985 src_addr: LOCAL_IPV6, 986 dst_addr: REMOTE_IPV6, 987 next_header: IpProtocol::Icmpv6, 988 payload_len: ECHOV6_REPR.buffer_len(), 989 hop_limit: 0x2a, 990 }) 991 ); 992 Ok::<_, ()>(()) 993 }), 994 Ok(()) 995 ); 996 } 997 998 #[test] test_recv_process()999 fn test_recv_process() { 1000 let mut socket = socket(buffer(1), buffer(1)); 1001 let mut cx = Context::mock(); 1002 assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(())); 1003 1004 assert!(!socket.can_recv()); 1005 assert_eq!(socket.recv(), Err(RecvError::Exhausted)); 1006 1007 let checksum = ChecksumCapabilities::default(); 1008 1009 let mut bytes = [0xff; 24]; 1010 let mut packet = Icmpv6Packet::new_unchecked(&mut bytes[..]); 1011 ECHOV6_REPR.emit( 1012 &LOCAL_IPV6.into(), 1013 &REMOTE_IPV6.into(), 1014 &mut packet, 1015 &checksum, 1016 ); 1017 let data = &*packet.into_inner(); 1018 1019 assert!(socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into())); 1020 socket.process(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()); 1021 assert!(socket.can_recv()); 1022 1023 assert!(socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into())); 1024 socket.process(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()); 1025 1026 assert_eq!(socket.recv(), Ok((data, REMOTE_IPV6.into()))); 1027 assert!(!socket.can_recv()); 1028 } 1029 1030 #[test] test_accept_bad_id()1031 fn test_accept_bad_id() { 1032 let mut socket = socket(buffer(1), buffer(1)); 1033 let mut cx = Context::mock(); 1034 assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(())); 1035 1036 let checksum = ChecksumCapabilities::default(); 1037 let mut bytes = [0xff; 20]; 1038 let mut packet = Icmpv6Packet::new_unchecked(&mut bytes); 1039 let icmp_repr = Icmpv6Repr::EchoRequest { 1040 ident: 0x4321, 1041 seq_no: 0x5678, 1042 data: &[0xff; 16], 1043 }; 1044 icmp_repr.emit( 1045 &LOCAL_IPV6.into(), 1046 &REMOTE_IPV6.into(), 1047 &mut packet, 1048 &checksum, 1049 ); 1050 1051 // Ensure that a packet with an identifier that isn't the bound 1052 // ID is not accepted 1053 assert!(!socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &icmp_repr.into())); 1054 } 1055 1056 #[test] test_accepts_udp()1057 fn test_accepts_udp() { 1058 let mut socket = socket(buffer(1), buffer(1)); 1059 let mut cx = Context::mock(); 1060 assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END_V6.into())), Ok(())); 1061 1062 let checksum = ChecksumCapabilities::default(); 1063 1064 let mut bytes = [0xff; 18]; 1065 let mut packet = UdpPacket::new_unchecked(&mut bytes); 1066 UDP_REPR.emit( 1067 &mut packet, 1068 &REMOTE_IPV6.into(), 1069 &LOCAL_IPV6.into(), 1070 UDP_PAYLOAD.len(), 1071 |buf| buf.copy_from_slice(UDP_PAYLOAD), 1072 &checksum, 1073 ); 1074 1075 let data = &*packet.into_inner(); 1076 1077 let icmp_repr = Icmpv6Repr::DstUnreachable { 1078 reason: Icmpv6DstUnreachable::PortUnreachable, 1079 header: Ipv6Repr { 1080 src_addr: LOCAL_IPV6, 1081 dst_addr: REMOTE_IPV6, 1082 next_header: IpProtocol::Icmpv6, 1083 payload_len: 12, 1084 hop_limit: 0x40, 1085 }, 1086 data: data, 1087 }; 1088 let ip_repr = IpRepr::Ipv6(Ipv6Repr { 1089 src_addr: REMOTE_IPV6, 1090 dst_addr: LOCAL_IPV6, 1091 next_header: IpProtocol::Icmpv6, 1092 payload_len: icmp_repr.buffer_len(), 1093 hop_limit: 0x40, 1094 }); 1095 1096 assert!(!socket.can_recv()); 1097 1098 // Ensure we can accept ICMP error response to the bound 1099 // UDP port 1100 assert!(socket.accepts(&mut cx, &ip_repr, &icmp_repr.into())); 1101 socket.process(&mut cx, &ip_repr, &icmp_repr.into()); 1102 assert!(socket.can_recv()); 1103 1104 let mut bytes = [0x00; 66]; 1105 let mut packet = Icmpv6Packet::new_unchecked(&mut bytes[..]); 1106 icmp_repr.emit( 1107 &LOCAL_IPV6.into(), 1108 &REMOTE_IPV6.into(), 1109 &mut packet, 1110 &checksum, 1111 ); 1112 assert_eq!( 1113 socket.recv(), 1114 Ok((&*packet.into_inner(), REMOTE_IPV6.into())) 1115 ); 1116 assert!(!socket.can_recv()); 1117 } 1118 } 1119