a
    kÄ#dËŠ  ã                   @   sz  d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZmZm	Z	 d dl
mZmZmZmZmZmZmZmZmZ d dlmZ d dlmZ d dlm  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' d dl(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0 e�r d dl1m2Z2 e  3d¡Z4d Z5dZ6dZ7dZ8dZ9d Z:dZ;dZ<G dd„ deƒZ=G dd„ dƒZ>G dd„ dƒZ?dS )é    N)ÚThreadÚEventÚRLock)	ÚOptionalÚUnionÚListÚTupleÚAnyÚTypeÚcastÚCallableÚTYPE_CHECKING)ÚPacket)ÚCAN)ÚScapy_Exception)ÚSuperSocket)Úconf)ÚLINUX)ÚEDecimal)Ú
ObjectPipeÚselect_objects)ÚISOTPÚCAN_MAX_DLENÚN_PCI_SFÚN_PCI_CFÚN_PCI_FCÚN_PCI_FFÚISOTP_MAX_DLENÚISOTP_MAX_DLEN_2015)Ú	CANSocketzscapy.contrib.isotpé   é   é   é   c                
       sl   e Zd ZdZdZdddddddddef
dd„Zdd	„ Zd
d„ Zddd„Z	d‡ fdd„	Z
eddd„ƒZ‡  ZS )ÚISOTPSoftSocketa¥  
    This class is a wrapper around the ISOTPSocketImplementation, for the
    reasons described below.

    The ISOTPSoftSocket aims to be fully compatible with the Linux ISOTP
    sockets provided by the can-isotp kernel module, while being usable on any
    operating system.
    Therefore, this socket needs to be able to respond to an incoming FF frame
    with a FC frame even before the recv() method is called.
    A thread is needed for receiving CAN frames in the background, and since
    the lower layer CAN implementation is not guaranteed to have a functioning
    POSIX select(), each ISOTP socket needs its own CAN receiver thread.
    SuperSocket automatically calls the close() method when the GC destroys an
    ISOTPSoftSocket. However, note that if any thread holds a reference to
    an ISOTPSoftSocket object, it will not be collected by the GC.

    The implementation of the ISOTP protocol, along with the necessary
    thread, are stored in the ISOTPSocketImplementation class, and therefore:

    * There no reference from ISOTPSocketImplementation to ISOTPSoftSocket
    * ISOTPSoftSocket can be normally garbage collected
    * Upon destruction, ISOTPSoftSocket.close() will be called
    * ISOTPSoftSocket.close() will call ISOTPSocketImplementation.close()
    * RX background thread can be stopped by the garbage collector

    Initialize an ISOTPSoftSocket using the provided underlying can socket.

    Example (with NativeCANSocket underneath):
        >>> conf.contribs['ISOTP'] = {'use-can-isotp-kernel-module': False}
        >>> load_contrib('isotp')
        >>> with ISOTPSocket("can0", tx_id=0x641, rx_id=0x241) as sock:
        >>>     sock.send(...)

    Example (with PythonCANSocket underneath):
        >>> conf.contribs['ISOTP'] = {'use-can-isotp-kernel-module': False}
        >>> conf.contribs['CANSocket'] = {'use-python-can': True}
        >>> load_contrib('isotp')
        >>> with ISOTPSocket(CANSocket(bustype='socketcan', channel="can0"), tx_id=0x641, rx_id=0x241) as sock:
        >>>     sock.send(...)

    :param can_socket: a CANSocket instance, preferably filtering only can
                       frames with identifier equal to rx_id
    :param tx_id: the CAN identifier of the sent CAN frames
    :param rx_id: the CAN identifier of the received CAN frames
    :param ext_address: the extended address of the sent ISOTP frames
    :param rx_ext_address: the extended address of the received ISOTP frames
    :param bs: block size sent in Flow Control ISOTP frames
    :param stmin: minimum desired separation time sent in
                  Flow Control ISOTP frames
    :param padding: If True, pads sending packets with 0x00 which not
                    count to the payload.
                    Does not affect receiving packets.
    :param listen_only: Does not send Flow Control frames if a First Frame is
                        received
    :param basecls: base class of the packets emitted by this socket
    TNr   Fc                 C   s¼   t jr,tr,t|t jƒr,ddlm} ||ƒ}nt|t jƒr@tdƒ‚|| _|pL|| _	|| _
|| _t|| j
| j|| j| j	|||	d�	}ttj|ƒ| _ttj|ƒ| _|| _|
| _|
d u r¸t d¡ d S )Nr   )ÚNativeCANSocketz"Provide a CANSocket object instead)Útx_idÚrx_idÚpaddingÚext_addressÚrx_ext_addressÚbsÚstminÚlisten_onlyzProvide a basecls )ÚsixÚPY3r   Ú
isinstanceÚstring_typesZscapy.contrib.cansocket_nativer%   r   r)   r*   r&   r'   ÚISOTPSocketImplementationr   ÚsocketZinsZoutsÚimplÚbaseclsÚ	log_isotpÚwarning)ÚselfÚ
can_socketr&   r'   r)   r*   r+   r,   r(   r-   r5   r%   r4   © r:   ú\/var/www/html/gsl.tools/lib/python3.9/site-packages/scapy/contrib/isotp/isotp_soft_socket.pyÚ__init__n   s4    

÷zISOTPSoftSocket.__init__c                 C   s   | j s| j ¡  d| _ d S )NT)Úclosedr4   Úclose©r8   r:   r:   r;   r>   ›   s    
zISOTPSoftSocket.closec                 C   s   | j  ¡  d S ©N)r4   Úfailure_analysisr?   r:   r:   r;   rA   ¡   s    z ISOTPSoftSocket.failure_analysiséÿÿ  c                 C   s<   | j s0| j ¡ }|dur0| j|d t|d ƒfS | jddfS )a  Receive a complete ISOTP message, blocking until a message is
        received or the specified timeout is reached.
        If self.timeout is 0, then this function doesn't block and returns the
        first frame in the receive buffer or None if there isn't any.Nr   r    )r=   r4   Úrecvr5   Úfloat)r8   ÚxÚtupr:   r:   r;   Úrecv_raw¥   s
    
zISOTPSoftSocket.recv_rawc                    sh   t t| ƒ |¡}|d u rd S t|dƒr.| j|_t|dƒr@| j|_t|dƒrR| j|_t|dƒrd| j|_|S )Nr&   r'   r)   r*   )Úsuperr$   rC   Úhasattrr&   r'   r)   r*   )r8   rE   Úmsg©Ú	__class__r:   r;   rC   ±   s    



zISOTPSoftSocket.recvc                    s*   dd„ | D ƒ}t ||ƒ‰ ‡ fdd„| D ƒS )zmThis function is called during sendrecv() routine to wait for
        sockets to be ready to receive
        c                 S   s$   g | ]}t |tƒr|js|jj‘qS r:   ©r0   r$   r=   r4   Úrx_queue©Ú.0rE   r:   r:   r;   Ú
<listcomp>Ç   s   ÿz*ISOTPSoftSocket.select.<locals>.<listcomp>c                    s,   g | ]$}t |tƒr|js|jjˆ v r|‘qS r:   rM   rO   ©Zready_pipesr:   r;   rQ   Ì   s   ÿ)r   )ÚsocketsZremainZ	obj_pipesr:   rR   r;   ÚselectÁ   s    
zISOTPSoftSocket.select)rB   )rB   )N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Znonblocking_socketr   r<   r>   rA   rG   rC   ÚstaticmethodrT   Ú__classcell__r:   r:   rK   r;   r$   2   s&   9ö
-
r$   c                   @   s–   e Zd ZdZdZeƒ Zeƒ ZdZ	g Z
edd„ ƒZedd„ ƒZedd	„ ƒZed
d„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZG dd„ dƒZdS )ÚTimeoutSchedulerzA timeout scheduler which uses a single thread for all timeouts, unlike
    python's own Timer objects which use a thread each.çš™™™™™¹?Nc                 C   sª   |   ¡ | }|  ||¡}| j�` t | j|¡ | jd |k}| jdu rpt| jdd�}d}|| _| j	 
¡  | ¡  W d  ƒ n1 s„0    Y  |r¦| j	 ¡  t d¡ |S )z­Schedules the execution of a timeout.

        The function `callback` will be called in `timeout` seconds.

        Returns a handle that can be used to remove the timeout.r   NúTimeoutScheduler._task)ÚtargetÚnameF)Ú_timeÚHandleÚ_mutexÚheapqÚheappushÚ_handlesÚ_threadr   Ú_taskÚ_eventÚclearÚstartÚsetÚtimeÚsleep)ÚclsÚtimeoutÚcallbackÚwhenÚhandleZmust_interruptÚtr:   r:   r;   ÚscheduleÛ   s    

&

zTimeoutScheduler.schedulec                 C   st   | j �Z || jv rJd|_| j |¡ t | j¡ t| jƒdkrR| j ¡  nt	dƒ‚W d  ƒ n1 sf0    Y  dS )z8Provided its handle, cancels the execution of a timeout.Nr   zHandle not found)
rb   re   Ú_cbÚremoverc   ÚheapifyÚlenrh   rk   r   )rn   rr   r:   r:   r;   Úcancelþ   s    
zTimeoutScheduler.cancelc                 C   s:   | j � g | _W d  ƒ n1 s"0    Y  | j ¡  dS )z&Cancels the execution of all timeouts.N)rb   re   rh   rk   ©rn   r:   r:   r;   ri     s    $zTimeoutScheduler.clearc                 C   s>   | j �$ | jr| jd ndW  d  ƒ S 1 s00    Y  dS )zcReturns the next timeout to execute, or `None` if list is empty,
        without modifying the listr   N)rb   re   rz   r:   r:   r;   Ú
_peek_next  s    zTimeoutScheduler._peek_nextc                 C   sn   |   ¡ }|du r| j}n
|j| }|dkr`t d||¡ | j |¡}|   ¡ }t d||| |¡ | j ¡  dS )ziWaits until it is time to execute the provided handle, or until
        another thread calls _event.set()Nr   z3TimeoutScheduler Thread going to sleep @ %f for %fsz@TimeoutScheduler Thread awake @ %f, slept for %f, interrupted=%d)r`   ÚGRACEÚ_whenr6   Údebugrh   Úwaitri   )rn   rr   ÚnowZto_waitÚinterruptedÚnewr:   r:   r;   Ú_wait"  s    
ÿþzTimeoutScheduler._waitc                 C   s´   t  d|  ¡ ¡ d}z‚|  ¡ }|du rf|  ¡ }|du r:|}| j|| k rjW t  d|  ¡ ¡ d| _dS nd}|  |¡ |  ¡  qW t  d|  ¡ ¡ d| _nt  d|  ¡ ¡ d| _0 dS )z¬Executed in a background thread, this thread will automatically
        start when the first timeout is added and stop when the last timeout
        is removed or executed.z%TimeoutScheduler Thread spawning @ %fNz!TimeoutScheduler Thread died @ %f)r6   r~   r`   r{   r|   rf   rƒ   Ú_poll)rn   Z
time_emptyrr   r€   r:   r:   r;   rg   ?  s(    	ö
ÿr]   c                 C   s´   | j �j |  ¡ }t| jƒdks.| jd j|kr>W d  ƒ dS t | j¡}d}|durb|j}d|_W d  ƒ n1 sv0    Y  t|ƒr z
|ƒ  W q  t	y¬   t
 ¡  Y q 0 q dS )z1Execute all the callbacks that were due until nowr   NT)rb   r`   rx   re   r}   rc   Úheappopru   ÚcallableÚ	ExceptionÚ	tracebackÚ	print_exc)rn   r€   rr   rp   r:   r:   r;   r„   _  s    $
zTimeoutScheduler._pollc                   C   s   t jrt ¡ S t ¡ S r@   )r.   ÚPY2rl   Ú	monotonicr:   r:   r:   r;   r`   y  s    zTimeoutScheduler._timec                   @   sH   e Zd ZdZddgZdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dS )zTimeoutScheduler.Handlez]Handle for a timeout, consisting of a callback and a time when it
        should be executed.r}   ru   c                 C   s   || _ || _d S r@   )r}   ru   )r8   rq   Úcbr:   r:   r;   r<   …  s    z TimeoutScheduler.Handle.__init__c                 C   sz   | j du rtdƒ‚nbtj�L t| j tƒr8W d  ƒ dS d| _ t | ¡ W d  ƒ dS W d  ƒ n1 sl0    Y  dS )zKCancels this timeout, preventing it from executing its
            callbackNz+cancel() called on previous canceled HandleFT)ru   r   r[   rb   r0   Úboolry   r?   r:   r:   r;   ry   �  s    
ÿ
zTimeoutScheduler.Handle.cancelc                 C   s   t |tjƒstƒ ‚| j|jk S r@   ©r0   r[   ra   Ú	TypeErrorr}   ©r8   Úotherr:   r:   r;   Ú__lt__Ÿ  s    zTimeoutScheduler.Handle.__lt__c                 C   s   t |tjƒstƒ ‚| j|jkS r@   rŽ   r�   r:   r:   r;   Ú__le__¥  s    zTimeoutScheduler.Handle.__le__c                 C   s   t |tjƒstƒ ‚| j|jkS r@   rŽ   r�   r:   r:   r;   Ú__gt__«  s    zTimeoutScheduler.Handle.__gt__c                 C   s   t |tjƒstƒ ‚| j|jkS r@   rŽ   r�   r:   r:   r;   Ú__ge__±  s    zTimeoutScheduler.Handle.__ge__N)rU   rV   rW   rX   Ú	__slots__r<   ry   r’   r“   r”   r•   r:   r:   r:   r;   ra   €  s   ra   )rU   rV   rW   rX   r|   r   rb   r   rh   rf   re   Úclassmethodrt   ry   ri   r{   rƒ   rg   r„   rY   r`   ra   r:   r:   r:   r;   r[   Ð   s.   
"

	




r[   c                   @   s¤   e Zd ZdZd)dd„Zdd„ Zd	d
„ Zdd„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ Zd#d$„ Zd%d&„ Zd*d'd(„ZdS )+r2   a¼  
    Implementation of an ISOTP "state machine".

    Most of the ISOTP logic was taken from
    https://github.com/hartkopp/can-isotp/blob/master/net/can/isotp.c

    This class is separated from ISOTPSoftSocket to make sure the background
    thread can't hold a reference to ISOTPSoftSocket, allowing it to be
    collected by the GC.

    :param can_socket: a CANSocket instance, preferably filtering only can
                       frames with identifier equal to rx_id
    :param tx_id: the CAN identifier of the sent CAN frames
    :param rx_id: the CAN identifier of the received CAN frames
    :param padding: If True, pads sending packets with 0x00 which not
                    count to the payload.
                    Does not affect receiving packets.
    :param ext_address: Extended Address byte to be added at the
            beginning of every CAN frame _sent_ by this object. Can be None
            in order to disable extended addressing on sent frames.
    :param rx_ext_address: Extended Address byte expected to be found at
            the beginning of every CAN frame _received_ by this object. Can
            be None in order to disable extended addressing on received
            frames.
    :param bs: Block Size byte to be included in every Control
            Flow Frame sent by this object. The default value of 0 means
            that all the data will be received in a single block.
    :param stmin: Time Minimum Separation byte to be
            included in every Control Flow Frame sent by this object. The
            default value of 0 indicates that the peer will not wait any
            time between sending frames.
    :param listen_only: Disables send of flow control frames
    FNr   c
           
      C   s,  || _ || _|| _|| _d| _d| _d| _d| _|| _d| _	|d urRt
 d|¡| _	|	| _|| _|| _ttttttf f  ƒ | _d| _d | _d| _d| _d| _d| _t| _tt ƒ | _d| _d| _ d| _!d | _"d| _#d| _$d| _%d| _&t| _'d| _(d | _)d | _*t+ ,| j(| j-¡| _.t+ ,| j(| j/¡| _0d| _1d S )	Nr    Fó    ÚBéÿÿÿÿr   ç        g{®Gázt?)2r9   r'   r&   r(   Ú
fc_timeoutÚ
cf_timeoutÚfilter_warning_emittedr=   r*   Úea_hdrÚstructÚpackr-   Úrxfc_bsÚ
rxfc_stminr   r   Úbytesr   rD   r   rN   Úrx_lenÚrx_bufÚrx_snÚrx_bsÚrx_idxÚrx_tsÚ
ISOTP_IDLEÚrx_stateÚtx_queueÚtxfc_bsÚ
txfc_stminÚtx_gapÚtx_bufÚtx_snÚtx_bsÚtx_idxÚrx_ll_dlÚtx_stateÚrx_tx_poll_rateÚtx_timeout_handleÚrx_timeout_handler[   rt   Úcan_recvÚ	rx_handleÚ_sendÚ	tx_handleÚlast_rx_call)
r8   r9   r&   r'   r(   r)   r*   r+   r,   r-   r:   r:   r;   r<   Û  sV    ÿÿz"ISOTPSocketImplementation.__init__c                 C   sj   t  d¡ t  dt| jƒ¡ t  dt| jƒ¡ t  dt| jjƒ¡ t  dt| jjƒ¡ t  dt ¡ ¡ d S )NzFailure analysiszLast_rx_call: %szself.rx_handle: %szself.rx_handle._cb: %szself.rx_handle._when: %szNow: %s)	r6   r~   Ústrr¾   r»   ru   r}   r[   r`   r?   r:   r:   r;   rA     s    
z*ISOTPSocketImplementation.failure_analysisc                 C   s   |   ¡  d S r@   )r>   r?   r:   r:   r;   Ú__del__!  s    z!ISOTPSocketImplementation.__del__c                 C   sb   | j r|dtt|ƒ  7 }| jd u s.| jdkrF| j t| j|d�¡ n| j t| jd|d�¡ d S )Nó   Ìiÿ  )Ú
identifierÚdataÚextended)rÂ   ÚflagsrÃ   )r(   r   rx   r&   r9   Úsendr   )r8   Úloadr:   r:   r;   Úcan_send%  s    ÿz"ISOTPSocketImplementation.can_sendc                 C   s˜   t  ¡ | _| j | jgd¡r4| j ¡ }|r4|  |¡ | jsr| jjsr| j | jgd¡rZd}n| j}t  	|| j
¡| _n"z| j ¡  W n ty’   Y n0 d S )Nr   r›   )r[   r`   r¾   r9   rT   rC   Úon_can_recvr=   r·   rt   rº   r»   ry   r   )r8   ÚpktZ	poll_timer:   r:   r;   rº   /  s     


ÿz"ISOTPSocketImplementation.can_recvc                 C   s@   |j | jkr2| js<tjdkr<t d| j¡ d| _n
|  |¡ d S )Nr!   z<You should put a filter for identifier=%x on your CAN socketT)rÂ   r'   rž   r   Úverbr6   r7   Úon_recv©r8   Úpr:   r:   r;   rÉ   C  s    ÿz%ISOTPSocketImplementation.on_can_recvc                 C   s¸   z&t | jgdƒr$t d¡ t d¡ W n ty8   Y n0 zt | jgdƒrTt d¡ W n tyh   Y n0 d| _z| j	 
¡  W n ty�   Y n0 z| j 
¡  W n ty²   Y n0 d S )Nr   zTX queue not emptyr\   zRX queue not emptyT)r   r­   r6   r7   rl   rm   ÚOSErrorrN   r=   r»   ry   r   r½   r?   r:   r:   r;   r>   M  s(    
zISOTPSocketImplementation.closec                 C   s(   | j tkr$t| _ tjdkr$t d¡ dS )zˆMethod called every time the rx_timer times out, due to the peer not
        sending a consecutive frame within the expected time windowr!   z!RX state was reset due to timeoutN)r¬   ÚISOTP_WAIT_DATAr«   r   rË   r6   r7   r?   r:   r:   r;   Ú_rx_timer_handlerf  s    

z+ISOTPSocketImplementation._rx_timer_handlerc                 C   sL  | j tks| j tkr(t| _ t d¡ dS | j tk�rHt| jƒ}d| }| j	du rdt| _ t d¡ dS | j}|t
 dt| j ¡7 }|| j	| j| j| … 7 }|  |¡ | jd d | _|  jd7  _|  j|7  _t| j	ƒ| jkrêt| _ dS | jdk�r | j| jk�r t| _ t | j| j¡| _dS | jdk�r0qdqdt | j| j¡| _dS qddS )	zÞMethod called every time the tx_timer times out, which can happen in
        two situations: either a Flow Control frame was not received in time,
        or the Separation Time Min is expired and a new frame must be sent.z!TX state was reset due to timeoutNé   zTX buffer is not filledr™   r    é   r   )r¶   ÚISOTP_WAIT_FCÚISOTP_WAIT_FIRST_FCr«   r6   r7   ÚISOTP_SENDINGrx   rŸ   r±   r    r¡   r   r²   r´   rÈ   r³   r®   r[   rt   rœ   Ú_tx_timer_handlerr¸   r°   )r8   Zsrc_offZ	max_bytesrÇ   r:   r:   r;   r×   r  sF    
ÿ




ÿÿz+ISOTPSocketImplementation._tx_timer_handlerc                 C   sÜ   t |jƒ}t|ƒdk rdS d}| jdurRd}t|ƒdk r<dS t |d¡| jkrRdS t ||¡d@ }|tkr~|  ||d… ¡ nZ|tkrž|  	||d… |j
¡ n:|tkr¾|  ||d… |j
¡ n|tkrØ|  ||d… ¡ dS )zfFunction that must be called every time a CAN frame is received, to
        advance the state machine.r!   Nr   r    r"   éð   )r¤   rÃ   rx   r*   r.   Ú
indexbytesr   Ú_recv_fcr   Ú_recv_sfrl   r   Ú_recv_ffr   Ú_recv_cf)r8   ÚcfrÃ   ZaeZn_pcir:   r:   r;   rÌ   ¥  s&    

z!ISOTPSocketImplementation.on_recvc                 C   s¢  t  d¡ | jtkr"| jtkr"dS | jdur<| j ¡  d| _t|ƒdk r\t| _t  	d¡ dS | jtkr‚t
 |d¡| _t
 |d¡| _| jdkr¦| jdk s | jd	kr¦d| _t
 |d¡dkrÈt
 |d¡d
 }n:dt
 |d¡  kräd	krþn nt
 |d¡d@ d }nd}|| _t| _t
 |d¡d@ }|tk�rHd| _t| _t | j| j¡| _nV|tk�rlt| _t | j| j¡| _n2|tk�rŠt| _t  	d¡ dS t| _t  	d¡ dS dS )z'Process a received 'Flow Control' framezProcessing FCNr"   z+CF frame discarded because it was too shortr    r!   é   éñ   éù   g     @�@é   g     ˆÃ@r   z&Overflow happened at the receiver sidezUnknown FC frame type)r6   r~   r¶   rÔ   rÕ   r¸   ry   rx   r«   r7   r.   rÙ   r®   r¯   r°   ÚISOTP_FC_CTSr³   rÖ   r[   rt   r×   ÚISOTP_FC_WTrœ   ÚISOTP_FC_OVFLW)r8   rÃ   r°   Zisotp_fcr:   r:   r;   rÚ   Â  s^    

ÿ




ÿÿ 
ÿ
ÿ


z"ISOTPSocketImplementation._recv_fcc                 C   s�   t  d¡ | jdur$| j ¡  d| _| jtkrHtjdkrBt  d¡ t| _t	 
|d¡d@ }t|ƒd |k rldS |dd| … }| j ||f¡ dS )z'Process a received 'Single Frame' framezProcessing SFNr!   z4RX state was reset because single frame was receivedr   râ   r    )r6   r~   r¹   ry   r¬   r«   r   rË   r7   r.   rÙ   rx   rN   rÆ   )r8   rÃ   ÚtsÚlengthrJ   r:   r:   r;   rÛ   þ  s    





z"ISOTPSocketImplementation._recv_sfc                 C   sl  t  d¡ | jdur$| j ¡  d| _| jtkrHtjdkrBt  d¡ t| _t	|ƒdk rXdS t	|ƒ| _
t |d¡d@ d t |d	¡ | _d}| jdkròt |d¡d
> | _|  jt |d¡d> 7  _|  jt |d¡d> 7  _|  jt |d¡7  _d}||d… }t	|ƒ| _|| _|| _d	| _t| _| j�sP| j}|t dt| j| j¡7 }|  |¡ d| _t | j| j¡| _dS )z&Process a received 'First Frame' framezProcessing FFNr!   z3RX state was reset because first frame was receivedrÒ   r   râ   é   r    é   r"   rÓ   r#   é   é   é   ÚBBB) r6   r~   r¹   ry   r¬   r«   r   rË   r7   rx   rµ   r.   rÙ   r¥   r©   r¦   rª   r§   rÐ   r-   rŸ   r    r¡   r   r¢   r£   rÈ   r¨   r[   rt   r�   rÑ   )r8   rÃ   ræ   Z	ff_pci_szZ
data_bytesrÇ   r:   r:   r;   rÜ     sF    






ÿ


ÿz"ISOTPSocketImplementation._recv_ffc                 C   sÌ  t  d¡ | jtkrdS | jdur2| j ¡  d| _t|ƒ| jkrDdS t|ƒ| jk r|| j| j	 | jkr|t
jdkrxt  d¡ dS t |d¡d@ | jkr°t
jdkr¦t  d¡ t| _dS | jdu rØt
jdkrÎt  d¡ t| _dS | jd	 d
 | _|  j|d	d… 7  _t| jƒ| _	| j	| jk�rN| jd| j… | _t| _| j | j| jf¡ d| _dS | jdk�r¬|  jd	7  _| j| jk�r¬| j�s¬| j}|t dt| j| j¡7 }d| _|  |¡ t  d¡ t | j | j!¡| _dS )z,Process a received 'Consecutive Frame' framezProcessing CFNr!   z&Received a CF with insufficient lengthr   râ   z=RX state was reset because wrong sequence number was receivedzrx_buf not filled with data!r    rÓ   rí   zWait for another CF)"r6   r~   r¬   rÐ   r¹   ry   rx   rµ   r¥   r©   r   rË   r7   r.   rÙ   r§   r«   r¦   rN   rÆ   rª   r¢   r¨   r-   rŸ   r    r¡   r   r£   rÈ   r[   rt   r�   rÑ   )r8   rÃ   rÇ   r:   r:   r;   rÝ   J  sZ    










ÿ

ÿz"ISOTPSocketImplementation._recv_cfc                 C   s  | j tkrt d¡ dS t| _ t|ƒ}|tkr8t d¡ t| jƒ| dkr|| j}|t 	d|¡7 }||7 }t| _ |  
|¡ dS | j}|tkrž|t 	dd|¡7 }n|t 	dd|B ¡7 }|d	d
t|ƒ … }||7 }|  
|¡ || _d| _d	| _t|ƒ| _t| _ t | j| j¡| _dS )z<Begins sending an ISOTP message. This method does not block.z&Socket is already sending, retry laterNzToo much data for ISOTP messagerÒ   r™   z>HIi   z>Hr   rê   r    )r¶   r«   r6   r7   rÖ   rx   r   rŸ   r    r¡   rÈ   r   r±   r²   r³   r´   rÕ   r[   rt   rœ   r×   r¸   )r8   rE   rç   rÃ   rÇ   r:   r:   r;   Ú
begin_sendŽ  s:    





ÿz$ISOTPSocketImplementation.begin_sendc                 C   sp   | j tkr0t| jgdƒr0| j ¡ }|r0|  |¡ | jsJt | j	| j
¡| _n"z| j ¡  W n tyj   Y n0 d S )Nr   )r¶   r«   r   r­   rC   rî   r=   r[   rt   r·   r¼   r½   ry   r   )r8   rÊ   r:   r:   r;   r¼   ¶  s    


ÿzISOTPSocketImplementation._sendc                 C   s   | j  |¡ dS )zTSend an ISOTP frame and block until the message is sent or an error
        happens.N)r­   rÆ   rÍ   r:   r:   r;   rÆ   Ç  s    zISOTPSocketImplementation.sendc                 C   s&   z| j  ¡ W S  ty    Y dS 0 dS )zjReceive an ISOTP frame, blocking if none is available in the buffer
        for at most 'timeout' seconds.N)rN   rC   Ú
IndexError)r8   ro   r:   r:   r;   rC   Í  s    zISOTPSocketImplementation.recv)FNNr   r   F)N)rU   rV   rW   rX   r<   rA   rÀ   rÈ   rº   rÉ   r>   rÑ   r×   rÌ   rÚ   rÛ   rÜ   rÝ   rî   r¼   rÆ   rC   r:   r:   r:   r;   r2   ¸  s2   &      ÷
=	

3<6D(r2   )@Úloggingr    rl   rˆ   rc   r3   Ú	threadingr   r   r   Zscapy.compatr   r   r   r   r	   r
   r   r   r   Zscapy.packetr   Zscapy.layers.canr   Zscapy.libs.sixZlibsr.   Zscapy.errorr   Zscapy.supersocketr   Zscapy.configr   Zscapy.constsr   Zscapy.utilsr   Zscapy.automatonr   r   Z scapy.contrib.isotp.isotp_packetr   r   r   r   r   r   r   r   Zscapy.contrib.cansocketr   Ú	getLoggerr6   r«   rÕ   rÔ   rÐ   rÖ   rã   rä   rå   r$   r[   r2   r:   r:   r:   r;   Ú<module>	   sB   ,(
  i