arp: Implement ARP requests
This is still missing timeout in case of no reply. This needs to be added!
This commit is contained in:
parent
1a41120afa
commit
4804674d8e
@ -43,11 +43,78 @@ architecture rtl of trashernet_arp is
|
|||||||
constant OPER_REQUEST : byte_vector := (x"00", x"01");
|
constant OPER_REQUEST : byte_vector := (x"00", x"01");
|
||||||
constant OPER_REPLY : byte_vector := (x"00", x"02");
|
constant OPER_REPLY : byte_vector := (x"00", x"02");
|
||||||
|
|
||||||
signal arp_reply_rq : std_logic; -- Request to transmit an ARP reply
|
signal arp_tx_reply_rq : std_logic; -- Request to transmit an ARP reply
|
||||||
signal arp_reply_tha : mac_addr_t; -- Target MAC to use in reply (SHA in received packet)
|
signal arp_tx_reply_tha : mac_addr_t; -- Target MAC to use in reply (SHA in received packet)
|
||||||
signal arp_reply_tpa : ip_addr_t; -- Target IP to use in reply (SPA in received packet)
|
signal arp_tx_reply_tpa : ip_addr_t; -- Target IP to use in reply (SPA in received packet)
|
||||||
signal arp_reply_ack : std_logic; -- ARP reply has been latched and is being sent
|
signal arp_tx_reply_ack : std_logic; -- ARP reply has been latched and is being sent
|
||||||
|
|
||||||
|
signal arp_tx_request_rq : std_logic; -- Request to transmit an ARP request
|
||||||
|
signal arp_tx_request_tpa : ip_addr_t; -- IP address that we want to know the MAC address of
|
||||||
|
signal arp_tx_request_ack : std_logic; -- ARP request has been latched and is being sent
|
||||||
|
|
||||||
|
signal arp_rx_reply_stb : std_logic; -- An ARP reply was received (strobe)
|
||||||
|
signal arp_rx_sha : mac_addr_t; -- The MAC address of the reply sender, valid with arp_rx_reply
|
||||||
|
signal arp_rx_spa : ip_addr_t; -- The IP address of the reply sender, valid with arp_rx_reply
|
||||||
begin
|
begin
|
||||||
|
resolver : block
|
||||||
|
type resolver_state_t is (IDLE, QUERY_MAC);
|
||||||
|
signal state : resolver_state_t;
|
||||||
|
|
||||||
|
signal query_mac_found : std_logic;
|
||||||
|
signal query_timeout : std_logic := '0'; -- TODO: Implement
|
||||||
|
|
||||||
|
signal replied_ip : ip_addr_t;
|
||||||
|
signal replied_mac : mac_addr_t;
|
||||||
|
begin
|
||||||
|
|
||||||
|
arp_resolver_main : process(rst, clk) is
|
||||||
|
begin
|
||||||
|
if rst then
|
||||||
|
state <= IDLE;
|
||||||
|
replied_ip <= (others => x"00"); -- 0.0.0.0
|
||||||
|
arp_out.arp_ok_stb <= '0';
|
||||||
|
arp_out.arp_fail_stb <= '0';
|
||||||
|
arp_tx_request_rq <= '0';
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
arp_out.arp_ok_stb <= '0';
|
||||||
|
arp_out.arp_fail_stb <= '0';
|
||||||
|
|
||||||
|
if arp_rx_reply_stb then
|
||||||
|
if arp_tx_request_tpa = arp_rx_spa then -- If this reply is actually for our request
|
||||||
|
replied_mac <= arp_rx_sha;
|
||||||
|
replied_ip <= arp_rx_spa;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
case state is
|
||||||
|
when IDLE =>
|
||||||
|
if arp_in.arp_query_stb then
|
||||||
|
if query_mac_found then
|
||||||
|
arp_out.arp_ok_stb <= '1';
|
||||||
|
else
|
||||||
|
arp_tx_request_rq <= '1';
|
||||||
|
state <= QUERY_MAC;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when QUERY_MAC =>
|
||||||
|
if arp_tx_request_ack then
|
||||||
|
arp_tx_request_rq <= '0';
|
||||||
|
end if;
|
||||||
|
if query_mac_found or query_timeout then
|
||||||
|
arp_out.arp_ok_stb <= query_mac_found;
|
||||||
|
arp_out.arp_fail_stb <= not query_mac_found;
|
||||||
|
state <= IDLE;
|
||||||
|
end if;
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
end process arp_resolver_main;
|
||||||
|
query_mac_found <= '1' when (arp_tx_request_tpa = replied_ip) else '0';
|
||||||
|
arp_out.arp_mac <= replied_mac;
|
||||||
|
arp_tx_request_tpa <= arp_in.arp_ip;
|
||||||
|
end block resolver;
|
||||||
|
|
||||||
rx : block
|
rx : block
|
||||||
constant BYTECOUNT_HEAD : integer := 8; -- HTYPE -> OPER
|
constant BYTECOUNT_HEAD : integer := 8; -- HTYPE -> OPER
|
||||||
constant BYTECOUNT_ADDRESSES : integer := 20; -- SHA -> TPA
|
constant BYTECOUNT_ADDRESSES : integer := 20; -- SHA -> TPA
|
||||||
@ -99,8 +166,11 @@ begin
|
|||||||
state <= HEAD;
|
state <= HEAD;
|
||||||
shifted <= '0';
|
shifted <= '0';
|
||||||
bytecount <= BYTECOUNT_HEAD;
|
bytecount <= BYTECOUNT_HEAD;
|
||||||
|
arp_rx_reply_stb <= '0';
|
||||||
|
|
||||||
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
||||||
|
arp_rx_reply_stb <= '0';
|
||||||
|
|
||||||
if (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
|
if (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
|
||||||
state <= HEAD; -- Safe return from any state, may be overridden below
|
state <= HEAD; -- Safe return from any state, may be overridden below
|
||||||
bytecount <= BYTECOUNT_HEAD;
|
bytecount <= BYTECOUNT_HEAD;
|
||||||
@ -136,13 +206,12 @@ begin
|
|||||||
if is_request then
|
if is_request then
|
||||||
state <= SENDREPLY;
|
state <= SENDREPLY;
|
||||||
else
|
else
|
||||||
report "reply";
|
arp_rx_reply_stb <= '1';
|
||||||
null; -- TODO: process response
|
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when SENDREPLY =>
|
when SENDREPLY =>
|
||||||
if arp_reply_ack then
|
if arp_tx_reply_ack then
|
||||||
bytecount <= BYTECOUNT_HEAD;
|
bytecount <= BYTECOUNT_HEAD;
|
||||||
state <= HEAD;
|
state <= HEAD;
|
||||||
end if;
|
end if;
|
||||||
@ -152,14 +221,17 @@ begin
|
|||||||
end case;
|
end case;
|
||||||
end if;
|
end if;
|
||||||
end process rx_fsm;
|
end process rx_fsm;
|
||||||
arp_reply_rq <= '1' when state = SENDREPLY else '0';
|
arp_tx_reply_rq <= '1' when state = SENDREPLY else '0';
|
||||||
arp_reply_tha <= sr_addresses_sha;
|
arp_tx_reply_tha <= sr_addresses_sha;
|
||||||
arp_reply_tpa <= sr_addresses_spa;
|
arp_tx_reply_tpa <= sr_addresses_spa;
|
||||||
|
arp_rx_sha <= sr_addresses_sha;
|
||||||
|
arp_rx_spa <= sr_addresses_spa;
|
||||||
end block rx;
|
end block rx;
|
||||||
|
|
||||||
tx : block
|
tx : block
|
||||||
signal sr : byte_vector(0 to 27);
|
signal sr : byte_vector(0 to 27);
|
||||||
signal arp_reply_preload : byte_vector(sr'range);
|
signal arp_reply_preload : byte_vector(sr'range);
|
||||||
|
signal arp_request_preload : byte_vector(sr'range);
|
||||||
constant BYTECOUNT_MAX : integer := sr'length + 1;
|
constant BYTECOUNT_MAX : integer := sr'length + 1;
|
||||||
signal bytecount : integer range 0 to BYTECOUNT_MAX;
|
signal bytecount : integer range 0 to BYTECOUNT_MAX;
|
||||||
|
|
||||||
@ -169,15 +241,21 @@ begin
|
|||||||
|
|
||||||
arp_reply_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REPLY & -- Header
|
arp_reply_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REPLY & -- Header
|
||||||
mac_config.mac_address & ip_config.ip_address & -- Sender
|
mac_config.mac_address & ip_config.ip_address & -- Sender
|
||||||
arp_reply_tha & arp_reply_tpa; -- Target
|
arp_tx_reply_tha & arp_tx_reply_tpa; -- Target
|
||||||
|
|
||||||
|
arp_request_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REQUEST & -- Header
|
||||||
|
mac_config.mac_address & ip_config.ip_address & -- Sender
|
||||||
|
mac_addr_t'(x"00", x"00", x"00", x"00", x"00", x"00") & arp_tx_request_tpa; -- Target
|
||||||
|
|
||||||
tx_fsm : process(clk, rst) is
|
tx_fsm : process(clk, rst) is
|
||||||
begin
|
begin
|
||||||
if rst then
|
if rst then
|
||||||
arp_reply_ack <= '0';
|
arp_tx_reply_ack <= '0';
|
||||||
|
arp_tx_request_ack <= '0';
|
||||||
|
|
||||||
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
||||||
arp_reply_ack <= '0';
|
arp_tx_reply_ack <= '0';
|
||||||
|
arp_tx_request_ack <= '0';
|
||||||
|
|
||||||
if (ethernet_ii_out.tx_data_ack = '1') and (bytecount > 0) then
|
if (ethernet_ii_out.tx_data_ack = '1') and (bytecount > 0) then
|
||||||
sr <= sr(sr'low + 1 to sr'high) & x"00";
|
sr <= sr(sr'low + 1 to sr'high) & x"00";
|
||||||
@ -186,10 +264,16 @@ begin
|
|||||||
|
|
||||||
case state is
|
case state is
|
||||||
when IDLE =>
|
when IDLE =>
|
||||||
if arp_reply_rq then
|
if arp_tx_reply_rq then
|
||||||
state <= TRANSMIT;
|
state <= TRANSMIT;
|
||||||
arp_reply_ack <= '1';
|
arp_tx_reply_ack <= '1';
|
||||||
sr <= arp_reply_preload;
|
sr <= arp_reply_preload;
|
||||||
|
ethernet_ii_in.tx_mac_address <= arp_tx_reply_tha;
|
||||||
|
elsif arp_tx_request_rq then
|
||||||
|
state <= TRANSMIT;
|
||||||
|
arp_tx_request_ack <= '1';
|
||||||
|
sr <= arp_request_preload;
|
||||||
|
ethernet_ii_in.tx_mac_address <= MAC_ADDR_BROADCAST;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
bytecount <= BYTECOUNT_MAX;
|
bytecount <= BYTECOUNT_MAX;
|
||||||
@ -202,7 +286,6 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
end process tx_fsm;
|
end process tx_fsm;
|
||||||
|
|
||||||
ethernet_ii_in.tx_mac_address <= arp_reply_tha;
|
|
||||||
ethernet_ii_in.tx_en <= '1' when state = TRANSMIT else '0';
|
ethernet_ii_in.tx_en <= '1' when state = TRANSMIT else '0';
|
||||||
ethernet_ii_in.tx_data <= sr(0);
|
ethernet_ii_in.tx_data <= sr(0);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ begin
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
mac_destination_matches <= '1' when --
|
mac_destination_matches <= '1' when --
|
||||||
((mac_out.rx_header.mac_destination = (x"FF", x"FF", x"FF", x"FF", x"FF", x"FF")) or --
|
((mac_out.rx_header.mac_destination = MAC_ADDR_BROADCAST) or --
|
||||||
(mac_out.rx_header.mac_destination = config.mac_address)) else
|
(mac_out.rx_header.mac_destination = config.mac_address)) else
|
||||||
'0';
|
'0';
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ package trashernet_pkg is
|
|||||||
|
|
||||||
-- MAC specific types
|
-- MAC specific types
|
||||||
subtype mac_addr_t is byte_vector(0 to 5);
|
subtype mac_addr_t is byte_vector(0 to 5);
|
||||||
|
constant MAC_ADDR_BROADCAST : mac_addr_t := (others => x"FF");
|
||||||
function mac_to_string(constant mac_address : in mac_addr_t) return string;
|
function mac_to_string(constant mac_address : in mac_addr_t) return string;
|
||||||
subtype ethertype_t is byte_vector(0 to 1);
|
subtype ethertype_t is byte_vector(0 to 1);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user