a
    kÄ#d2  ã                   @   s*  d dl Z d dlmZmZmZ d dlmZ d dl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Z d dlmZ d d	lmZ g d
¢Ze d¡ zdejd d< W n  eyÈ   ddiejd< Y n0 dd„ ZG dd„ deƒZd"dd„Zd#dd„Zd$dd„Z d%dd„Z!d&dd„Z"d'dd„Z#d d!„ Z$dS )(é    N)ÚOptionalÚcastÚCallable)Úlog_automotive)ÚGMLANÚGMLAN_SAÚGMLAN_RDÚGMLAN_TDÚGMLAN_PMÚ
GMLAN_RMBA)Úconf)ÚPacket)ÚSuperSocket)ÚISOTPSocket)ÚPeriodicSenderThread)ÚGMLAN_TesterPresentSenderÚGMLAN_InitDiagnosticsÚGMLAN_GetSecurityAccessÚGMLAN_RequestDownloadÚGMLAN_TransferDataÚGMLAN_TransferPayloadÚGMLAN_ReadMemoryByAddressÚGMLAN_BroadcastSocketz‹"conf.contribs['GMLAN']['treat-response-pending-as-answer']" set to True). This is required by the GMLAN-Utils module to operate correctly.Fr   z treat-response-pending-as-answerc                 C   s0   | d u rt  d¡ dS t  dt| ƒ¡ | jdkS )NúTimeout.Fú%sé   )r   ÚdebugÚreprÚservice)Úresp© r    ú]/var/www/html/gsl.tools/lib/python3.9/site-packages/scapy/contrib/automotive/gm/gmlanutils.pyÚ_check_response'   s
    
r"   c                   @   s(   e Zd Zedd�dfdd„Zdd„ ZdS )	r   ZTesterPresent©r   é   c                 C   s   t  | |||¡ dS )zÙ Thread to send GMLAN TesterPresent packets periodically

        :param sock: socket where packet is sent periodically
        :param pkt: packet to send
        :param interval: interval between two packets
        N)r   Ú__init__)ÚselfÚsockÚpktÚintervalr    r    r!   r%   2   s    z"GMLAN_TesterPresentSender.__init__c                 C   sX   | j  ¡ sT| jjsT| jD ]8}| jj|ddd� t | j¡ | j  ¡ sL| jjr q qq d S )NFgš™™™™™¹?)ÚverboseÚtimeout)	Z_stoppedÚis_setÚ_socketÚclosedZ_pktsÚsr1ÚtimeÚsleepZ	_interval)r&   Úpr    r    r!   Úrun<   s    
zGMLAN_TesterPresentSender.runN)Ú__name__Ú
__module__Ú__qualname__r   r%   r3   r    r    r    r!   r   0   s   
r   é   c                 C   sæ   dd„ }t |ƒ}|dkrâ|d8 }tdd�}|du rB|| ||ƒs\qnt dt|ƒ¡ | |¡ |sjt d	¡ td
d�}|| ||ƒs‚qtƒ tdd� }|| ||ƒs q|s®t d	¡ tƒ tdd� }t dt|ƒ¡ | j	|ddd� dS dS )a   Send messages to put an ECU into diagnostic/programming state.

    :param sock: socket for communication.
    :param broadcast_socket: socket for broadcasting. If provided some message
                             will be sent as broadcast. Recommended when used
                             on a network with several ECUs.
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param retry: number of retries in case of failure.
    :param unittest: disable delays
    :return: True on success else False
    c                 S   s(   t  dt|ƒ¡ | j||dd�}t|ƒS )Nú
Sending %sF©r+   r*   )r   r   r   r/   r"   )r'   Úreqr+   r   r    r    r!   Ú_send_and_check_response[   s    z7GMLAN_InitDiagnostics.<locals>._send_and_check_responser   r7   ZDisableNormalCommunicationr#   NzSending %s as broadcastgš™™™™™©?ZReportProgrammingStateZrequestProgrammingMode©ÚsubfunctionZenableProgrammingModer8   gü©ñÒMbP?Fr9   T)
Úabsr   r   r   r   Úsendr0   r1   r
   r/   )r'   Zbroadcast_socketr+   ÚretryÚunittestr;   r2   r    r    r!   r   F   s2    




r   c           
      C   sh  t |ƒ}|du rdS |d dkr.t d¡ dS |dk�rd|d8 }tƒ t|d� }t d¡ | j||dd	�}t|ƒs¬|dur |jd
kr |r t d¡ |s t	 
d¡ t d¡ q.tt|ƒj}|dkrÎt d¡ dS tƒ t|d ||ƒd� }	t d¡ | j|	|dd	�}|du �rt d¡ q.t dt|ƒ¡ |jdk�rBt d¡ dS |jdkr.|jdkr.t d¡ q.q.dS )aš   Authenticate on ECU. Implements Seey-Key procedure.

    :param sock: socket to send the message on.
    :param key_function: function implementing the key algorithm.
    :param level: level of access
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param retry: number of retries in case of failure.
    :param unittest: disable internal delays
    :return: True on success.
    NFr$   r   z-Parameter Error: Level must be an odd number.r7   r<   zRequesting seed..r9   é7   z&RequiredTimeDelayNotExpired. Wait 10s.é
   zNegative Response.z/ECU security already unlocked. (seed is 0x0000)T)r=   ZsecurityKeyzResponding with key..r   r   ég   zSecurityAccess granted.r   é5   zKey invalid)r>   r   Úwarningr   r   r   r/   r"   Z
returnCoder0   r1   r   r   ZsecuritySeedr   r   )
r'   Zkey_functionÚlevelr+   r@   rA   Úrequestr   ÚseedZkeypktr    r    r!   r   ‡   sL    






ÿ




r   c                 C   s\   t |ƒ}|dkrXtƒ t|d� }| j||dd�}t|ƒr<dS |d8 }|dkrt d¡ qdS )at   Send RequestDownload message.

        Usually used before calling TransferData.

    :param sock: socket to send the message on.
    :param length: value for the message's parameter 'unCompressedMemorySize'.
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param retry: number of retries in case of failure.
    :return: True on success
    r   )Ú
memorySizeFr9   Tr7   ú
Retrying..)r>   r   r   r/   r"   r   r   )r'   Úlengthr+   r@   r(   r   r    r    r!   r   É   s    r   c                 C   s   t |ƒ}|}tjd d }|dk s2|dd|  krLt dt|ƒt|ƒ¡ dS |du sh|dksh|d	| krpd	| }tt|ƒ}t	dt
|ƒ|ƒD ]�}|}t
||d… ƒ|kr¸|||| … }	n||d… }	tƒ t|| |	d
� }
| j|
|dd�}t|ƒrôqŠ|d8 }|dk�rt d¡ q’ dS q’qŠdS )aí   Send TransferData message.

    Usually used after calling RequestDownload.

    :param sock: socket to send the message on.
    :param addr: destination memory address on the ECU.
    :param payload: data to be sent.
    :param maxmsglen: maximum length of a single iso-tp message.
                      default: maximum length
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param retry: number of retries in case of failure.
    :return: True on success.
    r   ÚGMLAN_ECU_AddressingSchemer   r$   é   ú'Error: Invalid address %s for scheme %sFNiý  )ZstartingAddressÚ
dataRecordr9   r7   rK   T)r>   r   Úcontribsr   rF   ÚhexÚstrr   ÚintÚrangeÚlenr   r	   r/   r"   r   )r'   ÚaddrÚpayloadÚ	maxmsglenr+   r@   Z
startretryÚschemeÚiZ	transdatar(   r   r    r    r!   r   ã   s6    ÿ
ÿ

r   c                 C   s4   t | t|ƒ||d�sdS t| |||||d�s0dS dS )aÁ   Send data by using GMLAN services.

    :param sock: socket to send the data on.
    :param addr: destination memory address on the ECU.
    :param payload: data to be sent.
    :param maxmsglen: maximum length of a single iso-tp message.
                      default: maximum length
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param retry: number of retries in case of failure.
    :return: True on success.
    )r+   r@   F)rY   r+   r@   T)r   rV   r   )r'   rW   rX   rY   r+   r@   r    r    r!   r     s    ÿ
ÿr   c                 C   sÞ   t |ƒ}tjd d }|dk s.|dd|  krHt dt|ƒt|ƒ¡ dS |dks\|d| kr€t d	t|ƒt|ƒtd| ƒ¡ dS |dkrÚtƒ t||d
� }| j	||dd�}t
|ƒr¾tt|ƒjS |d8 }|dkr€t d¡ q€dS )aC   Read data from ECU memory.

    :param sock: socket to send the data on.
    :param addr: source memory address on the ECU.
    :param length: bytes to read.
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param retry: number of retries in case of failure.
    :return: bytes red or None
    r   rM   r   r$   rN   rO   Niþ  zAError: Invalid length %s for scheme %s. Choose between 0x1 and %s)ZmemoryAddressrJ   Fr9   r7   rK   )r>   r   rQ   r   rF   rR   rS   r   r   r/   r"   r   r   rP   r   )r'   rW   rL   r+   r@   rZ   r(   r   r    r    r!   r   :  s*    ÿþr   c                 C   s   t | ddtddd�S )z› Returns a GMLAN broadcast socket using interface.

    :param interface: interface name
    :return: ISOTPSocket configured as GMLAN Broadcast Socket
    i  r   éþ   T)Ztx_idZrx_idZbaseclsZext_addressÚpadding)r   r   )Ú	interfacer    r    r!   r   f  s    
ÿr   )Nr7   r   F)r7   Nr   F)Nr   )NNr   )NNr   )Nr   )%r0   Zscapy.compatr   r   r   Zscapy.contrib.automotiver   Z!scapy.contrib.automotive.gm.gmlanr   r   r   r	   r
   r   Zscapy.configr   Zscapy.packetr   Zscapy.supersocketr   Zscapy.contrib.isotpr   Zscapy.utilsr   Ú__all__ÚinforQ   ÚKeyErrorr"   r   r   r   r   r   r   r   r   r    r    r    r!   Ú<module>
   sN    
	    û
D    ú
B
   ú
>   ú
!  û
,