From 4804674d8e7e5050b614c18061f9a5a41f2229cb Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Fri, 28 Oct 2022 18:52:17 +0200 Subject: [PATCH] arp: Implement ARP requests This is still missing timeout in case of no reply. This needs to be added! --- trashernet/trashernet_arp.vhd | 133 +++++++++++++++++++++++++++------- trashernet/trashernet_eth.vhd | 2 +- trashernet/trashernet_pkg.vhd | 1 + 3 files changed, 110 insertions(+), 26 deletions(-) diff --git a/trashernet/trashernet_arp.vhd b/trashernet/trashernet_arp.vhd index 4d0da19..4ea1663 100644 --- a/trashernet/trashernet_arp.vhd +++ b/trashernet/trashernet_arp.vhd @@ -43,11 +43,78 @@ architecture rtl of trashernet_arp is constant OPER_REQUEST : byte_vector := (x"00", x"01"); constant OPER_REPLY : byte_vector := (x"00", x"02"); - signal arp_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_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_rq : std_logic; -- Request to transmit an ARP reply + signal arp_tx_reply_tha : mac_addr_t; -- Target MAC to use in reply (SHA in received packet) + signal arp_tx_reply_tpa : ip_addr_t; -- Target IP to use in reply (SPA in received packet) + 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 + 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 constant BYTECOUNT_HEAD : integer := 8; -- HTYPE -> OPER constant BYTECOUNT_ADDRESSES : integer := 20; -- SHA -> TPA @@ -96,11 +163,14 @@ begin rx_fsm : process(clk, rst) is begin if rst then - state <= HEAD; - shifted <= '0'; - bytecount <= BYTECOUNT_HEAD; + state <= HEAD; + shifted <= '0'; + bytecount <= BYTECOUNT_HEAD; + arp_rx_reply_stb <= '0'; 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 state <= HEAD; -- Safe return from any state, may be overridden below bytecount <= BYTECOUNT_HEAD; @@ -136,13 +206,12 @@ begin if is_request then state <= SENDREPLY; else - report "reply"; - null; -- TODO: process response + arp_rx_reply_stb <= '1'; end if; end if; when SENDREPLY => - if arp_reply_ack then + if arp_tx_reply_ack then bytecount <= BYTECOUNT_HEAD; state <= HEAD; end if; @@ -152,16 +221,19 @@ begin end case; end if; end process rx_fsm; - arp_reply_rq <= '1' when state = SENDREPLY else '0'; - arp_reply_tha <= sr_addresses_sha; - arp_reply_tpa <= sr_addresses_spa; + arp_tx_reply_rq <= '1' when state = SENDREPLY else '0'; + arp_tx_reply_tha <= sr_addresses_sha; + arp_tx_reply_tpa <= sr_addresses_spa; + arp_rx_sha <= sr_addresses_sha; + arp_rx_spa <= sr_addresses_spa; end block rx; tx : block - signal sr : byte_vector(0 to 27); - signal arp_reply_preload : byte_vector(sr'range); - constant BYTECOUNT_MAX : integer := sr'length + 1; - signal bytecount : integer range 0 to BYTECOUNT_MAX; + signal sr : byte_vector(0 to 27); + signal arp_reply_preload : byte_vector(sr'range); + signal arp_request_preload : byte_vector(sr'range); + constant BYTECOUNT_MAX : integer := sr'length + 1; + signal bytecount : integer range 0 to BYTECOUNT_MAX; type state_t is (IDLE, TRANSMIT); signal state : state_t; @@ -169,15 +241,21 @@ begin arp_reply_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REPLY & -- Header 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 begin if rst then - arp_reply_ack <= '0'; + arp_tx_reply_ack <= '0'; + arp_tx_request_ack <= '0'; 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 sr <= sr(sr'low + 1 to sr'high) & x"00"; @@ -186,10 +264,16 @@ begin case state is when IDLE => - if arp_reply_rq then - state <= TRANSMIT; - arp_reply_ack <= '1'; - sr <= arp_reply_preload; + if arp_tx_reply_rq then + state <= TRANSMIT; + arp_tx_reply_ack <= '1'; + 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; bytecount <= BYTECOUNT_MAX; @@ -202,7 +286,6 @@ begin end if; 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_data <= sr(0); diff --git a/trashernet/trashernet_eth.vhd b/trashernet/trashernet_eth.vhd index 1f50269..e019f18 100644 --- a/trashernet/trashernet_eth.vhd +++ b/trashernet/trashernet_eth.vhd @@ -54,7 +54,7 @@ begin begin 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 '0'; diff --git a/trashernet/trashernet_pkg.vhd b/trashernet/trashernet_pkg.vhd index 2b29ee7..61e629f 100644 --- a/trashernet/trashernet_pkg.vhd +++ b/trashernet/trashernet_pkg.vhd @@ -19,6 +19,7 @@ package trashernet_pkg is -- MAC specific types 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; subtype ethertype_t is byte_vector(0 to 1);