Skip to content

Commit

Permalink
Send an ARP request when the destination is not in cache.
Browse files Browse the repository at this point in the history
whitequark committed Mar 5, 2017
1 parent 4083ee8 commit ee20c49
Showing 1 changed file with 42 additions and 17 deletions.
59 changes: 42 additions & 17 deletions src/iface/ethernet.rs
Original file line number Diff line number Diff line change
@@ -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(())
});

0 comments on commit ee20c49

Please sign in to comment.