------------------------------------------------------- -- CS 535 - Snort on a Chip -- Author: Michael Attig (mea1@arl.wustl.edu) -- Created: July 29th, 2003 -- File Name: ccp_rules_progammer.vhd -- File Description: This component is responsible for -- processing control packets to program options, remove -- options, and read statistic information from counters. -- -------------------------------------------------------- LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL ; ENTITY cpp_rules_programmer IS PORT ( clk : IN STD_LOGIC ; reset_l : IN STD_LOGIC ; -- these signals come from the Wrappers dataen_out_appl_int : IN STD_LOGIC ; sof_out_appl_int : IN STD_LOGIC ; -- start of frame soip_out_appl_int : IN STD_LOGIC ; -- start of ip eof_out_appl_int : IN STD_LOGIC ; -- end of frame sop_out_appl_int : IN STD_LOGIC ; -- start of payload d_out_appl_int : IN STD_LOGIC_VECTOR(31 DOWNTO 0) ; tca_out_appl_int : OUT STD_LOGIC ; -- congestion control new_pkt : OUT STD_LOGIC ; pkt_type : OUT STD_LOGIC_VECTOR(1 downto 0) -- Note: other signals will be added here later ); END cpp_rules_programmer ; ARCHITECTURE fsm OF cpp_rules_programmer IS -- Defining a new type is an easy way to both create a state machine -- and understand what's going on. TYPE states IS (idle, version, id_flags, ttl_protocol, source_ip, dest_ip, udp_port, udp_length, tcp_pkt, ip_pkt, wait_for_end ); ------------------------------------------------------------------------------- -- Signal Declarations ------------------------------------------------------------------------------- SIGNAL state, next_state : states ; SIGNAL is_udp, is_tcp : STD_LOGIC ; SIGNAL set_udp, set_tcp : STD_LOGIC ; BEGIN ------------------------------------------------------------------------------- -- NOTE: Our preferred state machine construct is to use 3 proceses. The first -- latches the next state into the state flops. The second defines logic to -- generate the next state. The third assigns state machine outputs. ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -- Process Name: latch_state -- Process Sensitive To: clk -- Process Description: This process is responsible for latching the next -- state into the flops and resetting the state upon a reset_l. ------------------------------------------------------------------------------- latch_state: PROCESS(clk) BEGIN IF (clk = '1' AND clk'EVENT) THEN IF (reset_l = '0') THEN state <= idle ; ELSE state <= next_state ; END IF ; END IF ; END PROCESS latch_state ; ------------------------------------------------------------------------------- -- NOTE: A sensitivity list is a very important part of a PROCESS declaration. -- A change in any item within the list tells the process to run. State -- transitions can be missed if the sensitivity list is not complete. If you -- want to describe something that is dependent upon the clock, you need only -- put the clk signal in the list. However, if you are defining combination -- logic,you must put every signal that is used within it. Combination logic -- is not sensitive to the global clock, which is why it has been left out -- below. ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -- Process Name: nextstate -- Process Sensitive To: state,next_state, dataen_out_appl_int, sof_out_appl_int, -- soip_out_appl_int, eof_out_appl_int, sop_out_appl_int, -- d_out_appl_int, is_udp, is_tcp -- Process Description: This process is responsible for describing the logic -- to generate the next state. ------------------------------------------------------------------------------- nextstate: PROCESS(state, next_state, dataen_out_appl_int, sof_out_appl_int, soip_out_appl_int, eof_out_appl_int, sop_out_appl_int, d_out_appl_int, is_udp, is_tcp) BEGIN ------------------------------------------------------------------------------- -- NOTE: It is important to have a default assignment. This way, can be sure -- your next state will always be assigned. In this case, the next state is -- simply assigned the current state. ------------------------------------------------------------------------------- -- default assignment next_state <= state ; CASE state IS WHEN idle => IF (sof_out_appl_int = '1') THEN next_state <= version ; END IF ; ------------------------------------------------------------------------------- -- IP Header of Packet ------------------------------------------------------------------------------- WHEN version => IF (dataen_out_appl_int = '1') THEN IF (soip_out_appl_int = '1') THEN IF (d_out_appl_int(31 DOWNTO 28) = x"4") THEN -- check if IPv4 next_state <= id_flags ; ELSE next_state <= idle ; END IF ; ELSE next_state <= version ; END IF ; END IF ; WHEN id_flags => IF (dataen_out_appl_int = '1') THEN next_state <= ttl_protocol ; END IF ; WHEN ttl_protocol => IF (dataen_out_appl_int = '1') THEN next_state <= source_ip ; END IF ; WHEN source_ip => IF (dataen_out_appl_int = '1') THEN next_state <= dest_ip ; END IF ; WHEN dest_ip => IF (dataen_out_appl_int = '1') THEN IF (is_udp = '1') THEN next_state <= udp_port ; ELSIF(is_tcp = '1') THEN next_state <= tcp_pkt ; ELSE next_state <= ip_pkt ; END IF ; ELSE next_state <= dest_ip ; END IF ; ------------------------------------------------------------------------------- -- UDP Packet ------------------------------------------------------------------------------- WHEN udp_port => IF (dataen_out_appl_int = '1') THEN IF (sop_out_appl_int = '1') THEN next_state <= udp_length ; END IF ; END IF ; WHEN udp_length => IF (dataen_out_appl_int = '1') THEN next_state <= wait_for_end ; END IF ; ------------------------------------------------------------------------------- -- TCP Packet ------------------------------------------------------------------------------- WHEN tcp_pkt => IF (dataen_out_appl_int = '1') THEN next_state <= wait_for_end ; END IF ; ------------------------------------------------------------------------------- -- IP Packet ------------------------------------------------------------------------------- WHEN ip_pkt => IF (dataen_out_appl_int = '1') THEN next_state <= wait_for_end ; END IF ; WHEN wait_for_end => IF (eof_out_appl_int = '1') THEN next_state <= idle ; END IF ; ------------------------------------------------------------------------------- -- NOTE: A WHEN OTHERS clause is also very important. This way, if your state -- machine were to somehow become confused, it would be able to default back -- to a known state. Also, if you were to forget to itemize a state above, -- this clause would be enacted. ------------------------------------------------------------------------------- WHEN OTHERS => next_state <= idle ; END CASE ; END PROCESS nextstate ; ------------------------------------------------------------------------------- -- Process Name: outputs -- Process Sensitive To: state,next_state, dataen_out_appl_int, sof_out_appl_int, -- soip_out_appl_int, eof_out_appl_int, sop_out_appl_int, -- d_out_appl_int, is_udp, is_tcp -- Process Description: This process describes the logic to generate the -- outputs. ------------------------------------------------------------------------------- outputs: PROCESS(state, next_state, dataen_out_appl_int, sof_out_appl_int, soip_out_appl_int, eof_out_appl_int, sop_out_appl_int, d_out_appl_int, is_udp, is_tcp) BEGIN -- default output values set_tcp <= '0' ; set_udp <= '0' ; new_pkt <= '0' ; pkt_type <= "00" ; -- let's say 01 is tcp -- 10 is udp CASE state IS WHEN ttl_protocol => IF (dataen_out_appl_int = '1') THEN IF (d_out_appl_int(23 DOWNTO 16) = x"06") THEN set_tcp <= '1' ; new_pkt <= '1' ; pkt_type <= "01" ; ELSIF (d_out_appl_int(23 DOWNTO 16) = x"11") THEN set_udp <= '1' ; new_pkt <= '1' ; pkt_type <= "10" ; END IF ; END IF ; WHEN OTHERS => NULL ; END CASE ; END PROCESS outputs ; ------------------------------------------------------------------------------- -- Process Name: pkttype -- Process Sensitive To: clk -- Process Description: This process describes two flops which specify the -- packet type. Later, it will be necessary to know what type of packet -- protocol we have. ------------------------------------------------------------------------------- pkttype: PROCESS(clk) BEGIN IF (clk = '1' AND clk'EVENT) THEN IF (reset_l = '0') THEN is_udp <= '0' ; is_tcp <= '0' ; ELSE IF (set_tcp = '1') THEN is_tcp <= '1' ; ELSIF (set_udp = '1') THEN is_udp <= '1' ; ELSIF (state = idle) THEN -- reset is_tcp <= '0' ; is_udp <= '0' ; END IF ; END IF ; END IF ; END PROCESS pkttype ; tca_out_appl_int <= '1' ; -- right now we can always accept -- packets (can never be backlogged) END fsm ;