Browse Source

Empty transmit buffers before starting to receive.

whitequark 8 years ago
parent
commit
3335b698b4
1 changed files with 89 additions and 49 deletions
  1. 89 49
      src/iface/ethernet.rs

+ 89 - 49
src/iface/ethernet.rs

@@ -118,6 +118,12 @@ impl<'a, 'b: 'a,
             Icmpv4(Ipv4Repr, Icmpv4Repr<'a>)
         }
 
+        // First, transmit any outgoing packets.
+        loop {
+            if try!(self.emit()) { break }
+        }
+
+        // Now, receive any incoming packets.
         let rx_buffer = try!(self.device.receive());
         let eth_frame = try!(EthernetFrame::new(&rx_buffer));
 
@@ -229,7 +235,9 @@ impl<'a, 'b: 'a,
                 frame.set_ethertype(EthernetProtocolType::Arp);
 
                 let mut packet = try!(ArpPacket::new(frame.payload_mut()));
-                repr.emit(&mut packet)
+                repr.emit(&mut packet);
+
+                Ok(())
             },
 
             Response::Icmpv4(ip_repr, icmp_repr) => {
@@ -252,62 +260,94 @@ impl<'a, 'b: 'a,
 
                 let mut icmp_packet = try!(Icmpv4Packet::new(ip_packet.payload_mut()));
                 icmp_repr.emit(&mut icmp_packet);
+
+                Ok(())
             }
 
             Response::Nop => {
-                // Borrow checker is being overly careful around closures, so we have
-                // to hack around that.
-                let src_hardware_addr = self.hardware_addr;
-                let arp_cache = &mut self.arp_cache;
-                let device = &mut self.device;
-
-                for socket in self.sockets.borrow_mut() {
-                    let result = socket.dispatch(&mut |src_addr, dst_addr, protocol, payload| {
-                        let ip_repr =
-                            match (src_addr, dst_addr) {
-                                (&InternetAddress::Ipv4(src_addr),
-                                 &InternetAddress::Ipv4(dst_addr)) => {
-                                    Ipv4Repr {
-                                        src_addr: src_addr,
-                                        dst_addr: dst_addr,
-                                        protocol: protocol
+                Ok(())
+            }
+        }
+    }
+
+    pub fn emit(&mut self) -> Result<bool, Error> {
+        // Borrow checker is being overly careful around closures, so we have
+        // to hack around that.
+        let src_hardware_addr = self.hardware_addr;
+        let src_protocol_addrs = self.protocol_addrs.borrow();
+        let arp_cache = &mut self.arp_cache;
+        let device = &mut self.device;
+
+        let mut nothing_to_transmit = true;
+        for socket in self.sockets.borrow_mut() {
+            let result = socket.dispatch(&mut |src_addr, dst_addr, protocol, payload| {
+                let src_addr =
+                    match src_addr {
+                        &InternetAddress::Ipv4(_) if src_addr.is_unspecified() => {
+                            let mut assigned_addr = None;
+                            for addr in src_protocol_addrs {
+                                match addr {
+                                    addr @ &InternetAddress::Ipv4(_) => {
+                                        assigned_addr = Some(addr);
+                                        break
                                     }
-                                },
-                                _ => unreachable!()
-                            };
-
-                        let dst_hardware_addr =
-                            match arp_cache.lookup(*dst_addr) {
-                                None => return Err(Error::Unaddressable),
-                                Some(hardware_addr) => hardware_addr
-                            };
-
-                        let tx_len = EthernetFrame::<&[u8]>::buffer_len(ip_repr.buffer_len() +
-                                                                        payload.buffer_len());
-                        let mut tx_buffer = try!(device.transmit(tx_len));
-                        let mut frame = try!(EthernetFrame::new(&mut tx_buffer));
-                        frame.set_src_addr(src_hardware_addr);
-                        frame.set_dst_addr(dst_hardware_addr);
-                        frame.set_ethertype(EthernetProtocolType::Ipv4);
-
-                        let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
-                        ip_repr.emit(&mut ip_packet, payload.buffer_len());
-
-                        payload.emit(src_addr, dst_addr, ip_packet.payload_mut());
-
-                        Ok(())
-                    });
-
-                    match result {
-                        Ok(()) => break,
-                        Err(Error::Exhausted) => continue,
-                        Err(e) => return Err(e)
-                    }
+                                    _ => ()
+                                }
+                            }
+                            assigned_addr.expect(
+                                "to respond to an UDP packet without a source address,\
+                                 the interface must have an assigned address from \
+                                 the same family")
+                        },
+                        addr => addr
+                    };
+
+                let ip_repr =
+                    match (src_addr, dst_addr) {
+                        (&InternetAddress::Ipv4(src_addr),
+                         &InternetAddress::Ipv4(dst_addr)) => {
+                            Ipv4Repr {
+                                src_addr: src_addr,
+                                dst_addr: dst_addr,
+                                protocol: protocol
+                            }
+                        },
+                        _ => unreachable!()
+                    };
+
+                let dst_hardware_addr =
+                    match arp_cache.lookup(*dst_addr) {
+                        None => return Err(Error::Unaddressable),
+                        Some(hardware_addr) => hardware_addr
+                    };
+
+                let tx_len = EthernetFrame::<&[u8]>::buffer_len(ip_repr.buffer_len() +
+                                                                payload.buffer_len());
+                let mut tx_buffer = try!(device.transmit(tx_len));
+                let mut frame = try!(EthernetFrame::new(&mut tx_buffer));
+                frame.set_src_addr(src_hardware_addr);
+                frame.set_dst_addr(dst_hardware_addr);
+                frame.set_ethertype(EthernetProtocolType::Ipv4);
+
+                let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
+                ip_repr.emit(&mut ip_packet, payload.buffer_len());
+
+                payload.emit(src_addr, dst_addr, ip_packet.payload_mut());
+
+                Ok(())
+            });
+
+            match result {
+                Ok(()) => {
+                    nothing_to_transmit = false;
+                    break
                 }
+                Err(Error::Exhausted) => continue,
+                Err(e) => return Err(e)
             }
         }
 
-        Ok(())
+        Ok(nothing_to_transmit)
     }
 }