
    hh                     p   d dl Z d dlZd dlZd dlZd dlmZ d dlmZ d dlm	Z	 d dl
mZ d dlmZmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZmZmZmZmZmZm Z m!Z!m"Z"m#Z# g dZ$ G d de%          Z& G d de%          Z' G d de          Z( G d d          Z) G d dee                   Z*dS )    N)defaultdict)GeneratorType)Lock)orb)RawPacket)
PacketList)DefaultSession)AnsweringMachine)SuperSocket)Scapy_Exception)
AnyUnionIterableCallableListOptionalTupleTypecastDict)EcuStateEcuEcuResponse
EcuSessionEcuAnsweringMachinec                       e Zd ZdZddgZd Zd Zed             Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zed             Zed             Zedd            ZdS )r   z
    Stores the state of an Ecu. The state is defined by a protocol, for
    example UDS or GMLAN.
    A EcuState supports comparison and serialization (command()).
    __dict__	__cache__c                     d | _         |                                D ]?\  }}t          |t                    rt	          |          }|                     ||           @d S N)r   items
isinstancer   list__setitem__)selfkwargskvs       `/mounts/lovelace/software/anaconda3/lib/python3.11/site-packages/scapy/contrib/automotive/ecu.py__init__zEcuState.__init__5   sd    LLNN 	# 	#DAq!]++ GGQ""""	# 	#    c                     t           j                                                  }t           j                                                  } j         j        d         |k    r~t                      }t          j         fd|D              D ]L}i }t          |          D ]\  }}||         ||         ||<   |                    t          di |           M||f _         j        d         S )N   c                 :    g | ]}                     |          S  )_flatten).0r)   r&   s     r*   
<listcomp>z$EcuState._expand.<locals>.<listcomp>C   s%    (J(J(Jaq)9)9(J(J(Jr,   r   r0   )
r$   r   valueskeysr   	itertoolsproduct	enumerateappendr   )r&   r4   r5   expandedxr'   ir(   s   `       r*   _expandzEcuState._expand=   s    dm**,,--DM&&(())>!T^A%6&%@%@vvH&(J(J(J(J6(J(J(JK 4 4%dOO % %DAqt|  !!F1II 2 26 2 23333&/DN~a  r,   c                 p   t          | t          t          f          r| gS t          | d          r,t          | d          rt	          |           dk    r	t          |  S t          | d          s| gS t                      }| D ]6}t          | d          r|t                              |          z  }0||gz  }7|S )N__iter____len__r.   )r#   strbyteshasattrlenr$   r   r1   )r;   	flattenedys      r*   r1   zEcuState._flattenM   s     a#u&& 	3JQ
## 	9(=(= 	#a&&A++8OJ'' 	3JFF	 	! 	!Aq*%% !X..q111		aS 		r,   c                 $    d | _         | j        |= d S r!   r   r   )r&   keys     r*   __delitem__zEcuState.__delitem__^   s    M#r,   c                 N    t          | j                                                  S r!   )rD   r   r5   r&   s    r*   r@   zEcuState.__len__c   s    4=%%''(((r,   c                     | j         |         S r!   r   r&   items     r*   __getitem__zEcuState.__getitem__g   s    }T""r,   c                 (    d | _         || j        |<   d S r!   rH   )r&   rI   values      r*   r%   zEcuState.__setitem__k   s    "cr,   c                     d                     d t          | j                                        d           D                       S )N c              3   Z   K   | ]&\  }}t          |          t          |          z   V  'd S r!   )rA   r2   r(   r)   s      r*   	<genexpr>z$EcuState.__repr__.<locals>.<genexpr>r   sN       J J41as1vvA J J J J J Jr,   c                     | d         S Nr   r0   ts    r*   <lambda>z#EcuState.__repr__.<locals>.<lambda>s   s
    1Q4 r,   rI   joinsortedr   r"   rL   s    r*   __repr__zEcuState.__repr__p   sY    ww J Jdm1133HHHJ J J J J 	Jr,   c                     t          t                    t           j                  t          j                  k    rdS 	 t	           fd j                                        D                       S # t          $ r Y dS w xY w)NFc              3   P   K   | ] }j         |         j         |         k    V  !d S r!   rN   )r2   r(   otherr&   s     r*   rX   z"EcuState.__eq__.<locals>.<genexpr>{   sJ       6 6 }Q'5>!+<< 6 6 6 6 6 6r,   )r   r   rD   r   allr5   KeyErrorr&   re   s   ``r*   __eq__zEcuState.__eq__u   s    Xu%%t}U^!4!4445	 6 6 6 6 6 $ 2 2 4 46 6 6 6 6 6 	 	 	55	s   2A8 8
BBc                      t          |t                    sdS t           fd|                                D                       S )NFc              3   D   K   | ]}|                                 v V  d S r!   )r=   )r2   sr&   s     r*   rX   z(EcuState.__contains__.<locals>.<genexpr>   s0      ??11&??????r,   )r#   r   rf   r=   rO   s   ` r*   __contains__zEcuState.__contains__   sE    $)) 	5??????????r,   c                     || k     S r!   r0   rh   s     r*   __ne__zEcuState.__ne__   s    D=  r,   c           
      (   | |k    rdS t          |           t          |          k     rdS t          |           t          |          k    rdS t          | j                                                                      t          |j                                                            }t          |          D ]}t          |j        |         t          | j        |                             sHt          dt          | j        |                   dt          |j        |                   d|          | j        |         |j        |         k     r dS | j        |         |j        |         k    r dS t          |          t          | j                  k     rt          | j                                                  	                    t          |j                                                            }t          |j                                                  	                    t          | j                                                            }t          ||          D ]\  }}||k     r dS dS t          d| j        d|j                  )NFTzCan't compare z with z for the EcuState element z;EcuStates should be identical. Something bad happen. self: z other: )rD   setr   r5   intersectionra   r#   type	TypeError
differencezip)r&   re   commonr(   
self_diffsother_diffsrl   os           r*   __lt__zEcuState.__lt__   so   5==5t99s5zz!!4t99s5zz!!5T]''))**77##%%&&( (  	 	AenQ/dmA6F1G1GHH Ji$-*++++T%.2C-D-D-D-DaaIJ J J }Q%."333tt}Q%."333uu 4 v;;T]++++T]//1122==EN''))**, ,Jen113344??DM&&(())+ +K J44    1q5544  5i04u~~O P P 	Pr,   c                 :    t          t          |                     S r!   )hashreprrL   s    r*   __hash__zEcuState.__hash__   s    DJJr,   c                 z    d | _         t          | j                                                  }|D ]
}| j        |= d S r!   )r   r$   r   r5   )r&   r5   r(   s      r*   resetzEcuState.reset   sJ    DM&&(()) 	! 	!Aa  	! 	!r,   c                     dd                     d t          | j                                        d           D                       z   dz   S )Nz	EcuState(, c                 <    g | ]\  }}|d t          |          S )=)r~   rW   s      r*   r3   z$EcuState.command.<locals>.<listcomp>   s9     < < <14777# < < <r,   c                     | d         S rZ   r0   r[   s    r*   r]   z"EcuState.command.<locals>.<lambda>   s
    QqT r,   r^   )r_   rL   s    r*   commandzEcuState.command   sh    TYY< <##%%>>1; 1; 1; < < <= = =?BC 	Cr,   c                      t           j                  dk    rt          d          t           d          rt          d           fd}|S )z
        Decorator to add a function as 'modify_ecu_state' method to a given
        class. This allows dynamic modifications and additions to a protocol.
        :param cls: A packet class to be modified
        :return: Decorator function
        r   z)Packets without fields can't be extended.modify_ecu_statez7Class already extended. Can't override existing method.c                 *    t          d|            d S )Nr   setattrfclss    r*   decorator_functionz=EcuState.extend_pkt_with_modifier.<locals>.decorator_function   s    C+Q/////r,   )rD   fields_descr   rC   r   r   s   ` r*   extend_pkt_with_modifierz!EcuState.extend_pkt_with_modifier   sv     s1$$!"MNNN3*++ 	K!IK K K	0 	0 	0 	0 	0 "!r,   c                 X    t          d |                                 D                       S )z
        Helper function to determine if a Packet contains a layer that
        modifies the EcuState.
        :param pkt: Packet to be analyzed
        :return: True if pkt contains layer that implements modify_ecu_state
        c              3   6   K   | ]}t          |d           V  dS )r   N)rC   )r2   layers     r*   rX   z+EcuState.is_modifier_pkt.<locals>.<genexpr>   sA       . . 5"455 . . . . . .r,   )anylayers)pkts    r*   is_modifier_pktzEcuState.is_modifier_pkt   s:      . . #

. . . . . 	.r,   Fc                    |r|}nt          j         |          }|                                 D ]W}t          |d          s	 |                    | ||           ,# t          $ r |j                            | ||           Y Tw xY w|S )ax  
        Helper function to get a modified EcuState from a Packet and a
        previous EcuState. An EcuState is always modified after a response
        Packet is received. In some protocols, the belonging request packet
        is necessary to determine the precise state of the Ecu

        :param response: Response packet that supports `modify_ecu_state`
        :param request: Belonging request of the response that modifies Ecu
        :param state: The previous/current EcuState
        :param modify_in_place: If True, the given EcuState will be modified
        :return: The modified EcuState or a modified copy
        r   )copyr   rC   r   rt   im_func)responserequeststatemodify_in_place	new_stater   s         r*   get_modified_ecu_statezEcuState.get_modified_ecu_state   s      	)II	%((I__&& 	M 	ME5"455 M&&x)DDDD M M M&..x)LLLLLMs   A&BBN)F)__name__
__module____qualname____doc__	__slots__r+   r=   staticmethodr1   rJ   r@   rQ   r%   rb   ri   rm   ro   r{   r   r   r   r   r   r   r0   r,   r*   r   r   -   sz        
 [)I# # #! ! !    \   
) ) )# # ## # #
J J J
	 	 	@ @ @! ! !%P %P %PN     ! ! !C C C " " \"* 	. 	. \	.    \  r,   r   c                       e Zd ZdZ	 	 ddZd Zd Zd Zd Zd	 Z	e
d
             Zed             Zed             Zd Ze
d             ZdS )r   a^  An Ecu object can be used to
        * track the states of an Ecu.
        * to log all modification to an Ecu.
        * to extract supported responses of a real Ecu.

    Example:
        >>> print("This ecu logs, tracks and creates supported responses")
        >>> my_virtual_ecu = Ecu()
        >>> my_virtual_ecu.update(PacketList([...]))
        >>> my_virtual_ecu.supported_responses
        >>> print("Another ecu just tracks")
        >>> my_tracking_ecu = Ecu(logging=False, store_supported_responses=False)
        >>> my_tracking_ecu.update(PacketList([...]))
        >>> print("Another ecu just logs all modifications to it")
        >>> my_logging_ecu = Ecu(verbose=False, store_supported_responses=False)
        >>> my_logging_ecu.update(PacketList([...]))
        >>> my_logging_ecu.log
        >>> print("Another ecu just creates supported responses")
        >>> my_response_ecu = Ecu(verbose=False, logging=False)
        >>> my_response_ecu.update(PacketList([...]))
        >>> my_response_ecu.supported_responses

    Parameters to initialize an Ecu object

    :param logging: Turn logging on or off. Default is on.
    :param verbose: Turn tracking on or off. Default is on.
    :param store_supported_responses: Create a list of supported responses if True.
    :param lookahead: Configuration for lookahead when computing supported responses
    T
   c                     t                      | _        || _        || _        || _        || _        t          t                    | _        t                      | _	        t                      | _        d S r!   )r   r   verboseloggingstore_supported_responses	lookaheadr   r$   log_Ecu__supported_responsesr	   _Ecu__unanswered_packets)r&   r   r   r   r   s        r*   r+   zEcu.__init__   sY     ZZ
)B&"t$$%)VV"$.LL!!!r,   c                 0    t          d          | _        dS )zB
        Resets the internal state to a default EcuState.
        r.   sessionN)r   r   rL   s    r*   r   z	Ecu.reset,  s    
 a(((


r,   c                     t          |t                    r|D ]}|                     |           dS t          |t                    st	          d          |                     |           dS )z
        Processes a Packet or a list of Packets, according to the chosen
        configuration.
        :param p: Packet or list of Packets
        z%Provide a Packet object for an updateN)r#   r	   updater   rt   _Ecu__update)r&   pr   s      r*   r   z
Ecu.update3  s}     a$$ 	 ! !C    ! !Av&& 	CDDDMM!r,   c                     | j         r*t          t          |           t          |                     | j        r|                     |           |                     |           dS )zv
        Processes a Packet according to the chosen configuration.
        :param pkt: Packet to be processed
        N)r   printr~   r   _Ecu__update_log _Ecu__update_supported_responsesr&   r   s     r*   __updatezEcu.__updateB  sb     < 	)$t**d3ii(((< 	#c"""))#.....r,   c                 2   |                                 D ]}t          |d          s	 |                    |          \  }}n-# t          $ r  |j                            |          \  }}Y nw xY w| j        |                             |j        |f           dS )aD  
        Checks if a packet or a layer of this packet supports the function
        `get_log`. If `get_log` is supported, this function will be executed
        and the returned log information is stored in the intern log of this
        Ecu object.
        :param pkt: A Packet to be processed for log information.
        get_logN)r   rC   r   rt   r   r   r9   time)r&   r   r   log_key	log_values        r*   __update_logzEcu.__update_logN  s     ZZ\\ 	< 	<E5),, @%*]]3%7%7" @ @ @%*]%:%:3%?%?"@ HW$$ch	%:;;;;	< 	<s   A'A,+A,c                 |   | j                             |           | j         | j         d         }|                    | j                  \  }}|| _         |D ]\  }}d}t	          j        | j                  }t                              ||| j        d           | j        sJ| j	        D ]@}	||	j
        k    r3|	j        (| j        |	j        vr|	j                            |           d} nA|rt          ||          }
| j        rt          dt          |
                     | j	                            |
           dS )au  
        Stores a given packet as supported response, if a matching request
        packet is found in a list of the latest unanswered packets. For
        performance improvements, this list of unanswered packets only contains
        a fixed number of packets, defined by the `lookahead` parameter of
        this Ecu.
        :param pkt: Packet to be processed.
        N)r   FT)	responsesz[+] )r   r9   r   srr   r   r   r   r   r   key_responsestatesr   r   r   r~   )r&   r   reduced_plistanswered
unansweredreqrespaddedcurrent_statesup_respecu_resps              r*   __update_supported_responsesz Ecu.__update_supported_responsesa  si    	!((---14>/2B2BC,//$./II*$.!! 	8 	8ICE Idj11M++D#tz4HHH1  6  80002 Jho== ..}=== EE 1  "=DAAAH| .fd8nn---&--h7777-	8 	8r,   c                     t          t          | j        d                   }t          t	          |          d                   }|dk    |dt          | j        pg           z
  dt          | j                  z
  fS )a.  
        This sorts responses in the following order:
        1. Positive responses first
        2. Lower ServiceIDs first
        3. Less supported states first
        4. Longer (more specific) responses first
        :param resp: EcuResponse to be sorted
        :return: Tuple as sort key
        r      l    )r   r   r   r   rB   rD   r   )r   first_layerservices      r*   sort_key_funczEcu.sort_key_func  ss     64#4Q#788eK((+,,4S!2333S!23335 	5r,   c                 P    | j                             | j                   | j         S )a<  
        Returns a sorted list of supported responses. The sort is done in a way
        to provide the best possible results, if this list of supported
        responses is used to simulate an real world Ecu with the
        EcuAnsweringMachine object.
        :return: A sorted list of EcuResponse objects
        r^   )r   sortr   rL   s    r*   supported_responseszEcu.supported_responses  s*     	"''D,>'???))r,   c                     | j         S )z
        A list of all unanswered packets, which were processed by this Ecu
        object.
        :return: PacketList of unanswered packets
        )r   rL   s    r*   unanswered_packetszEcu.unanswered_packets  s     ((r,   c                 *    t          | j                  S r!   )r~   r   rL   s    r*   rb   zEcu.__repr__  s    DJr,   c                       fd}|S )z
        Decorator to add a function as 'get_log' method to a given
        class. This allows dynamic modifications and additions to a protocol.
        :param cls: A packet class to be modified
        :return: Decorator function
        c                 *    t          d|            d S )Nr   r   r   s    r*   r   z7Ecu.extend_pkt_with_logging.<locals>.decorator_function  s    CA&&&&&r,   r0   r   s   ` r*   extend_pkt_with_loggingzEcu.extend_pkt_with_logging  s$    	' 	' 	' 	' 	' "!r,   N)TTTr   )r   r   r   r   r+   r   r   r   r   r   r   r   propertyr   r   rb   r   r0   r,   r*   r   r     s        : .2;=
1 
1 
1 
1) ) )  
/ 
/ 
/< < <&%8 %8 %8N 5 5 \5$ 
* 
* X
* ) ) X)      " " \" " "r,   r   c                   >     e Zd ZdZ fdZdedee         fdZ xZS )r   a  
    Tracks modification to an Ecu object 'on-the-flow'.

    The parameters for the internal Ecu object are obtained from the kwargs
    dict.

    `logging`: Turn logging on or off. Default is on.
    `verbose`: Turn tracking on or off. Default is on.
    `store_supported_responses`: Create a list of supported responses, if True.

    Example:
        >>> sniff(session=EcuSession)

    c                     t          |                    dd          |                    dd          |                    dd                    | _         t          t          |           j        |i | d S )Nr   Tr   r   )r   r   r   )r   popecusuperr   r+   )r&   argsr'   	__class__s      r*   r+   zEcuSession.__init__  sz    vzz)T::%zz)T::17<WY]1^1^` ` ` 	)j$($9&99999r,   r   returnc                 B    |sd S | j                             |           |S r!   )r   r   r   s     r*   processzEcuSession.process  s(     	4
r,   )	r   r   r   r   r+   r   r   r   __classcell__)r   s   @r*   r   r     si         : : : : :6 hv&6        r,   r   c                       e Zd ZdZd ed          dfdZed             Zed             Zed             Z	d Z
d	 Zd
 Zd Zd Zd ZdZdS )r   a  Encapsulates responses and the according EcuStates.
    A list of this objects can be used to configure an EcuAnsweringMachine.
    This is useful, if you want to clone the behaviour of a real Ecu.

    Example:
        >>> EcuResponse(EcuState(session=2, security_level=2), responses=UDS()/UDS_RDBIPR(dataIdentifier=2)/Raw(b"deadbeef1"))
        >>> EcuResponse([EcuState(session=range(2, 5), security_level=2), EcuState(session=3, security_level=5)], responses=UDS()/UDS_RDBIPR(dataIdentifier=9)/Raw(b"deadbeef4"))

    Initialize an EcuResponse capsule

    :param state: EcuState or list of EcuStates in which this response
                  is allowed to be sent. If no state provided, the response
                  packet will always be send.
    :param responses: A Packet or a list of Packet objects. By default the
                      last packet is asked if it answers an incoming
                      packet. This allows to send for example
                      `requestCorrectlyReceived-ResponsePending` packets.
    :param answers: Optional argument to provide a custom answer here:
                    `lambda resp, req: return resp.answers(req)`
                    This allows the modification of a response depending
                    on a request. Custom SecurityAccess mechanisms can
                    be implemented in this way or generic NegativeResponse
                    messages which answers to everything can be realized
                    in this way.
    Ns   c                     |d | _         n@t          |d          r(t          t          t                   |          }|| _         n|g| _         t          |t                    r|| _        nt          |t                    rt          |g          | _        ndt          |d          r5t          t          t                   |          }t          |          | _        nt          dt          |          z            || _        d S )Nr?   z Can't handle type %s as response)_EcuResponse__statesrC   r   r   r   r#   r	   _EcuResponse__responsesr   rt   rs   _EcuResponse__custom_answers)r&   r   r   answerss       r*   r+   zEcuResponse.__init__  s    = DMMuj)) (T(^U33 %!&i,, 		F(D	6** 	F)9+66DY
++ 	FT&\955I))44D2T)__DF F F !(r,   c                     | j         S r!   )r   rL   s    r*   r   zEcuResponse.states  s     }r,   c                     | j         S r!   r   rL   s    r*   r   zEcuResponse.responses  s     r,   c                      | j         d         }|S )Nr   r   s     r*   r   zEcuResponse.key_response   s     r"
r,   c                     | j         t          | j                   dk    rdS t          fd| j         D                       S )Nr   Tc              3   ,   K   | ]}|k    p|v V  d S r!   r0   )r2   rl   r   s     r*   rX   z-EcuResponse.supports_state.<locals>.<genexpr>+  s0      GGAqEz/UaZGGGGGGr,   )r   rD   r   )r&   r   s    `r*   supports_statezEcuResponse.supports_state&  sI    = C$6$6!$;$;4GGGGGGGGGGr,   c                 z    | j         |                      | j        |          S | j                            |          S r!   )r   r   r   rh   s     r*   r   zEcuResponse.answers-  s;     ,(():EBBB$,,U333r,   c                 R    t          | j                  dd | j        D             S )N, responses=c                 6    g | ]}|                                 S r0   )summary)r2   r   s     r*   r3   z(EcuResponse.__repr__.<locals>.<listcomp>8  s     ===D===r,   )r~   r   r   rL   s    r*   rb   zEcuResponse.__repr__4  s8     T]####==D,<====? 	?r,   c                 :   t          t                    t          | j                  t          j                  k    o0t	          d t          | j        j                  D                       }| j        |S t          fd| j        D                       o|S )Nc              3   \   K   | ]'\  }}t          |          t          |          k    V  (d S r!   )rB   )r2   r;   rF   s      r*   rX   z%EcuResponse.__eq__.<locals>.<genexpr>@  sO       G GAaE!HH$ G G G G G Gr,   c              3   B   K   | ]}                     |          V  d S r!   )r   )r2   rl   re   s     r*   rX   z%EcuResponse.__eq__.<locals>.<genexpr>E  s1      FF1u++A..FFFFFFr,   )r   r   rD   r   rf   rv   r   r   )r&   re   responses_equals    ` r*   ri   zEcuResponse.__eq__:  s    [%(( 3u#7#77 G G GT^5:_2F 2F G G G G G 	 = ""FFFFFFFFF   r,   c                     | |k     S r!   r0   rh   s     r*   ro   zEcuResponse.__ne__H  s     5=  r,   c                    | j         Yddd                    d | j         D                       z   dz   ddd                    d | j        D                       z   dz   dS d	dz  d                    d
 | j        D                       z   dz   S )NzEcuResponse([r   c              3   >   K   | ]}|                                 V  d S r!   r   )r2   rl   s     r*   rX   z&EcuResponse.command.<locals>.<genexpr>Q  s*      CC		CCCCCCr,   ]r  c              3   >   K   | ]}|                                 V  d S r!   r  r2   r   s     r*   rX   z&EcuResponse.command.<locals>.<genexpr>R  s*      FF		FFFFFFr,   r   zEcuResponse(responses=%s)c              3   >   K   | ]}|                                 V  d S r!   r  r  s     r*   rX   z&EcuResponse.command.<locals>.<genexpr>T  sC       A7 A7 !		A7 A7 A7 A7 A7 A7r,   )r   r`   r   rL   s    r*   r   zEcuResponse.commandM  s    =$$diiCCT]CCCCCCcIIIdiiFFT5EFFFFFFLLLN N /4tyy A7 A7%)%5A7 A7 A7 87 87 79<= =r,   )r   r   r   r   r   r+   r   r   r   r   r   r   rb   ri   ro   r   r   r0   r,   r*   r   r     s         2 "SS-=-=t ( ( ( (0   X     X    X
H H H4 4 4? ? ?     ! ! !
= = = HHHr,   r   c                   b    e Zd ZdZd Zg dZdddeddfdZed             Z	d Z
d Zd Zd
d	ZdS )r   a  AnsweringMachine which emulates the basic behaviour of a real world ECU.
    Provide a list of ``EcuResponse`` objects to configure the behaviour of a
    AnsweringMachine.

    Usage:
        >>> resp = EcuResponse(session=range(0,255), security_level=0, responses=UDS() / UDS_NR(negativeResponseCode=0x7f, requestServiceId=0x10))
        >>> sock = ISOTPSocket(can_iface, tx_id=0x700, rx_id=0x600, basecls=UDS)
        >>> answering_machine = EcuAnsweringMachine(supported_responses=[resp], main_socket=sock, basecls=UDS)
        >>> sim = threading.Thread(target=answering_machine, kwargs={'count': 4, 'timeout':5})
        >>> sim.start()
    )storeopened_socketcountfilterprnstop_filtertimeoutNc                 D   || _         | j         g| _        || j                            |           |pt          d          | _        t                      | _        t          j        | j                  | _        || _	        || _
        || j        d<   | j        | j        d<   dS )a  
        :param supported_responses: List of ``EcuResponse`` objects to define
                                    the behaviour. The default response is
                                    ``generalReject``.
        :param main_socket: Defines the object of the socket to send
                            and receive packets.
        :param broadcast_socket: Defines the object of the broadcast socket.
                                 Listen-only, responds with the main_socket.
                                 `None` to disable broadcast capabilities.
        :param basecls: Provide a basecls of the used protocol
        :param timeout: Specifies the timeout for sniffing in seconds.
        Nr.   r   r  r  )_main_socket_socketsr9   r   _initial_ecu_stater   _ecu_state_mutexr   
_ecu_state_basecls_supported_responsessniff_options)r&   r   main_socketbroadcast_socketbaseclsr  initial_ecu_states          r*   parse_optionsz!EcuAnsweringMachine.parse_optionsj  s    , (*+'M  !1222"3"Jx7J7J7J $)D$;<<$7!(/9%.2m?+++r,   c                     | j         S r!   )r  rL   s    r*   r   zEcuAnsweringMachine.state  s     r,   c                     | j         5  t          j        | j                  | _        d d d            d S # 1 swxY w Y   d S r!   )r  r   r  r  rL   s    r*   reset_statezEcuAnsweringMachine.reset_state  s    " 	A 	A"i(?@@DO	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	As   488c                 ,    t          || j                  S r!   )r#   r  )r&   r   s     r*   
is_requestzEcuAnsweringMachine.is_request  s    #t}---r,   c                    | j         | j         D ]}t          |t                    st          d          | j        5  |                    | j                  s	 ddd           U|                    |          s	 ddd           wt          	                    |j
        || j        d           |j        cddd           c S # 1 swxY w Y   t          |                     dt          |          dd         z   dz             g          S )a  
        Checks if a given request can be answered by the internal list of
        EcuResponses. First, it's evaluated if the internal EcuState of this
        AnsweringMachine is supported by an EcuResponse, next it's evaluated if
        a request answers the key_response of this EcuResponse object. The
        first fitting EcuResponse is used. If this EcuResponse modified the
        EcuState, the internal EcuState of this AnsweringMachine is updated,
        and the list of response Packets of the selected EcuResponse is
        returned. If no EcuResponse if found, a PacketList with a generic
        NegativeResponse is returned.
        :param req: A request packet
        :return: A list of response packets
        Nz@Unsupported type for response. Please use `EcuResponse` objects.T   r   r.      )r   r#   r   rt   r  r   r  r   r   r   r   r   r	   r  rB   )r&   r   r   s      r*   
make_replyzEcuAnsweringMachine.make_reply  s    $01 * *!$44 I# %H I I I * 
* 
*..t?? ! 
* 
* 
* 
* 
* 
* 
*  <<,, ! 
* 
* 
* 
* 
* 
* 
* 33)3G G G  >
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 4==eCjj1o%/1 1 2 3 3 	3s   C$C-CC		C	c                     |D ]]}t          |          dk    r't          j        t          j        dd                     | j        r| j                            |           ^dS )a7  
        Sends all Packets of a EcuResponse object. This allows to send multiple
        packets up on a request. If the list contains more than one packet,
        a random time between each packet is waited until the next packet will
        be sent.
        :param reply: List of packets to be sent.
        r.   g{Gz?g      ?N)rD   r   sleeprandomuniformr  send)r&   replysend_functionr   s       r*   
send_replyzEcuAnsweringMachine.send_reply  sk      	* 	*A5zzA~~
6>$44555  *!&&q)))		* 	*r,   r!   )r   r   r   r   function_namesniff_options_listr   r&  r   r   r)  r+  r/  r7  r0   r,   r*   r   r   Z  s        
 
 *M4 4 4
 !%!"$< $< $< $<L   XA A A
. . ."3 "3 "3H* * * * * *r,   r   )+r   r2  r   r6   collectionsr   typesr   	threadingr   scapy.compatr   scapy.packetr   r   scapy.plistr	   scapy.sessionsr
   scapy.ansmachiner   scapy.supersocketr   scapy.errorr   typingr   r   r   r   r   r   r   r   r   r   __all__objectr   r   r   r   r   r0   r,   r*   <module>rG     sv          # # # # # #                   $ $ $ $ $ $ $ $ " " " " " " ) ) ) ) ) ) - - - - - - ) ) ) ) ) ) ' ' ' ' ' '                       " " "R R R R Rv R R RjB" B" B" B" B"& B" B" B"J       :s s s s s s s slu* u* u* u* u**:6 u* u* u* u* u*r,   