瀏覽代碼

Remove IpRepr::Unspecified and lowering.

Choosing the right source IP address is now responsibility of the individual sockets.
Dario Nieuwenhuis 3 年之前
父節點
當前提交
5989896299
共有 8 個文件被更改,包括 221 次插入527 次删除
  1. 1 0
      Cargo.toml
  2. 14 8
      src/iface/interface.rs
  3. 8 8
      src/socket/icmp.rs
  4. 77 57
      src/socket/tcp.rs
  5. 72 82
      src/socket/udp.rs
  6. 35 372
      src/wire/ip.rs
  7. 7 0
      src/wire/ipv4.rs
  8. 7 0
      src/wire/ipv6.rs

+ 1 - 0
Cargo.toml

@@ -22,6 +22,7 @@ log = { version = "0.4.4", default-features = false, optional = true }
 libc = { version = "0.2.18", optional = true }
 bitflags = { version = "1.0", default-features = false }
 defmt = { version = "0.3", optional = true }
+cfg-if = "1.0.0"
 
 [dev-dependencies]
 env_logger = "0.9"

+ 14 - 8
src/iface/interface.rs

@@ -923,7 +923,8 @@ where
                     (IpRepr::Ipv6(ipv6_repr), IcmpRepr::Ipv6(icmpv6_repr)) => {
                         respond!(inner, IpPacket::Icmpv6((ipv6_repr, icmpv6_repr)))
                     }
-                    _ => Err(Error::Unaddressable),
+                    #[allow(unreachable_patterns)]
+                    _ => unreachable!(),
                 }),
                 #[cfg(feature = "socket-udp")]
                 Socket::Udp(socket) => socket.dispatch(inner, |inner, response| {
@@ -1811,7 +1812,8 @@ impl<'a> InterfaceInner<'a> {
                     };
                     Ok(self.icmpv6_reply(ipv6_repr, icmp_reply_repr))
                 }
-                _ => Err(Error::Unrecognized),
+                #[allow(unreachable_patterns)]
+                _ => unreachable!(),
             },
 
             // Ignore any echo replies.
@@ -1821,7 +1823,8 @@ impl<'a> InterfaceInner<'a> {
             #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
             Icmpv6Repr::Ndisc(repr) if ip_repr.hop_limit() == 0xff => match ip_repr {
                 IpRepr::Ipv6(ipv6_repr) => self.process_ndisc(ipv6_repr, repr),
-                _ => Ok(None),
+                #[allow(unreachable_patterns)]
+                _ => unreachable!(),
             },
 
             // Don't report an error if a packet with unknown type
@@ -1996,7 +1999,8 @@ impl<'a> InterfaceInner<'a> {
                 };
                 match ip_repr {
                     IpRepr::Ipv4(ipv4_repr) => Ok(self.icmpv4_reply(ipv4_repr, icmp_reply_repr)),
-                    _ => Err(Error::Unrecognized),
+                    #[allow(unreachable_patterns)]
+                    _ => unreachable!(),
                 }
             }
 
@@ -2133,7 +2137,6 @@ impl<'a> InterfaceInner<'a> {
                 };
                 Ok(self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr))
             }
-            IpRepr::Unspecified { .. } => Err(Error::Unaddressable),
         }
     }
 
@@ -2410,7 +2413,9 @@ impl<'a> InterfaceInner<'a> {
     }
 
     fn dispatch_ip<Tx: TxToken>(&mut self, tx_token: Tx, packet: IpPacket) -> Result<()> {
-        let ip_repr = packet.ip_repr().lower(&self.ip_addrs)?;
+        let ip_repr = packet.ip_repr();
+        assert!(!ip_repr.src_addr().is_unspecified());
+        assert!(!ip_repr.dst_addr().is_unspecified());
 
         match self.caps.medium {
             #[cfg(feature = "medium-ethernet")]
@@ -2433,7 +2438,6 @@ impl<'a> InterfaceInner<'a> {
                         IpRepr::Ipv4(_) => frame.set_ethertype(EthernetProtocol::Ipv4),
                         #[cfg(feature = "proto-ipv6")]
                         IpRepr::Ipv6(_) => frame.set_ethertype(EthernetProtocol::Ipv6),
-                        _ => return,
                     }
 
                     ip_repr.emit(frame.payload_mut(), &caps.checksum);
@@ -2463,7 +2467,9 @@ impl<'a> InterfaceInner<'a> {
 
     #[cfg(feature = "medium-ieee802154")]
     fn dispatch_ieee802154<Tx: TxToken>(&mut self, tx_token: Tx, packet: IpPacket) -> Result<()> {
-        let ip_repr = packet.ip_repr().lower(&self.ip_addrs)?;
+        let ip_repr = packet.ip_repr();
+        assert!(!ip_repr.src_addr().is_unspecified());
+        assert!(!ip_repr.dst_addr().is_unspecified());
 
         match self.caps.medium {
             #[cfg(feature = "medium-ieee802154")]

+ 8 - 8
src/socket/icmp.rs

@@ -747,13 +747,13 @@ mod test_ipv4 {
             },
             data: data,
         };
-        let ip_repr = IpRepr::Unspecified {
-            src_addr: REMOTE_IPV4.into(),
-            dst_addr: LOCAL_IPV4.into(),
+        let ip_repr = IpRepr::Ipv4(Ipv4Repr {
+            src_addr: REMOTE_IPV4,
+            dst_addr: LOCAL_IPV4,
             next_header: IpProtocol::Icmp,
             payload_len: icmp_repr.buffer_len(),
             hop_limit: 0x40,
-        };
+        });
 
         assert!(!socket.can_recv());
 
@@ -1015,13 +1015,13 @@ mod test_ipv6 {
             },
             data: data,
         };
-        let ip_repr = IpRepr::Unspecified {
-            src_addr: REMOTE_IPV6.into(),
-            dst_addr: LOCAL_IPV6.into(),
+        let ip_repr = IpRepr::Ipv6(Ipv6Repr {
+            src_addr: REMOTE_IPV6,
+            dst_addr: LOCAL_IPV6,
             next_header: IpProtocol::Icmpv6,
             payload_len: icmp_repr.buffer_len(),
             hop_limit: 0x40,
-        };
+        });
 
         assert!(!socket.can_recv());
 

+ 77 - 57
src/socket/tcp.rs

@@ -1137,13 +1137,13 @@ impl<'a> TcpSocket<'a> {
             sack_ranges: [None, None, None],
             payload: &[],
         };
-        let ip_reply_repr = IpRepr::Unspecified {
-            src_addr: ip_repr.dst_addr(),
-            dst_addr: ip_repr.src_addr(),
-            next_header: IpProtocol::Tcp,
-            payload_len: reply_repr.buffer_len(),
-            hop_limit: 64,
-        };
+        let ip_reply_repr = IpRepr::new(
+            ip_repr.dst_addr(),
+            ip_repr.src_addr(),
+            IpProtocol::Tcp,
+            reply_repr.buffer_len(),
+            64,
+        );
         (ip_reply_repr, reply_repr)
     }
 
@@ -2136,14 +2136,13 @@ impl<'a> TcpSocket<'a> {
 
         // Construct the lowered IP representation.
         // We might need this to calculate the MSS, so do it early.
-        let mut ip_repr = IpRepr::Unspecified {
-            src_addr: self.local_endpoint.addr,
-            dst_addr: self.remote_endpoint.addr,
-            next_header: IpProtocol::Tcp,
-            hop_limit: self.hop_limit.unwrap_or(64),
-            payload_len: 0,
-        }
-        .lower(&[])?;
+        let mut ip_repr = IpRepr::new(
+            self.local_endpoint.addr,
+            self.remote_endpoint.addr,
+            IpProtocol::Tcp,
+            0,
+            self.hop_limit.unwrap_or(64),
+        );
 
         // Construct the basic TCP representation, an empty ACK packet.
         // We'll adjust this to be more specific as needed.
@@ -2417,8 +2416,7 @@ impl<'a> fmt::Write for TcpSocket<'a> {
 #[cfg(test)]
 mod test {
     use super::*;
-    use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3, MOCK_UNSPECIFIED};
-    use crate::wire::{IpAddress, IpCidr, IpRepr};
+    use crate::wire::{IpAddress, IpRepr};
     use core::i32;
     use std::ops::{Deref, DerefMut};
     use std::vec::Vec;
@@ -2430,23 +2428,53 @@ mod test {
     const LOCAL_PORT: u16 = 80;
     const REMOTE_PORT: u16 = 49500;
     const LOCAL_END: IpEndpoint = IpEndpoint {
-        addr: MOCK_IP_ADDR_1,
+        addr: LOCAL_ADDR.into_address(),
         port: LOCAL_PORT,
     };
     const REMOTE_END: IpEndpoint = IpEndpoint {
-        addr: MOCK_IP_ADDR_2,
+        addr: REMOTE_ADDR.into_address(),
         port: REMOTE_PORT,
     };
     const LOCAL_SEQ: TcpSeqNumber = TcpSeqNumber(10000);
     const REMOTE_SEQ: TcpSeqNumber = TcpSeqNumber(-10001);
 
-    const SEND_IP_TEMPL: IpRepr = IpRepr::Unspecified {
-        src_addr: MOCK_IP_ADDR_1,
-        dst_addr: MOCK_IP_ADDR_2,
+    cfg_if::cfg_if! {
+        if #[cfg(feature = "proto-ipv4")] {
+            use crate::wire::Ipv4Address as IpvXAddress;
+            use crate::wire::Ipv4Repr as IpvXRepr;
+            use IpRepr::Ipv4 as IpReprIpvX;
+
+            const LOCAL_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 1]);
+            const REMOTE_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 2]);
+            const OTHER_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 3]);
+
+            const BASE_MSS: u16 = 1460;
+        } else {
+            use crate::wire::Ipv6Address as IpvXAddress;
+            use crate::wire::Ipv6Repr as IpvXRepr;
+            use IpRepr::Ipv6 as IpReprIpvX;
+
+            const LOCAL_ADDR: IpvXAddress = IpvXAddress([
+                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+            ]);
+            const REMOTE_ADDR: IpvXAddress = IpvXAddress([
+                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+            ]);
+            const OTHER_ADDR: IpvXAddress = IpvXAddress([
+                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+            ]);
+
+            const BASE_MSS: u16 = 1440;
+        }
+    }
+
+    const SEND_IP_TEMPL: IpRepr = IpReprIpvX(IpvXRepr {
+        src_addr: LOCAL_ADDR,
+        dst_addr: REMOTE_ADDR,
         next_header: IpProtocol::Tcp,
         payload_len: 20,
         hop_limit: 64,
-    };
+    });
     const SEND_TEMPL: TcpRepr<'static> = TcpRepr {
         src_port: REMOTE_PORT,
         dst_port: LOCAL_PORT,
@@ -2460,13 +2488,13 @@ mod test {
         sack_ranges: [None, None, None],
         payload: &[],
     };
-    const _RECV_IP_TEMPL: IpRepr = IpRepr::Unspecified {
-        src_addr: MOCK_IP_ADDR_1,
-        dst_addr: MOCK_IP_ADDR_2,
+    const _RECV_IP_TEMPL: IpRepr = IpReprIpvX(IpvXRepr {
+        src_addr: LOCAL_ADDR,
+        dst_addr: REMOTE_ADDR,
         next_header: IpProtocol::Tcp,
         payload_len: 20,
         hop_limit: 64,
-    };
+    });
     const RECV_TEMPL: TcpRepr<'static> = TcpRepr {
         src_port: LOCAL_PORT,
         dst_port: REMOTE_PORT,
@@ -2481,11 +2509,6 @@ mod test {
         payload: &[],
     };
 
-    #[cfg(feature = "proto-ipv6")]
-    const BASE_MSS: u16 = 1440;
-    #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
-    const BASE_MSS: u16 = 1460;
-
     // =========================================================================================//
     // Helper functions
     // =========================================================================================//
@@ -2515,13 +2538,13 @@ mod test {
     ) -> Result<Option<TcpRepr<'static>>> {
         socket.cx.set_now(timestamp);
 
-        let ip_repr = IpRepr::Unspecified {
-            src_addr: MOCK_IP_ADDR_2,
-            dst_addr: MOCK_IP_ADDR_1,
+        let ip_repr = IpReprIpvX(IpvXRepr {
+            src_addr: REMOTE_ADDR,
+            dst_addr: LOCAL_ADDR,
             next_header: IpProtocol::Tcp,
             payload_len: repr.buffer_len(),
             hop_limit: 64,
-        };
+        });
         net_trace!("send: {}", repr);
 
         assert!(socket.socket.accepts(&mut socket.cx, &ip_repr, repr));
@@ -2545,11 +2568,9 @@ mod test {
         let result = socket
             .socket
             .dispatch(&mut socket.cx, |_, (ip_repr, tcp_repr)| {
-                let ip_repr = ip_repr.lower(&[IpCidr::new(LOCAL_END.addr, 24)]).unwrap();
-
                 assert_eq!(ip_repr.next_header(), IpProtocol::Tcp);
-                assert_eq!(ip_repr.src_addr(), MOCK_IP_ADDR_1);
-                assert_eq!(ip_repr.dst_addr(), MOCK_IP_ADDR_2);
+                assert_eq!(ip_repr.src_addr(), LOCAL_ADDR.into());
+                assert_eq!(ip_repr.dst_addr(), REMOTE_ADDR.into());
                 assert_eq!(ip_repr.payload_len(), tcp_repr.buffer_len());
 
                 net_trace!("recv: {}", tcp_repr);
@@ -3223,12 +3244,12 @@ mod test {
         );
         assert_eq!(
             s.socket
-                .connect(&mut s.cx, REMOTE_END, (MOCK_UNSPECIFIED, 0)),
+                .connect(&mut s.cx, REMOTE_END, (IpvXAddress::UNSPECIFIED, 0)),
             Err(Error::Unaddressable)
         );
         assert_eq!(
             s.socket
-                .connect(&mut s.cx, (MOCK_UNSPECIFIED, 0), LOCAL_END),
+                .connect(&mut s.cx, (IpvXAddress::UNSPECIFIED, 0), LOCAL_END),
             Err(Error::Unaddressable)
         );
         assert_eq!(
@@ -3282,7 +3303,7 @@ mod test {
         let mut s = socket();
         assert_eq!(
             s.socket
-                .connect(&mut s.cx, REMOTE_END, (MOCK_UNSPECIFIED, 80)),
+                .connect(&mut s.cx, REMOTE_END, (IpvXAddress::UNSPECIFIED, 80)),
             Ok(())
         );
         s.abort();
@@ -3298,8 +3319,7 @@ mod test {
     fn test_connect_specified_local() {
         let mut s = socket();
         assert_eq!(
-            s.socket
-                .connect(&mut s.cx, REMOTE_END, (MOCK_IP_ADDR_2, 80)),
+            s.socket.connect(&mut s.cx, REMOTE_END, (REMOTE_ADDR, 80)),
             Ok(())
         );
     }
@@ -6945,31 +6965,31 @@ mod test {
             ..SEND_TEMPL
         };
 
-        let ip_repr = IpRepr::Unspecified {
-            src_addr: MOCK_IP_ADDR_2,
-            dst_addr: MOCK_IP_ADDR_1,
+        let ip_repr = IpReprIpvX(IpvXRepr {
+            src_addr: REMOTE_ADDR,
+            dst_addr: LOCAL_ADDR,
             next_header: IpProtocol::Tcp,
             payload_len: tcp_repr.buffer_len(),
             hop_limit: 64,
-        };
+        });
         assert!(s.socket.accepts(&mut s.cx, &ip_repr, &tcp_repr));
 
-        let ip_repr_wrong_src = IpRepr::Unspecified {
-            src_addr: MOCK_IP_ADDR_3,
-            dst_addr: MOCK_IP_ADDR_1,
+        let ip_repr_wrong_src = IpReprIpvX(IpvXRepr {
+            src_addr: OTHER_ADDR,
+            dst_addr: LOCAL_ADDR,
             next_header: IpProtocol::Tcp,
             payload_len: tcp_repr.buffer_len(),
             hop_limit: 64,
-        };
+        });
         assert!(!s.socket.accepts(&mut s.cx, &ip_repr_wrong_src, &tcp_repr));
 
-        let ip_repr_wrong_dst = IpRepr::Unspecified {
-            src_addr: MOCK_IP_ADDR_2,
-            dst_addr: MOCK_IP_ADDR_3,
+        let ip_repr_wrong_dst = IpReprIpvX(IpvXRepr {
+            src_addr: REMOTE_ADDR,
+            dst_addr: OTHER_ADDR,
             next_header: IpProtocol::Tcp,
             payload_len: tcp_repr.buffer_len(),
             hop_limit: 64,
-        };
+        });
         assert!(!s.socket.accepts(&mut s.cx, &ip_repr_wrong_dst, &tcp_repr));
     }
 

+ 72 - 82
src/socket/udp.rs

@@ -359,13 +359,13 @@ impl<'a> UdpSocket<'a> {
                     src_port: endpoint.port,
                     dst_port: remote_endpoint.port,
                 };
-                let ip_repr = IpRepr::Unspecified {
-                    src_addr: endpoint.addr,
-                    dst_addr: remote_endpoint.addr,
-                    next_header: IpProtocol::Udp,
-                    payload_len: repr.header_len() + payload_buf.len(),
-                    hop_limit: hop_limit,
-                };
+                let ip_repr = IpRepr::new(
+                    endpoint.addr,
+                    remote_endpoint.addr,
+                    IpProtocol::Udp,
+                    repr.header_len() + payload_buf.len(),
+                    hop_limit,
+                );
                 emit(cx, (ip_repr, repr, payload_buf))
             })?;
 
@@ -387,11 +387,6 @@ impl<'a> UdpSocket<'a> {
 #[cfg(test)]
 mod test {
     use super::*;
-    use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3};
-    #[cfg(feature = "proto-ipv4")]
-    use crate::wire::Ipv4Repr;
-    #[cfg(feature = "proto-ipv6")]
-    use crate::wire::Ipv6Repr;
     use crate::wire::{IpAddress, IpRepr, UdpRepr};
 
     fn buffer(packets: usize) -> UdpSocketBuffer<'static> {
@@ -411,22 +406,64 @@ mod test {
     const LOCAL_PORT: u16 = 53;
     const REMOTE_PORT: u16 = 49500;
 
+    cfg_if::cfg_if! {
+        if #[cfg(feature = "proto-ipv4")] {
+            use crate::wire::Ipv4Address as IpvXAddress;
+            use crate::wire::Ipv4Repr as IpvXRepr;
+            use IpRepr::Ipv4 as IpReprIpvX;
+
+            const LOCAL_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 1]);
+            const REMOTE_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 2]);
+            const OTHER_ADDR: IpvXAddress = IpvXAddress([192, 168, 1, 3]);
+        } else {
+            use crate::wire::Ipv6Address as IpvXAddress;
+            use crate::wire::Ipv6Repr as IpvXRepr;
+            use IpRepr::Ipv6 as IpReprIpvX;
+
+            const LOCAL_ADDR: IpvXAddress = IpvXAddress([
+                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+            ]);
+            const REMOTE_ADDR: IpvXAddress = IpvXAddress([
+                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+            ]);
+            const OTHER_ADDR: IpvXAddress = IpvXAddress([
+                0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+            ]);
+        }
+    }
+
     pub const LOCAL_END: IpEndpoint = IpEndpoint {
-        addr: MOCK_IP_ADDR_1,
+        addr: LOCAL_ADDR.into_address(),
         port: LOCAL_PORT,
     };
     pub const REMOTE_END: IpEndpoint = IpEndpoint {
-        addr: MOCK_IP_ADDR_2,
+        addr: REMOTE_ADDR.into_address(),
         port: REMOTE_PORT,
     };
 
-    pub const LOCAL_IP_REPR: IpRepr = IpRepr::Unspecified {
-        src_addr: MOCK_IP_ADDR_1,
-        dst_addr: MOCK_IP_ADDR_2,
+    pub const LOCAL_IP_REPR: IpRepr = IpReprIpvX(IpvXRepr {
+        src_addr: LOCAL_ADDR,
+        dst_addr: REMOTE_ADDR,
         next_header: IpProtocol::Udp,
         payload_len: 8 + 6,
         hop_limit: 64,
-    };
+    });
+
+    pub const REMOTE_IP_REPR: IpRepr = IpReprIpvX(IpvXRepr {
+        src_addr: REMOTE_ADDR,
+        dst_addr: LOCAL_ADDR,
+        next_header: IpProtocol::Udp,
+        payload_len: 8 + 6,
+        hop_limit: 64,
+    });
+
+    pub const BAD_IP_REPR: IpRepr = IpReprIpvX(IpvXRepr {
+        src_addr: REMOTE_ADDR,
+        dst_addr: OTHER_ADDR,
+        next_header: IpProtocol::Udp,
+        payload_len: 8 + 6,
+        hop_limit: 64,
+    });
 
     const LOCAL_UDP_REPR: UdpRepr = UdpRepr {
         src_port: LOCAL_PORT,
@@ -440,28 +477,6 @@ mod test {
 
     const PAYLOAD: &[u8] = b"abcdef";
 
-    fn remote_ip_repr() -> IpRepr {
-        match (MOCK_IP_ADDR_2, MOCK_IP_ADDR_1) {
-            #[cfg(feature = "proto-ipv4")]
-            (IpAddress::Ipv4(src), IpAddress::Ipv4(dst)) => IpRepr::Ipv4(Ipv4Repr {
-                src_addr: src,
-                dst_addr: dst,
-                next_header: IpProtocol::Udp,
-                payload_len: 8 + 6,
-                hop_limit: 64,
-            }),
-            #[cfg(feature = "proto-ipv6")]
-            (IpAddress::Ipv6(src), IpAddress::Ipv6(dst)) => IpRepr::Ipv6(Ipv6Repr {
-                src_addr: src,
-                dst_addr: dst,
-                next_header: IpProtocol::Udp,
-                payload_len: 8 + 6,
-                hop_limit: 64,
-            }),
-            _ => unreachable!(),
-        }
-    }
-
     #[test]
     fn test_bind_unaddressable() {
         let mut socket = socket(buffer(0), buffer(0));
@@ -567,16 +582,16 @@ mod test {
         assert!(!socket.can_recv());
         assert_eq!(socket.recv(), Err(Error::Exhausted));
 
-        assert!(socket.accepts(&mut cx, &remote_ip_repr(), &REMOTE_UDP_REPR));
+        assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
         assert_eq!(
-            socket.process(&mut cx, &remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
+            socket.process(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR, PAYLOAD),
             Ok(())
         );
         assert!(socket.can_recv());
 
-        assert!(socket.accepts(&mut cx, &remote_ip_repr(), &REMOTE_UDP_REPR));
+        assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
         assert_eq!(
-            socket.process(&mut cx, &remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
+            socket.process(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR, PAYLOAD),
             Err(Error::Exhausted)
         );
         assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END)));
@@ -593,7 +608,7 @@ mod test {
         assert_eq!(socket.peek(), Err(Error::Exhausted));
 
         assert_eq!(
-            socket.process(&mut cx, &remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
+            socket.process(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR, PAYLOAD),
             Ok(())
         );
         assert_eq!(socket.peek(), Ok((&b"abcdef"[..], &REMOTE_END)));
@@ -608,9 +623,9 @@ mod test {
 
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
-        assert!(socket.accepts(&mut cx, &remote_ip_repr(), &REMOTE_UDP_REPR));
+        assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
         assert_eq!(
-            socket.process(&mut cx, &remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
+            socket.process(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR, PAYLOAD),
             Ok(())
         );
 
@@ -627,7 +642,7 @@ mod test {
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
         assert_eq!(
-            socket.process(&mut cx, &remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
+            socket.process(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR, PAYLOAD),
             Ok(())
         );
 
@@ -652,13 +667,13 @@ mod test {
             s.dispatch(&mut cx, |_, (ip_repr, _, _)| {
                 assert_eq!(
                     ip_repr,
-                    IpRepr::Unspecified {
-                        src_addr: MOCK_IP_ADDR_1,
-                        dst_addr: MOCK_IP_ADDR_2,
+                    IpReprIpvX(IpvXRepr {
+                        src_addr: LOCAL_ADDR,
+                        dst_addr: REMOTE_ADDR,
                         next_header: IpProtocol::Udp,
                         payload_len: 8 + 6,
                         hop_limit: 0x2a,
-                    }
+                    })
                 );
                 Ok(())
             }),
@@ -674,44 +689,22 @@ mod test {
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
         let mut udp_repr = REMOTE_UDP_REPR;
-        assert!(socket.accepts(&mut cx, &remote_ip_repr(), &udp_repr));
+        assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &udp_repr));
         udp_repr.dst_port += 1;
-        assert!(!socket.accepts(&mut cx, &remote_ip_repr(), &udp_repr));
+        assert!(!socket.accepts(&mut cx, &REMOTE_IP_REPR, &udp_repr));
     }
 
     #[test]
     fn test_doesnt_accept_wrong_ip() {
-        fn generate_bad_repr() -> IpRepr {
-            match (MOCK_IP_ADDR_2, MOCK_IP_ADDR_3) {
-                #[cfg(feature = "proto-ipv4")]
-                (IpAddress::Ipv4(src), IpAddress::Ipv4(dst)) => IpRepr::Ipv4(Ipv4Repr {
-                    src_addr: src,
-                    dst_addr: dst,
-                    next_header: IpProtocol::Udp,
-                    payload_len: 8 + 6,
-                    hop_limit: 64,
-                }),
-                #[cfg(feature = "proto-ipv6")]
-                (IpAddress::Ipv6(src), IpAddress::Ipv6(dst)) => IpRepr::Ipv6(Ipv6Repr {
-                    src_addr: src,
-                    dst_addr: dst,
-                    next_header: IpProtocol::Udp,
-                    payload_len: 8 + 6,
-                    hop_limit: 64,
-                }),
-                _ => unreachable!(),
-            }
-        }
-
         let mut cx = Context::mock();
 
         let mut port_bound_socket = socket(buffer(1), buffer(0));
         assert_eq!(port_bound_socket.bind(LOCAL_PORT), Ok(()));
-        assert!(port_bound_socket.accepts(&mut cx, &generate_bad_repr(), &REMOTE_UDP_REPR));
+        assert!(port_bound_socket.accepts(&mut cx, &BAD_IP_REPR, &REMOTE_UDP_REPR));
 
         let mut ip_bound_socket = socket(buffer(1), buffer(0));
         assert_eq!(ip_bound_socket.bind(LOCAL_END), Ok(()));
-        assert!(!ip_bound_socket.accepts(&mut cx, &generate_bad_repr(), &REMOTE_UDP_REPR));
+        assert!(!ip_bound_socket.accepts(&mut cx, &BAD_IP_REPR, &REMOTE_UDP_REPR));
     }
 
     #[test]
@@ -740,10 +733,7 @@ mod test {
             src_port: REMOTE_PORT,
             dst_port: LOCAL_PORT,
         };
-        assert_eq!(
-            socket.process(&mut cx, &remote_ip_repr(), &repr, &[]),
-            Ok(())
-        );
+        assert_eq!(socket.process(&mut cx, &REMOTE_IP_REPR, &repr, &[]), Ok(()));
         assert_eq!(socket.recv(), Ok((&[][..], REMOTE_END)));
     }
 

+ 35 - 372
src/wire/ip.rs

@@ -506,20 +506,12 @@ impl<T: Into<Address>> From<(T, u16)> for Endpoint {
 
 /// An IP packet representation.
 ///
-/// This enum abstracts the various versions of IP packets. It either contains a concrete
-/// high-level representation for some IP protocol version, or an unspecified representation,
-/// which permits the `IpAddress::Unspecified` addresses.
+/// This enum abstracts the various versions of IP packets. It either contains an IPv4
+/// or IPv6 concrete high-level representation.
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 #[non_exhaustive]
 pub enum Repr {
-    Unspecified {
-        src_addr: Address,
-        dst_addr: Address,
-        next_header: Protocol,
-        payload_len: usize,
-        hop_limit: u8,
-    },
     #[cfg(feature = "proto-ipv4")]
     Ipv4(Ipv4Repr),
     #[cfg(feature = "proto-ipv6")]
@@ -541,10 +533,42 @@ impl From<Ipv6Repr> for Repr {
 }
 
 impl Repr {
+    /// Create a new IpRepr, choosing the right IP version for the src/dst addrs.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `src_addr` and `dst_addr` are different IP version.
+    pub fn new(
+        src_addr: Address,
+        dst_addr: Address,
+        next_header: Protocol,
+        payload_len: usize,
+        hop_limit: u8,
+    ) -> Self {
+        match (src_addr, dst_addr) {
+            #[cfg(feature = "proto-ipv4")]
+            (Address::Ipv4(src_addr), Address::Ipv4(dst_addr)) => Self::Ipv4(Ipv4Repr {
+                src_addr,
+                dst_addr,
+                next_header,
+                payload_len,
+                hop_limit,
+            }),
+            #[cfg(feature = "proto-ipv6")]
+            (Address::Ipv6(src_addr), Address::Ipv6(dst_addr)) => Self::Ipv6(Ipv6Repr {
+                src_addr,
+                dst_addr,
+                next_header,
+                payload_len,
+                hop_limit,
+            }),
+            _ => panic!("IP version mismatch: src={:?} dst={:?}", src_addr, dst_addr),
+        }
+    }
+
     /// Return the protocol version.
     pub fn version(&self) -> Version {
         match *self {
-            Repr::Unspecified { .. } => Version::Unspecified,
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(_) => Version::Ipv4,
             #[cfg(feature = "proto-ipv6")]
@@ -555,7 +579,6 @@ impl Repr {
     /// Return the source address.
     pub fn src_addr(&self) -> Address {
         match *self {
-            Repr::Unspecified { src_addr, .. } => src_addr,
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(repr) => Address::Ipv4(repr.src_addr),
             #[cfg(feature = "proto-ipv6")]
@@ -566,7 +589,6 @@ impl Repr {
     /// Return the destination address.
     pub fn dst_addr(&self) -> Address {
         match *self {
-            Repr::Unspecified { dst_addr, .. } => dst_addr,
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(repr) => Address::Ipv4(repr.dst_addr),
             #[cfg(feature = "proto-ipv6")]
@@ -577,7 +599,6 @@ impl Repr {
     /// Return the next header (protocol).
     pub fn next_header(&self) -> Protocol {
         match *self {
-            Repr::Unspecified { next_header, .. } => next_header,
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(repr) => repr.next_header,
             #[cfg(feature = "proto-ipv6")]
@@ -588,7 +609,6 @@ impl Repr {
     /// Return the payload length.
     pub fn payload_len(&self) -> usize {
         match *self {
-            Repr::Unspecified { payload_len, .. } => payload_len,
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(repr) => repr.payload_len,
             #[cfg(feature = "proto-ipv6")]
@@ -599,10 +619,6 @@ impl Repr {
     /// Set the payload length.
     pub fn set_payload_len(&mut self, length: usize) {
         match *self {
-            Repr::Unspecified {
-                ref mut payload_len,
-                ..
-            } => *payload_len = length,
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(Ipv4Repr {
                 ref mut payload_len,
@@ -619,7 +635,6 @@ impl Repr {
     /// Return the TTL value.
     pub fn hop_limit(&self) -> u8 {
         match *self {
-            Repr::Unspecified { hop_limit, .. } => hop_limit,
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(Ipv4Repr { hop_limit, .. }) => hop_limit,
             #[cfg(feature = "proto-ipv6")]
@@ -627,156 +642,9 @@ impl Repr {
         }
     }
 
-    /// Convert an unspecified representation into a concrete one, or return
-    /// `Err(Error::Unaddressable)` if not possible.
-    ///
-    /// # Panics
-    /// This function panics if source and destination addresses belong to different families,
-    /// or the destination address is unspecified, since this indicates a logic error.
-    pub fn lower(&self, fallback_src_addrs: &[Cidr]) -> Result<Repr> {
-        macro_rules! resolve_unspecified {
-            ($reprty:path, $ipty:path, $iprepr:expr, $fallbacks:expr) => {
-                if $iprepr.src_addr.is_unspecified() {
-                    for cidr in $fallbacks {
-                        match cidr.address() {
-                            $ipty(addr) => {
-                                $iprepr.src_addr = addr;
-                                return Ok($reprty($iprepr));
-                            }
-                            _ => (),
-                        }
-                    }
-                    Err(Error::Unaddressable)
-                } else {
-                    Ok($reprty($iprepr))
-                }
-            };
-        }
-
-        match self {
-            #[cfg(feature = "proto-ipv4")]
-            &Repr::Unspecified {
-                src_addr: src_addr @ Address::Unspecified,
-                dst_addr: Address::Ipv4(dst_addr),
-                next_header,
-                payload_len,
-                hop_limit,
-            }
-            | &Repr::Unspecified {
-                src_addr: src_addr @ Address::Ipv4(_),
-                dst_addr: Address::Ipv4(dst_addr),
-                next_header,
-                payload_len,
-                hop_limit,
-            } if src_addr.is_unspecified() => {
-                let mut src_addr = if let Address::Ipv4(src_ipv4_addr) = src_addr {
-                    Some(src_ipv4_addr)
-                } else {
-                    None
-                };
-                for cidr in fallback_src_addrs {
-                    if let Address::Ipv4(addr) = cidr.address() {
-                        src_addr = Some(addr);
-                        break;
-                    }
-                }
-                Ok(Repr::Ipv4(Ipv4Repr {
-                    src_addr: src_addr.ok_or(Error::Unaddressable)?,
-                    dst_addr,
-                    next_header,
-                    payload_len,
-                    hop_limit,
-                }))
-            }
-
-            #[cfg(feature = "proto-ipv6")]
-            &Repr::Unspecified {
-                src_addr: src_addr @ Address::Unspecified,
-                dst_addr: Address::Ipv6(dst_addr),
-                next_header: protocol,
-                payload_len,
-                hop_limit,
-            }
-            | &Repr::Unspecified {
-                src_addr: src_addr @ Address::Ipv6(_),
-                dst_addr: Address::Ipv6(dst_addr),
-                next_header: protocol,
-                payload_len,
-                hop_limit,
-            } if src_addr.is_unspecified() => {
-                let mut src_addr = if let Address::Ipv6(src_ipv6_addr) = src_addr {
-                    Some(src_ipv6_addr)
-                } else {
-                    None
-                };
-                for cidr in fallback_src_addrs {
-                    if let Address::Ipv6(addr) = cidr.address() {
-                        src_addr = Some(addr);
-                        break;
-                    }
-                }
-                Ok(Repr::Ipv6(Ipv6Repr {
-                    src_addr: src_addr.ok_or(Error::Unaddressable)?,
-                    next_header: protocol,
-                    dst_addr,
-                    payload_len,
-                    hop_limit,
-                }))
-            }
-
-            #[cfg(feature = "proto-ipv4")]
-            &Repr::Unspecified {
-                src_addr: Address::Ipv4(src_addr),
-                dst_addr: Address::Ipv4(dst_addr),
-                next_header: protocol,
-                payload_len,
-                hop_limit,
-            } => Ok(Repr::Ipv4(Ipv4Repr {
-                src_addr: src_addr,
-                dst_addr: dst_addr,
-                next_header: protocol,
-                payload_len: payload_len,
-                hop_limit,
-            })),
-
-            #[cfg(feature = "proto-ipv6")]
-            &Repr::Unspecified {
-                src_addr: Address::Ipv6(src_addr),
-                dst_addr: Address::Ipv6(dst_addr),
-                next_header: protocol,
-                payload_len,
-                hop_limit,
-            } => Ok(Repr::Ipv6(Ipv6Repr {
-                src_addr: src_addr,
-                dst_addr: dst_addr,
-                next_header: protocol,
-                payload_len: payload_len,
-                hop_limit: hop_limit,
-            })),
-
-            #[cfg(feature = "proto-ipv4")]
-            &Repr::Ipv4(mut repr) => {
-                resolve_unspecified!(Repr::Ipv4, Address::Ipv4, repr, fallback_src_addrs)
-            }
-
-            #[cfg(feature = "proto-ipv6")]
-            &Repr::Ipv6(mut repr) => {
-                resolve_unspecified!(Repr::Ipv6, Address::Ipv6, repr, fallback_src_addrs)
-            }
-
-            &Repr::Unspecified { .. } => {
-                panic!("source and destination IP address families do not match")
-            }
-        }
-    }
-
     /// Return the length of a header that will be emitted from this high-level representation.
-    ///
-    /// # Panics
-    /// This function panics if invoked on an unspecified representation.
     pub fn buffer_len(&self) -> usize {
         match *self {
-            Repr::Unspecified { .. } => panic!("unspecified IP representation"),
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(repr) => repr.buffer_len(),
             #[cfg(feature = "proto-ipv6")]
@@ -785,16 +653,12 @@ impl Repr {
     }
 
     /// Emit this high-level representation into a buffer.
-    ///
-    /// # Panics
-    /// This function panics if invoked on an unspecified representation.
     pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(
         &self,
         buffer: T,
         _checksum_caps: &ChecksumCapabilities,
     ) {
         match *self {
-            Repr::Unspecified { .. } => panic!("unspecified IP representation"),
             #[cfg(feature = "proto-ipv4")]
             Repr::Ipv4(repr) => repr.emit(&mut Ipv4Packet::new_unchecked(buffer), _checksum_caps),
             #[cfg(feature = "proto-ipv6")]
@@ -806,9 +670,6 @@ impl Repr {
     /// high-level representation.
     ///
     /// This is the same as `repr.buffer_len() + repr.payload_len()`.
-    ///
-    /// # Panics
-    /// This function panics if invoked on an unspecified representation.
     pub fn total_len(&self) -> usize {
         self.buffer_len() + self.payload_len()
     }
@@ -1031,204 +892,6 @@ pub(crate) mod test {
     #[cfg(feature = "proto-ipv4")]
     use crate::wire::{Ipv4Address, Ipv4Repr};
 
-    macro_rules! generate_common_tests {
-        ($name:ident, $repr:ident, $ip_repr:path, $ip_addr:path,
-         $addr_from:path, $bytes_a:expr, $bytes_b:expr,
-         $unspecified:expr) => {
-            mod $name {
-                use super::*;
-
-                #[test]
-                fn test_ip_repr_lower() {
-                    let ip_addr_a = $addr_from(&$bytes_a);
-                    let ip_addr_b = $addr_from(&$bytes_b);
-                    let proto = IpProtocol::Icmp;
-                    let payload_len = 10;
-
-                    assert_eq!(
-                        Repr::Unspecified {
-                            src_addr: $ip_addr(ip_addr_a),
-                            dst_addr: $ip_addr(ip_addr_b),
-                            next_header: proto,
-                            hop_limit: 0x2a,
-                            payload_len,
-                        }
-                        .lower(&[]),
-                        Ok($ip_repr($repr {
-                            src_addr: ip_addr_a,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 0x2a,
-                            payload_len
-                        }))
-                    );
-
-                    assert_eq!(
-                        Repr::Unspecified {
-                            src_addr: IpAddress::Unspecified,
-                            dst_addr: $ip_addr(ip_addr_b),
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        }
-                        .lower(&[]),
-                        Err(Error::Unaddressable)
-                    );
-
-                    assert_eq!(
-                        Repr::Unspecified {
-                            src_addr: IpAddress::Unspecified,
-                            dst_addr: $ip_addr(ip_addr_b),
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        }
-                        .lower(&[IpCidr::new($ip_addr(ip_addr_a), 24)]),
-                        Ok($ip_repr($repr {
-                            src_addr: ip_addr_a,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        }))
-                    );
-
-                    assert_eq!(
-                        Repr::Unspecified {
-                            src_addr: $ip_addr($unspecified),
-                            dst_addr: $ip_addr(ip_addr_b),
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        }
-                        .lower(&[IpCidr::new($ip_addr(ip_addr_a), 24)]),
-                        Ok($ip_repr($repr {
-                            src_addr: ip_addr_a,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        }))
-                    );
-
-                    assert_eq!(
-                        Repr::Unspecified {
-                            src_addr: $ip_addr($unspecified),
-                            dst_addr: $ip_addr(ip_addr_b),
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        }
-                        .lower(&[]),
-                        Ok($ip_repr($repr {
-                            src_addr: $unspecified,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        }))
-                    );
-
-                    assert_eq!(
-                        $ip_repr($repr {
-                            src_addr: ip_addr_a,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 255,
-                            payload_len
-                        })
-                        .lower(&[]),
-                        Ok($ip_repr($repr {
-                            src_addr: ip_addr_a,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 255,
-                            payload_len
-                        }))
-                    );
-
-                    assert_eq!(
-                        $ip_repr($repr {
-                            src_addr: $unspecified,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 255,
-                            payload_len
-                        })
-                        .lower(&[]),
-                        Err(Error::Unaddressable)
-                    );
-
-                    assert_eq!(
-                        $ip_repr($repr {
-                            src_addr: $unspecified,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        })
-                        .lower(&[IpCidr::new($ip_addr(ip_addr_a), 24)]),
-                        Ok($ip_repr($repr {
-                            src_addr: ip_addr_a,
-                            dst_addr: ip_addr_b,
-                            next_header: proto,
-                            hop_limit: 64,
-                            payload_len
-                        }))
-                    );
-                }
-            }
-        };
-        (ipv4 $addr_bytes_a:expr, $addr_bytes_b:expr) => {
-            generate_common_tests!(
-                ipv4,
-                Ipv4Repr,
-                Repr::Ipv4,
-                IpAddress::Ipv4,
-                Ipv4Address::from_bytes,
-                $addr_bytes_a,
-                $addr_bytes_b,
-                Ipv4Address::UNSPECIFIED
-            );
-        };
-        (ipv6 $addr_bytes_a:expr, $addr_bytes_b:expr) => {
-            generate_common_tests!(
-                ipv6,
-                Ipv6Repr,
-                Repr::Ipv6,
-                IpAddress::Ipv6,
-                Ipv6Address::from_bytes,
-                $addr_bytes_a,
-                $addr_bytes_b,
-                Ipv6Address::UNSPECIFIED
-            );
-        };
-    }
-
-    #[cfg(feature = "proto-ipv4")]
-    generate_common_tests!(ipv4
-                           [1, 2, 3, 4],
-                           [5, 6, 7, 8]);
-
-    #[cfg(feature = "proto-ipv6")]
-    generate_common_tests!(ipv6
-                           [0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
-                           [0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
-
-    #[test]
-    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
-    #[should_panic(expected = "source and destination IP address families do not match")]
-    fn test_lower_between_families() {
-        Repr::Unspecified {
-            src_addr: Address::Ipv6(Ipv6Address::UNSPECIFIED),
-            dst_addr: Address::Ipv4(Ipv4Address::UNSPECIFIED),
-            next_header: IpProtocol::Icmpv6,
-            hop_limit: 0xff,
-            payload_len: 0,
-        }
-        .lower(&[]);
-    }
-
     #[test]
     fn endpoint_unspecified() {
         assert!(!Endpoint::UNSPECIFIED.is_specified());

+ 7 - 0
src/wire/ipv4.rs

@@ -87,6 +87,13 @@ impl Address {
     pub const fn is_loopback(&self) -> bool {
         self.0[0] == 127
     }
+
+    /// Convert to an `IpAddress`.
+    ///
+    /// Same as `.into()`, but works in `const`.
+    pub const fn into_address(self) -> super::IpAddress {
+        super::IpAddress::Ipv4(self)
+    }
 }
 
 #[cfg(feature = "std")]

+ 7 - 0
src/wire/ipv6.rs

@@ -188,6 +188,13 @@ impl Address {
             self.0[13], self.0[14], self.0[15],
         ])
     }
+
+    /// Convert to an `IpAddress`.
+    ///
+    /// Same as `.into()`, but works in `const`.
+    pub const fn into_address(self) -> super::IpAddress {
+        super::IpAddress::Ipv6(self)
+    }
 }
 
 #[cfg(feature = "std")]