Răsfoiți Sursa

Send an ARP request when the destination is not in cache.

whitequark 8 ani în urmă
părinte
comite
ee20c49a59
1 a modificat fișierele cu 42 adăugiri și 17 ștergeri
  1. 42 17
      src/iface/ethernet.rs

+ 42 - 17
src/iface/ethernet.rs

@@ -360,24 +360,49 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
             let result = socket.dispatch(timestamp, mtu, &mut |repr, payload| {
                 let repr = try!(repr.lower(src_protocol_addrs));
 
-                let dst_hardware_addr =
-                    match arp_cache.lookup(&repr.dst_addr()) {
-                        None => return Err(Error::Unaddressable),
-                        Some(hardware_addr) => hardware_addr
-                    };
-
-                let tx_len = EthernetFrame::<&[u8]>::buffer_len(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(EthernetProtocol::Ipv4);
-
-                repr.emit(frame.payload_mut());
+                match arp_cache.lookup(&repr.dst_addr()) {
+                    Some(dst_hardware_addr) => {
+                        let tx_len = EthernetFrame::<&[u8]>::buffer_len(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(EthernetProtocol::Ipv4);
+
+                        repr.emit(frame.payload_mut());
+
+                        let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
+                        payload.emit(&repr, ip_packet.payload_mut());
+                    }
+
+                    None => {
+                        let (src_addr, dst_addr) =
+                            match (repr.src_addr(), repr.dst_addr()) {
+                                (IpAddress::Ipv4(src_addr), IpAddress::Ipv4(dst_addr)) =>
+                                    (src_addr, dst_addr),
+                                _ => unimplemented!()
+                            };
 
-                let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
-                payload.emit(&repr, ip_packet.payload_mut());
+                        let payload = ArpRepr::EthernetIpv4 {
+                            operation: ArpOperation::Request,
+                            source_hardware_addr: src_hardware_addr,
+                            source_protocol_addr: src_addr,
+                            target_hardware_addr: EthernetAddress::default(),
+                            target_protocol_addr: dst_addr,
+                        };
+
+                        let tx_len = EthernetFrame::<&[u8]>::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(EthernetAddress([0xff; 6]));
+                        frame.set_ethertype(EthernetProtocol::Arp);
+
+                        let mut arp_packet = try!(ArpPacket::new(frame.payload_mut()));
+                        payload.emit(&mut arp_packet);
+                    }
+                }
 
                 Ok(())
             });