Explorar o código

Calculate IP payload length from the total length field.

Before this commit, IP payload length was calculated by subtracting
the IP header length from the total underlying buffer length, which
fails if the underlying buffer has padding, e.g. like Ethernet
does.
whitequark %!s(int64=8) %!d(string=hai) anos
pai
achega
41f9426380
Modificáronse 7 ficheiros con 114 adicións e 96 borrados
  1. 29 30
      src/iface/ethernet.rs
  2. 11 9
      src/socket/tcp.rs
  3. 9 8
      src/socket/udp.rs
  4. 2 6
      src/wire/icmpv4.rs
  5. 25 13
      src/wire/ip.rs
  6. 31 24
      src/wire/ipv4.rs
  7. 7 6
      src/wire/mod.rs

+ 29 - 30
src/iface/ethernet.rs

@@ -170,7 +170,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                     Ipv4Repr { dst_addr, .. } if !self.has_protocol_addr(dst_addr) => (),
                     Ipv4Repr { dst_addr, .. } if !self.has_protocol_addr(dst_addr) => (),
 
 
                     // Respond to ICMP packets.
                     // Respond to ICMP packets.
-                    Ipv4Repr { protocol: IpProtocol::Icmp, src_addr, dst_addr } => {
+                    Ipv4Repr { protocol: IpProtocol::Icmp, src_addr, dst_addr, .. } => {
                         let icmp_packet = try!(Icmpv4Packet::new(ipv4_packet.payload()));
                         let icmp_packet = try!(Icmpv4Packet::new(ipv4_packet.payload()));
                         let icmp_repr = try!(Icmpv4Repr::parse(&icmp_packet));
                         let icmp_repr = try!(Icmpv4Repr::parse(&icmp_packet));
                         match icmp_repr {
                         match icmp_repr {
@@ -178,16 +178,17 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                             Icmpv4Repr::EchoRequest {
                             Icmpv4Repr::EchoRequest {
                                 ident, seq_no, data
                                 ident, seq_no, data
                             } => {
                             } => {
-                                let ipv4_reply_repr = Ipv4Repr {
-                                    src_addr: dst_addr,
-                                    dst_addr: src_addr,
-                                    protocol: IpProtocol::Icmp
-                                };
                                 let icmp_reply_repr = Icmpv4Repr::EchoReply {
                                 let icmp_reply_repr = Icmpv4Repr::EchoReply {
                                     ident:  ident,
                                     ident:  ident,
                                     seq_no: seq_no,
                                     seq_no: seq_no,
                                     data:   data
                                     data:   data
                                 };
                                 };
+                                let ipv4_reply_repr = Ipv4Repr {
+                                    src_addr:    dst_addr,
+                                    dst_addr:    src_addr,
+                                    protocol:    IpProtocol::Icmp,
+                                    payload_len: icmp_reply_repr.buffer_len()
+                                };
                                 response = Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr)
                                 response = Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr)
                             }
                             }
 
 
@@ -200,7 +201,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                     },
                     },
 
 
                     // Try dispatching a packet to a socket.
                     // Try dispatching a packet to a socket.
-                    Ipv4Repr { src_addr, dst_addr, protocol } => {
+                    Ipv4Repr { src_addr, dst_addr, protocol, .. } => {
                         let mut handled = false;
                         let mut handled = false;
                         for socket in sockets.iter_mut() {
                         for socket in sockets.iter_mut() {
                             let ip_repr = IpRepr::Ipv4(ipv4_repr);
                             let ip_repr = IpRepr::Ipv4(ipv4_repr);
@@ -228,11 +229,6 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                         if !handled && protocol == IpProtocol::Tcp {
                         if !handled && protocol == IpProtocol::Tcp {
                             let tcp_packet = try!(TcpPacket::new(ipv4_packet.payload()));
                             let tcp_packet = try!(TcpPacket::new(ipv4_packet.payload()));
 
 
-                            let ipv4_reply_repr = Ipv4Repr {
-                                src_addr: dst_addr,
-                                dst_addr: src_addr,
-                                protocol: IpProtocol::Tcp
-                            };
                             let tcp_reply_repr = TcpRepr {
                             let tcp_reply_repr = TcpRepr {
                                 src_port:   tcp_packet.dst_port(),
                                 src_port:   tcp_packet.dst_port(),
                                 dst_port:   tcp_packet.src_port(),
                                 dst_port:   tcp_packet.src_port(),
@@ -243,6 +239,12 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                                 window_len: 0,
                                 window_len: 0,
                                 payload:    &[]
                                 payload:    &[]
                             };
                             };
+                            let ipv4_reply_repr = Ipv4Repr {
+                                src_addr:    dst_addr,
+                                dst_addr:    src_addr,
+                                protocol:    IpProtocol::Tcp,
+                                payload_len: tcp_reply_repr.buffer_len()
+                            };
                             response = Response::Tcpv4(ipv4_reply_repr, tcp_reply_repr);
                             response = Response::Tcpv4(ipv4_reply_repr, tcp_reply_repr);
                         } else if !handled {
                         } else if !handled {
                             let reason;
                             let reason;
@@ -255,16 +257,16 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                             let mut data = [0; 8];
                             let mut data = [0; 8];
                             data.copy_from_slice(&ipv4_packet.payload()[0..8]);
                             data.copy_from_slice(&ipv4_packet.payload()[0..8]);
 
 
-                            let ipv4_reply_repr = Ipv4Repr {
-                                src_addr: dst_addr,
-                                dst_addr: src_addr,
-                                protocol: IpProtocol::Icmp
-                            };
                             let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
                             let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
-                                reason:   reason,
-                                header:   ipv4_repr,
-                                length:   ipv4_packet.payload().len(),
-                                data:     data
+                                reason: reason,
+                                header: ipv4_repr,
+                                data:   data
+                            };
+                            let ipv4_reply_repr = Ipv4Repr {
+                                src_addr:    dst_addr,
+                                dst_addr:    src_addr,
+                                protocol:    IpProtocol::Icmp,
+                                payload_len: icmp_reply_repr.buffer_len()
                             };
                             };
                             response = Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr)
                             response = Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr)
                         }
                         }
@@ -277,16 +279,15 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
         }
         }
 
 
         macro_rules! ip_response {
         macro_rules! ip_response {
-            ($tx_buffer:ident, $frame:ident, $ip_repr:ident, $length:expr) => ({
+            ($tx_buffer:ident, $frame:ident, $ip_repr:ident) => ({
                 let dst_hardware_addr =
                 let dst_hardware_addr =
                     match self.arp_cache.lookup(&$ip_repr.dst_addr.into()) {
                     match self.arp_cache.lookup(&$ip_repr.dst_addr.into()) {
                         None => return Err(Error::Unaddressable),
                         None => return Err(Error::Unaddressable),
                         Some(hardware_addr) => hardware_addr
                         Some(hardware_addr) => hardware_addr
                     };
                     };
 
 
-                let payload_len = $length;
                 let frame_len = EthernetFrame::<&[u8]>::buffer_len($ip_repr.buffer_len() +
                 let frame_len = EthernetFrame::<&[u8]>::buffer_len($ip_repr.buffer_len() +
-                                                                   payload_len);
+                                                                   $ip_repr.payload_len);
                 $tx_buffer = try!(self.device.transmit(frame_len));
                 $tx_buffer = try!(self.device.transmit(frame_len));
                 $frame = try!(EthernetFrame::new(&mut $tx_buffer));
                 $frame = try!(EthernetFrame::new(&mut $tx_buffer));
                 $frame.set_src_addr(self.hardware_addr);
                 $frame.set_src_addr(self.hardware_addr);
@@ -294,7 +295,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                 $frame.set_ethertype(EthernetProtocol::Ipv4);
                 $frame.set_ethertype(EthernetProtocol::Ipv4);
 
 
                 let mut ip_packet = try!(Ipv4Packet::new($frame.payload_mut()));
                 let mut ip_packet = try!(Ipv4Packet::new($frame.payload_mut()));
-                $ip_repr.emit(&mut ip_packet, payload_len);
+                $ip_repr.emit(&mut ip_packet);
                 ip_packet
                 ip_packet
             })
             })
         }
         }
@@ -320,8 +321,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
             Response::Icmpv4(ip_repr, icmp_repr) => {
             Response::Icmpv4(ip_repr, icmp_repr) => {
                 let mut tx_buffer;
                 let mut tx_buffer;
                 let mut frame;
                 let mut frame;
-                let mut ip_packet = ip_response!(tx_buffer, frame, ip_repr,
-                                                 icmp_repr.buffer_len());
+                let mut ip_packet = ip_response!(tx_buffer, frame, ip_repr);
                 let mut icmp_packet = try!(Icmpv4Packet::new(ip_packet.payload_mut()));
                 let mut icmp_packet = try!(Icmpv4Packet::new(ip_packet.payload_mut()));
                 icmp_repr.emit(&mut icmp_packet);
                 icmp_repr.emit(&mut icmp_packet);
                 Ok(())
                 Ok(())
@@ -330,8 +330,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
             Response::Tcpv4(ip_repr, tcp_repr) => {
             Response::Tcpv4(ip_repr, tcp_repr) => {
                 let mut tx_buffer;
                 let mut tx_buffer;
                 let mut frame;
                 let mut frame;
-                let mut ip_packet = ip_response!(tx_buffer, frame, ip_repr,
-                                                 tcp_repr.buffer_len());
+                let mut ip_packet = ip_response!(tx_buffer, frame, ip_repr);
                 let mut tcp_packet = try!(TcpPacket::new(ip_packet.payload_mut()));
                 let mut tcp_packet = try!(TcpPacket::new(ip_packet.payload_mut()));
                 tcp_repr.emit(&mut tcp_packet,
                 tcp_repr.emit(&mut tcp_packet,
                               &IpAddress::Ipv4(ip_repr.src_addr),
                               &IpAddress::Ipv4(ip_repr.src_addr),
@@ -372,7 +371,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                 frame.set_dst_addr(dst_hardware_addr);
                 frame.set_dst_addr(dst_hardware_addr);
                 frame.set_ethertype(EthernetProtocol::Ipv4);
                 frame.set_ethertype(EthernetProtocol::Ipv4);
 
 
-                repr.emit(frame.payload_mut(), payload.buffer_len());
+                repr.emit(frame.payload_mut());
 
 
                 let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
                 let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
                 payload.emit(&repr, ip_packet.payload_mut());
                 payload.emit(&repr, ip_packet.payload_mut());

+ 11 - 9
src/socket/tcp.rs

@@ -513,7 +513,7 @@ impl<'a> TcpSocket<'a> {
                    payload: &[u8]) -> Result<(), Error> {
                    payload: &[u8]) -> Result<(), Error> {
         if ip_repr.protocol() != IpProtocol::Tcp { return Err(Error::Rejected) }
         if ip_repr.protocol() != IpProtocol::Tcp { return Err(Error::Rejected) }
 
 
-        let packet = try!(TcpPacket::new(payload));
+        let packet = try!(TcpPacket::new(&payload[..ip_repr.payload_len()]));
         let repr = try!(TcpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr()));
         let repr = try!(TcpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr()));
 
 
         // Reject packets with a wrong destination.
         // Reject packets with a wrong destination.
@@ -749,11 +749,6 @@ impl<'a> TcpSocket<'a> {
             where F: FnMut(&IpRepr, &IpPayload) -> Result<R, Error> {
             where F: FnMut(&IpRepr, &IpPayload) -> Result<R, Error> {
         if self.remote_endpoint.is_unspecified() { return Err(Error::Exhausted) }
         if self.remote_endpoint.is_unspecified() { return Err(Error::Exhausted) }
 
 
-        let ip_repr = IpRepr::Unspecified {
-            src_addr: self.local_endpoint.addr,
-            dst_addr: self.remote_endpoint.addr,
-            protocol: IpProtocol::Tcp,
-        };
         let mut repr = TcpRepr {
         let mut repr = TcpRepr {
             src_port:   self.local_endpoint.port,
             src_port:   self.local_endpoint.port,
             dst_port:   self.remote_endpoint.port,
             dst_port:   self.remote_endpoint.port,
@@ -864,6 +859,12 @@ impl<'a> TcpSocket<'a> {
             repr.ack_number = Some(ack_number);
             repr.ack_number = Some(ack_number);
             self.remote_last_ack = ack_number;
             self.remote_last_ack = ack_number;
 
 
+            let ip_repr = IpRepr::Unspecified {
+                src_addr:    self.local_endpoint.addr,
+                dst_addr:    self.remote_endpoint.addr,
+                protocol:    IpProtocol::Tcp,
+                payload_len: repr.buffer_len()
+            };
             emit(&ip_repr, &repr)
             emit(&ip_repr, &repr)
         } else {
         } else {
             Err(Error::Exhausted)
             Err(Error::Exhausted)
@@ -963,9 +964,10 @@ mod test {
         let mut packet = TcpPacket::new(&mut buffer).unwrap();
         let mut packet = TcpPacket::new(&mut buffer).unwrap();
         repr.emit(&mut packet, &REMOTE_IP, &LOCAL_IP);
         repr.emit(&mut packet, &REMOTE_IP, &LOCAL_IP);
         let ip_repr = IpRepr::Unspecified {
         let ip_repr = IpRepr::Unspecified {
-            src_addr: REMOTE_IP,
-            dst_addr: LOCAL_IP,
-            protocol: IpProtocol::Tcp
+            src_addr:    REMOTE_IP,
+            dst_addr:    LOCAL_IP,
+            protocol:    IpProtocol::Tcp,
+            payload_len: repr.buffer_len()
         };
         };
         socket.process(timestamp, &ip_repr, &packet.into_inner()[..])
         socket.process(timestamp, &ip_repr, &packet.into_inner()[..])
     }
     }

+ 9 - 8
src/socket/udp.rs

@@ -196,7 +196,7 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
                    payload: &[u8]) -> Result<(), Error> {
                    payload: &[u8]) -> Result<(), Error> {
         if ip_repr.protocol() != IpProtocol::Udp { return Err(Error::Rejected) }
         if ip_repr.protocol() != IpProtocol::Udp { return Err(Error::Rejected) }
 
 
-        let packet = try!(UdpPacket::new(payload));
+        let packet = try!(UdpPacket::new(&payload[..ip_repr.payload_len()]));
         let repr = try!(UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr()));
         let repr = try!(UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr()));
 
 
         if repr.dst_port != self.endpoint.port { return Err(Error::Rejected) }
         if repr.dst_port != self.endpoint.port { return Err(Error::Rejected) }
@@ -219,17 +219,18 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
         let packet_buf = try!(self.tx_buffer.dequeue().map_err(|()| Error::Exhausted));
         let packet_buf = try!(self.tx_buffer.dequeue().map_err(|()| Error::Exhausted));
         net_trace!("udp:{}:{}: sending {} octets",
         net_trace!("udp:{}:{}: sending {} octets",
                    self.endpoint, packet_buf.endpoint, packet_buf.size);
                    self.endpoint, packet_buf.endpoint, packet_buf.size);
-        let ip_repr = IpRepr::Unspecified {
-            src_addr: self.endpoint.addr,
-            dst_addr: packet_buf.endpoint.addr,
-            protocol: IpProtocol::Udp
-        };
-        let payload = UdpRepr {
+        let repr = UdpRepr {
             src_port: self.endpoint.port,
             src_port: self.endpoint.port,
             dst_port: packet_buf.endpoint.port,
             dst_port: packet_buf.endpoint.port,
             payload:  &packet_buf.as_ref()[..]
             payload:  &packet_buf.as_ref()[..]
         };
         };
-        emit(&ip_repr, &payload)
+        let ip_repr = IpRepr::Unspecified {
+            src_addr:    self.endpoint.addr,
+            dst_addr:    packet_buf.endpoint.addr,
+            protocol:    IpProtocol::Udp,
+            payload_len: repr.buffer_len()
+        };
+        emit(&ip_repr, &repr)
     }
     }
 }
 }
 
 

+ 2 - 6
src/wire/icmpv4.rs

@@ -352,7 +352,6 @@ pub enum Repr<'a> {
     DstUnreachable {
     DstUnreachable {
         reason: DstUnreachable,
         reason: DstUnreachable,
         header: Ipv4Repr,
         header: Ipv4Repr,
-        length: usize,
         data:   [u8; 8]
         data:   [u8; 8]
     },
     },
     #[doc(hidden)]
     #[doc(hidden)]
@@ -389,12 +388,9 @@ impl<'a> Repr<'a> {
                 if payload.len() < data.len() { return Err(Error::Truncated) }
                 if payload.len() < data.len() { return Err(Error::Truncated) }
                 data.copy_from_slice(&payload[0..8]);
                 data.copy_from_slice(&payload[0..8]);
 
 
-                let length = ip_packet.total_len() as usize - ip_packet.header_len() as usize;
-
                 Ok(Repr::DstUnreachable {
                 Ok(Repr::DstUnreachable {
                     reason: DstUnreachable::from(code),
                     reason: DstUnreachable::from(code),
                     header: ip_repr,
                     header: ip_repr,
-                    length: length,
                     data:   data
                     data:   data
                 })
                 })
             }
             }
@@ -439,13 +435,13 @@ impl<'a> Repr<'a> {
                 packet.data_mut()[..data_len].copy_from_slice(&data[..data_len])
                 packet.data_mut()[..data_len].copy_from_slice(&data[..data_len])
             },
             },
 
 
-            &Repr::DstUnreachable { reason, header, length, data } => {
+            &Repr::DstUnreachable { reason, header, data } => {
                 packet.set_msg_type(Message::DstUnreachable);
                 packet.set_msg_type(Message::DstUnreachable);
                 packet.set_msg_code(reason.into());
                 packet.set_msg_code(reason.into());
 
 
                 let mut ip_packet = Ipv4Packet::new(packet.data_mut())
                 let mut ip_packet = Ipv4Packet::new(packet.data_mut())
                                                .expect("undersized data");
                                                .expect("undersized data");
-                header.emit(&mut ip_packet, length);
+                header.emit(&mut ip_packet);
                 let mut payload = &mut ip_packet.into_inner()[header.buffer_len()..];
                 let mut payload = &mut ip_packet.into_inner()[header.buffer_len()..];
                 payload.copy_from_slice(&data[..])
                 payload.copy_from_slice(&data[..])
             }
             }

+ 25 - 13
src/wire/ip.rs

@@ -120,9 +120,10 @@ impl From<u16> for Endpoint {
 #[derive(Debug, Clone)]
 #[derive(Debug, Clone)]
 pub enum IpRepr {
 pub enum IpRepr {
     Unspecified {
     Unspecified {
-        src_addr: Address,
-        dst_addr: Address,
-        protocol: Protocol
+        src_addr:    Address,
+        dst_addr:    Address,
+        protocol:    Protocol,
+        payload_len: usize
     },
     },
     Ipv4(Ipv4Repr),
     Ipv4(Ipv4Repr),
     #[doc(hidden)]
     #[doc(hidden)]
@@ -157,6 +158,15 @@ impl IpRepr {
         }
         }
     }
     }
 
 
+    /// Return the payload length.
+    pub fn payload_len(&self) -> usize {
+        match self {
+            &IpRepr::Unspecified { payload_len, .. } => payload_len,
+            &IpRepr::Ipv4(repr) => repr.payload_len,
+            &IpRepr::__Nonexhaustive => unreachable!()
+        }
+    }
+
     /// Convert an unspecified representation into a concrete one, or return
     /// Convert an unspecified representation into a concrete one, or return
     /// `Err(Error::Unaddressable)` if not possible.
     /// `Err(Error::Unaddressable)` if not possible.
     ///
     ///
@@ -168,19 +178,20 @@ impl IpRepr {
             &IpRepr::Unspecified {
             &IpRepr::Unspecified {
                 src_addr: Address::Ipv4(src_addr),
                 src_addr: Address::Ipv4(src_addr),
                 dst_addr: Address::Ipv4(dst_addr),
                 dst_addr: Address::Ipv4(dst_addr),
-                protocol
+                protocol, payload_len
             } => {
             } => {
                 Ok(IpRepr::Ipv4(Ipv4Repr {
                 Ok(IpRepr::Ipv4(Ipv4Repr {
-                    src_addr: src_addr,
-                    dst_addr: dst_addr,
-                    protocol: protocol
+                    src_addr:    src_addr,
+                    dst_addr:    dst_addr,
+                    protocol:    protocol,
+                    payload_len: payload_len
                 }))
                 }))
             }
             }
 
 
             &IpRepr::Unspecified {
             &IpRepr::Unspecified {
                 src_addr: Address::Unspecified,
                 src_addr: Address::Unspecified,
                 dst_addr: Address::Ipv4(dst_addr),
                 dst_addr: Address::Ipv4(dst_addr),
-                protocol
+                protocol, payload_len
             } => {
             } => {
                 let mut src_addr = None;
                 let mut src_addr = None;
                 for addr in fallback_src_addrs {
                 for addr in fallback_src_addrs {
@@ -193,9 +204,10 @@ impl IpRepr {
                     }
                     }
                 }
                 }
                 Ok(IpRepr::Ipv4(Ipv4Repr {
                 Ok(IpRepr::Ipv4(Ipv4Repr {
-                    src_addr: try!(src_addr.ok_or(Error::Unaddressable)),
-                    dst_addr: dst_addr,
-                    protocol: protocol
+                    src_addr:    try!(src_addr.ok_or(Error::Unaddressable)),
+                    dst_addr:    dst_addr,
+                    protocol:    protocol,
+                    payload_len: payload_len
                 }))
                 }))
             }
             }
 
 
@@ -225,12 +237,12 @@ impl IpRepr {
     ///
     ///
     /// # Panics
     /// # Panics
     /// This function panics if invoked on an unspecified representation.
     /// This function panics if invoked on an unspecified representation.
-    pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, buffer: T, payload_len: usize) {
+    pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, buffer: T) {
         match self {
         match self {
             &IpRepr::Unspecified { .. } => panic!("unspecified IP representation"),
             &IpRepr::Unspecified { .. } => panic!("unspecified IP representation"),
             &IpRepr::Ipv4(repr) => {
             &IpRepr::Ipv4(repr) => {
                 let mut packet = Ipv4Packet::new(buffer).expect("undersized buffer");
                 let mut packet = Ipv4Packet::new(buffer).expect("undersized buffer");
-                repr.emit(&mut packet, payload_len)
+                repr.emit(&mut packet)
             }
             }
             &IpRepr::__Nonexhaustive => unreachable!()
             &IpRepr::__Nonexhaustive => unreachable!()
         }
         }

+ 31 - 24
src/wire/ipv4.rs

@@ -367,9 +367,10 @@ impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
 /// A high-level representation of an Internet Protocol version 4 packet header.
 /// A high-level representation of an Internet Protocol version 4 packet header.
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 pub struct Repr {
 pub struct Repr {
-    pub src_addr: Address,
-    pub dst_addr: Address,
-    pub protocol: Protocol
+    pub src_addr:    Address,
+    pub dst_addr:    Address,
+    pub protocol:    Protocol,
+    pub payload_len: usize
 }
 }
 
 
 impl Repr {
 impl Repr {
@@ -391,9 +392,10 @@ impl Repr {
         // All ECN values are acceptable, since ECN requires opt-in from both endpoints.
         // All ECN values are acceptable, since ECN requires opt-in from both endpoints.
         // All TTL values are acceptable, since we do not perform routing.
         // All TTL values are acceptable, since we do not perform routing.
         Ok(Repr {
         Ok(Repr {
-            src_addr: packet.src_addr(),
-            dst_addr: packet.dst_addr(),
-            protocol: packet.protocol()
+            src_addr:    packet.src_addr(),
+            dst_addr:    packet.dst_addr(),
+            protocol:    packet.protocol(),
+            payload_len: payload_len
         })
         })
     }
     }
 
 
@@ -404,13 +406,12 @@ impl Repr {
     }
     }
 
 
     /// Emit a high-level representation into an Internet Protocol version 4 packet.
     /// Emit a high-level representation into an Internet Protocol version 4 packet.
-    pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>,
-                                              payload_len: usize) {
+    pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
         packet.set_version(4);
         packet.set_version(4);
         packet.set_header_len(field::DST_ADDR.end as u8);
         packet.set_header_len(field::DST_ADDR.end as u8);
         packet.set_dscp(0);
         packet.set_dscp(0);
         packet.set_ecn(0);
         packet.set_ecn(0);
-        let total_len = packet.header_len() as u16 + payload_len as u16;
+        let total_len = packet.header_len() as u16 + self.payload_len as u16;
         packet.set_total_len(total_len);
         packet.set_total_len(total_len);
         packet.set_ident(0);
         packet.set_ident(0);
         packet.clear_flags();
         packet.clear_flags();
@@ -476,23 +477,28 @@ use super::pretty_print::{PrettyPrint, PrettyIndent};
 impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
 impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
     fn pretty_print(buffer: &AsRef<[u8]>, f: &mut fmt::Formatter,
     fn pretty_print(buffer: &AsRef<[u8]>, f: &mut fmt::Formatter,
                     indent: &mut PrettyIndent) -> fmt::Result {
                     indent: &mut PrettyIndent) -> fmt::Result {
-        let ip_packet = match Packet::new(buffer) {
+        let (ip_repr, payload) = match Packet::new(buffer) {
             Err(err) => return write!(f, "{}({})\n", indent, err),
             Err(err) => return write!(f, "{}({})\n", indent, err),
-            Ok(ip_packet) => ip_packet
+            Ok(ip_packet) => {
+                match Repr::parse(&ip_packet) {
+                    Err(err) => return write!(f, "{}{} ({})\n", indent, ip_packet, err),
+                    Ok(ip_repr) => (ip_repr, &ip_packet.payload()[..ip_repr.payload_len])
+                }
+            }
         };
         };
-        try!(write!(f, "{}{}\n", indent, ip_packet));
+        try!(write!(f, "{}{}\n", indent, ip_repr));
 
 
         indent.increase();
         indent.increase();
-        match ip_packet.protocol() {
+        match ip_repr.protocol {
             Protocol::Icmp =>
             Protocol::Icmp =>
-                super::Icmpv4Packet::<&[u8]>::pretty_print(&ip_packet.payload(), f, indent),
+                super::Icmpv4Packet::<&[u8]>::pretty_print(&payload, f, indent),
             Protocol::Udp => {
             Protocol::Udp => {
-                match super::UdpPacket::new(&ip_packet.payload()) {
+                match super::UdpPacket::new(payload) {
                     Err(err) => write!(f, "{}({})\n", indent, err),
                     Err(err) => write!(f, "{}({})\n", indent, err),
                     Ok(udp_packet) => {
                     Ok(udp_packet) => {
                         match super::UdpRepr::parse(&udp_packet,
                         match super::UdpRepr::parse(&udp_packet,
-                                                    &IpAddress::from(ip_packet.src_addr()),
-                                                    &IpAddress::from(ip_packet.dst_addr())) {
+                                                    &IpAddress::from(ip_repr.src_addr),
+                                                    &IpAddress::from(ip_repr.dst_addr)) {
                             Err(err) => write!(f, "{}{} ({})\n", indent, udp_packet, err),
                             Err(err) => write!(f, "{}{} ({})\n", indent, udp_packet, err),
                             Ok(udp_repr) => write!(f, "{}{}\n", indent, udp_repr)
                             Ok(udp_repr) => write!(f, "{}{}\n", indent, udp_repr)
                         }
                         }
@@ -500,12 +506,12 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
                 }
                 }
             }
             }
             Protocol::Tcp => {
             Protocol::Tcp => {
-                match super::TcpPacket::new(&ip_packet.payload()) {
+                match super::TcpPacket::new(payload) {
                     Err(err) => write!(f, "{}({})\n", indent, err),
                     Err(err) => write!(f, "{}({})\n", indent, err),
                     Ok(tcp_packet) => {
                     Ok(tcp_packet) => {
                         match super::TcpRepr::parse(&tcp_packet,
                         match super::TcpRepr::parse(&tcp_packet,
-                                                    &IpAddress::from(ip_packet.src_addr()),
-                                                    &IpAddress::from(ip_packet.dst_addr())) {
+                                                    &IpAddress::from(ip_repr.src_addr),
+                                                    &IpAddress::from(ip_repr.dst_addr)) {
                             Err(err) => write!(f, "{}{} ({})\n", indent, tcp_packet, err),
                             Err(err) => write!(f, "{}{} ({})\n", indent, tcp_packet, err),
                             Ok(tcp_repr) => write!(f, "{}{}\n", indent, tcp_repr)
                             Ok(tcp_repr) => write!(f, "{}{}\n", indent, tcp_repr)
                         }
                         }
@@ -592,9 +598,10 @@ mod test {
 
 
     fn packet_repr() -> Repr {
     fn packet_repr() -> Repr {
         Repr {
         Repr {
-            src_addr: Address([0x11, 0x12, 0x13, 0x14]),
-            dst_addr: Address([0x21, 0x22, 0x23, 0x24]),
-            protocol: Protocol::Icmp
+            src_addr:    Address([0x11, 0x12, 0x13, 0x14]),
+            dst_addr:    Address([0x21, 0x22, 0x23, 0x24]),
+            protocol:    Protocol::Icmp,
+            payload_len: 4
         }
         }
     }
     }
 
 
@@ -610,7 +617,7 @@ mod test {
         let repr = packet_repr();
         let repr = packet_repr();
         let mut bytes = vec![0; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
         let mut bytes = vec![0; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
         let mut packet = Packet::new(&mut bytes).unwrap();
         let mut packet = Packet::new(&mut bytes).unwrap();
-        repr.emit(&mut packet, REPR_PAYLOAD_BYTES.len());
+        repr.emit(&mut packet);
         packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
         packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
         assert_eq!(&packet.into_inner()[..], &REPR_PACKET_BYTES[..]);
         assert_eq!(&packet.into_inner()[..], &REPR_PACKET_BYTES[..]);
     }
     }

+ 7 - 6
src/wire/mod.rs

@@ -29,17 +29,18 @@
 ```rust
 ```rust
 use smoltcp::wire::*;
 use smoltcp::wire::*;
 let repr = Ipv4Repr {
 let repr = Ipv4Repr {
-    src_addr: Ipv4Address::new(10, 0, 0, 1),
-    dst_addr: Ipv4Address::new(10, 0, 0, 2),
-    protocol: IpProtocol::Tcp
+    src_addr:    Ipv4Address::new(10, 0, 0, 1),
+    dst_addr:    Ipv4Address::new(10, 0, 0, 2),
+    protocol:    IpProtocol::Tcp,
+    payload_len: 10
 };
 };
-let mut buffer = vec![0; repr.buffer_len()];
+let mut buffer = vec![0; repr.buffer_len() + 10];
 { // emission
 { // emission
     let mut packet = Ipv4Packet::new(&mut buffer).unwrap();
     let mut packet = Ipv4Packet::new(&mut buffer).unwrap();
-    repr.emit(&mut packet, /*payload size*/ 0);
+    repr.emit(&mut packet);
 }
 }
 { // parsing
 { // parsing
-    let mut packet = Ipv4Packet::new(&buffer).unwrap();
+    let packet = Ipv4Packet::new(&buffer).unwrap();
     let parsed = Ipv4Repr::parse(&packet).unwrap();
     let parsed = Ipv4Repr::parse(&packet).unwrap();
     assert_eq!(repr, parsed);
     assert_eq!(repr, parsed);
 }
 }