a
    kÄ#dZO  ã                   @   sÀ  d Z ddl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mZ ddlmZmZ ddlm  mZ ddlmZmZmZ G dd	„ d	eƒZG d
d„ deƒZG dd„ deƒZG dd„ deeƒZdddœZdddœZG dd„ deƒZ G dd„ de ƒZ!G dd„ de ƒZ"G dd„ de ƒZ#G dd„ de ƒZ$G dd „ d e ƒZ%G d!d"„ d"e ƒZ&G d#d$„ d$e ƒZ'G d%d&„ d&e ƒZ(G d'd(„ d(e ƒZ)G d)d*„ d*e ƒZ*G d+d,„ d,e ƒZ+G d-d.„ d.e ƒZ,G d/d0„ d0e ƒZ-G d1d2„ d2e ƒZ.G d3d4„ d4eƒZ/eee/d5d6� eee/d5d6� ee/e!d7d6� ee/e"d7d6� ee/e#d7d6� ee/e$d7d6� ee/e%d7d6� ee/e&d7d6� ee/e'd7d6� ee/e(d7d6� ee/e)d7d6� ee/e*d7d6� ee/e+d7d6� ee/e,d7d6� ee/e-d7d6� ee/e.d7d6� dS )8aí  
    EtherCat automation protocol
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    :author:    Thomas Tannhaeuser, hecke@naberius.de

    :description:

        This module provides Scapy layers for the EtherCat protocol.

        normative references:
            - IEC 61158-3-12 - data link service and topology description
            - IEC 61158-4-12 - protocol specification

        Currently only read/write services as defined in IEC 61158-4-12,
        sec. 5.4 are supported.

    :TODO:

        - Mailbox service (sec. 5.5)
        - Network variable service (sec. 5.6)

    :NOTES:

        - EtherCat frame type defaults to TYPE-12-PDU (0x01) using xxx bytes
          of padding
        - padding for minimum frame size is added automatically

é    N)Úraw)Úlog_runtimeÚScapy_Exception)ÚBitFieldÚ	ByteFieldÚLEShortFieldÚFieldListFieldÚ
LEIntFieldÚFieldLenFieldÚ
_EnumFieldÚ	EnumField)ÚEtherÚDot1Q)Úbind_layersÚPacketÚPaddingc                   @   s   e Zd ZdZdS )ÚLEBitFieldSequenceExceptionz,
    thrown by EtherCat structure tests
    N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r   r   úM/var/www/html/gsl.tools/lib/python3.9/site-packages/scapy/contrib/ethercat.pyr   9   s   r   c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	Ú
LEBitFieldz1
    a little endian version of the BitField
    c                 C   sn   |j  | ¡}z:|j ||  }t|ƒturD|jjturDtd | j¡ƒ‚W n" t	yh   td | j¡ƒ‚Y n0 dS )z»
        check if the field addressed by given index relative to this field
        shares type of this field so we can catch a mix of LEBitField
        and BitField/other types
        zBfield after field {} must be of type LEBitField or derived classesz7Missing further LEBitField based fields after field {} N)
Úfields_descÚindexÚtyper   Ú	__class__Ú__base__r   ÚformatÚnameÚ
IndexError)ÚselfÚpktr   Zmy_idxZ
next_fieldr   r   r   Ú_check_field_typeE   s    
ÿþ
þzLEBitField._check_field_typec                 C   s:  t |ƒtu r2t|ƒdkr2|\}}}}|  |d¡ nd}g }|| j7 }| | j|  ||¡f¡ |d r€|  |d¡ |||t tƒfS | ¡  d}d}t	ƒ }	|D ]–\}
}|
|k rÂ||
 }|||> O }qšq¢|
|k�r|
|8 }
|||
? O }t
 d|¡|	 }	d}d}|d|
 d M }q¢q¢||O }t
 d|¡|	 }	d}d}qšq¢qš||	 S )a×  

        :param pkt: packet instance the raw string s and field belongs to
        :param s:   raw string representing the frame
        :param val: value
        :return: final raw string, tuple (s, bitsdone, data) if in between bit field  # noqa: E501

        as we don't know the final size of the full bitfield we need to accumulate the data.  # noqa: E501
        if we reach a field that ends at a octet boundary, we build the whole string  # noqa: E501

        é   éÿÿÿÿr   é   é   z!Bé   )r   ÚtupleÚlenr$   ÚsizeÚappendÚi2mr   ÚreverseÚ	bytearrayÚstructÚpack)r"   r#   ÚsÚvalZbitsdoneÚdataÚ_ÚoctetZremaining_lenÚoctetsr,   r   r   r   ÚaddfieldY   sB    

zLEBitField.addfieldc                 C   sp  t |ƒtu r$t|ƒdkr$|\}}}nd}g }|| j7 }| | ¡ |d rV|||fdfS d}d}d}d}|| }	|	j}
d}t|ƒ}|d }|d|… D ]Æ}|d7 }d}|r”|
|krÒ|||> O }||j|	j< d}|}q¤|
|k �r0||d|
 d @ |> O }||j|	j< ||
L }||
8 }|d7 }|| }	|	j}
d}d}q¤|
|kr¤|||> O }||7 }|
|8 }
d}q¤q”||d… |fS dS )a  
        extract data from raw str

        collect all instances belonging to the bit field set.
        if we reach a field that ends at a octet boundary, dissect the whole bit field at once  # noqa: E501

        :param pkt: packet instance the field belongs to
        :param s: raw string representing the frame -or- tuple containing raw str, number of bits and array of fields  # noqa: E501
        :return: tuple containing raw str, number of bits and array of fields -or- remaining raw str and value of this  # noqa: E501
        é   r   r'   Nr(   r)   )r   r*   r+   r,   r-   r0   Úfieldsr    )r"   r#   r3   Zbits_in_setr;   Zcur_valZcur_val_bit_idxZthis_valZ	field_idxÚfieldZfield_required_bitsÚidxZbf_total_byte_lengthr7   Zoctet_bits_leftr   r   r   Úgetfield—   sT    


zLEBitField.getfieldN)r   r   r   r   r$   r9   r>   r   r   r   r   r   @   s   >r   c                   @   s0   e Zd Zg d¢Zdddd„ fdd„Zdd„ ZdS )	ÚLEBitFieldLenField)Ú	length_ofÚcount_ofÚadjustNc                 C   s   |S ©Nr   )r#   Úxr   r   r   Ú<lambda>ø   ó    zLEBitFieldLenField.<lambda>c                 C   s&   t  | |||¡ || _|| _|| _d S rC   )r   Ú__init__r@   rA   rB   )r"   r    Údefaultr,   r@   rA   rB   r   r   r   rG   ø   s    zLEBitFieldLenField.__init__c                 C   s   t jrtjjntj| ||ƒS rC   )ÚsixÚPY2r
   r.   Ú__func__)r"   r#   rD   r   r   r   r.   þ   s    zLEBitFieldLenField.i2m)r   r   r   Ú	__slots__rG   r.   r   r   r   r   r?   õ   s   r?   c                   @   s   e Zd ZejZdd„ ZdS )ÚLEBitEnumFieldc                 C   s(   t  | |||¡ |dk | _t|ƒ| _d S )Nr   )r   rG   ÚrevÚabsr,   )r"   r    rH   r,   Úenumr   r   r   rG     s    
zLEBitEnumField.__init__N)r   r   r   r   rL   rG   r   r   r   r   rM     s   rM   zFRAME-NOT-CIRCULATINGzFRAME-CIRCULATED-ONCE)r   r(   zLAST-TYPE12-PDUzTYPE12-PDU-FOLLOWSc                   @   s  e Zd ZdZdd„ Zdd„ Zeddƒeddƒed	dƒed
dddd�e	dddƒe
dddeƒe
dddeƒeddƒedg eddƒdd„ d�eddƒg
ZeZeddƒeddƒed
dddd�e	dddƒe
dddeƒe
dddeƒeddƒedg eddƒdd„ d�eddƒg	ZdS )ÚEtherCatType12DLPDUz#
    Type12 message base class
    c                 C   s”   t | jƒ}|dkr"td |d¡ƒ‚| jdur<| jr6dnd}n|rFd}nd}|rbt|d dB gƒ}nt|d d@ gƒ}|dd… | |d	d…  | S )
zî

        set next attr automatically if not set explicitly by user

        :param pkt: raw string containing the current layer
        :param pay: raw string containing the payload
        :return: <new current layer> + payload
        éÿ  z7payload size {} exceeds maximum length {} of data size.NTFé   é€   é   r'   )r+   r5   Ú
ValueErrorr   Únextr0   )r"   r#   ÚpayÚdata_lenZhas_nextZ	next_flagr   r   r   Ú
post_build  s    

ÿ
zEtherCatType12DLPDU.post_buildc                 C   sL   z|d }t j| W S  tyF   t d | jj¡¡ t 	| |¡ Y S 0 d S ©Nr   z8{}.guess_payload_class() - unknown or invalid DLPDU type©
ÚEtherCatÚETHERCAT_TYPE12_DLPDU_TYPESÚKeyErrorr   Úerrorr   r   r   r   Úguess_payload_class©r"   ÚpayloadZ
dlpdu_typer   r   r   ra   <  s    ÿÿz'EtherCatType12DLPDU.guess_payload_classr=   r   ZadpZador+   Né   r5   )rA   Ú	_reservedr:   Úcr(   rW   ZirqÚ c                 C   s   | j S rC   ©r+   ©r#   r   r   r   rE   S  rF   zEtherCatType12DLPDU.<lambda>)Z
count_fromZwkcZadrc                 C   s   | j S rC   rh   ri   r   r   r   rE   b  rF   )r   r   r   r   rZ   ra   r   r   r?   r   rM   Ú"ETHERCAT_TYPE_12_CIRCULATING_FRAMEÚETHERCAT_TYPE_12_NEXT_FRAMEr   ÚPHYSICAL_ADDRESSING_DESCÚBROADCAST_ADDRESSING_DESCr	   ÚLOGICAL_ADDRESSING_DESCr   r   r   r   rQ     s:   
ÿõ
ÿörQ   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatAPRDz`
    APRD - Auto Increment Physical Read
    (IEC 61158-5-12, sec. 5.4.1.2 tab. 14 / p. 32)
    Ú_cmdr(   N©r   r   r   r   r   rQ   rl   r   r   r   r   r   ro   k  s   
ÿro   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatFPRDzd
    FPRD - Configured address physical read
    (IEC 61158-5-12, sec. 5.4.1.3 tab. 15 / p. 33)
    rp   r%   Nrq   r   r   r   r   rr   u  s   
ÿrr   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatBRDzQ
    BRD - Broadcast read
    (IEC 61158-5-12, sec. 5.4.1.4 tab. 16 / p. 34)
    rp   rS   N©r   r   r   r   r   rQ   rm   r   r   r   r   r   rs     s   
ÿrs   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatLRDzO
    LRD - Logical read
    (IEC 61158-5-12, sec. 5.4.1.5 tab. 17 / p. 36)
    rp   é
   N©r   r   r   r   r   rQ   rn   r   r   r   r   r   ru   ‰  s   
ÿru   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatAPWRza
    APWR - Auto Increment Physical Write
    (IEC 61158-5-12, sec. 5.4.2.2 tab. 18 / p. 37)
    rp   r)   Nrq   r   r   r   r   rx   ˜  s   
ÿrx   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatFPWRze
    FPWR - Configured address physical write
    (IEC 61158-5-12, sec. 5.4.2.3 tab. 19 / p. 38)
    rp   é   Nrq   r   r   r   r   ry   ¢  s   
ÿry   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatBWRzM
    BWR - Broadcast read (IEC 61158-5-12, sec. 5.4.2.4 tab. 20 / p. 39)
    rp   r'   Nrt   r   r   r   r   r{   ¬  s   
ÿr{   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatLWRzP
    LWR - Logical write
    (IEC 61158-5-12, sec. 5.4.2.5 tab. 21 / p. 40)
    rp   rd   Nrw   r   r   r   r   r|   µ  s   
ÿr|   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatAPRWzf
    APRW - Auto Increment Physical Read Write
    (IEC 61158-5-12, sec. 5.4.3.1 tab. 22 / p. 41)
    rp   r:   Nrq   r   r   r   r   r}   Ä  s   
ÿr}   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatFPRWzj
    FPRW - Configured address physical read write
    (IEC 61158-5-12, sec. 5.4.3.2 tab. 23 / p. 43)
    rp   é   Nrq   r   r   r   r   r~   Î  s   
ÿr~   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatBRWzW
    BRW - Broadcast read write
    (IEC 61158-5-12, sec. 5.4.3.3 tab. 24 / p. 39)
    rp   é	   Nrt   r   r   r   r   r€   Ø  s   
ÿr€   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatLRWzU
    LRW - Logical read write
    (IEC 61158-5-12, sec. 5.4.3.4 tab. 25 / p. 45)
    rp   é   Nrw   r   r   r   r   r‚   â  s   
ÿr‚   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatARMWzo
    ARMW - Auto increment physical read multiple write
    (IEC 61158-5-12, sec. 5.4.3.5 tab. 26 / p. 46)
    rp   é   Nrq   r   r   r   r   r„   ì  s   
ÿr„   c                   @   s"   e Zd ZdZeddƒgej ZdS )ÚEtherCatFRMWzs
    FRMW - Configured address physical read multiple write
    (IEC 61158-5-12, sec. 5.4.3.6 tab. 27 / p. 47)
    rp   é   Nrq   r   r   r   r   r†   ö  s   
ÿr†   c                   @   s€   e Zd ZdZdZdZdZdZdddd	œZe	d
ddƒe	dddƒe	dddƒgZ
eeeeeeeeeeeeeedœZdd„ Zdd„ ZdS )r]   z&
    Common EtherCat header layer
    r‡   r%   é@   r)   zTYPE-12-PDUzNETWORK-VARIABLESZMAILBOX)r(   r%   rz   Úlengthr   rd   re   r(   r   )r(   r%   rS   rv   r)   rz   r'   rd   r:   r   r�   rƒ   r…   r‡   c           	      C   sà   G dd„ dt ƒ}t|ƒ}|dkr0td |d¡ƒ‚|| _d}| j}|r^t|tƒr^|d7 }|j}q@t|tƒspt	dƒ‚t
jt
j| t
j | t
j  }|dkrÈtƒ }d| |_t|| j| jd	�ƒ| t|ƒ S t|| j| jd	�ƒ| S )
aÆ  
        need to set the length of the whole PDU manually
        to avoid any bit fiddling use a dummy class to build the layer content

        also add padding if frame is < 64 bytes

        Note: padding only handles Ether/n*Dot1Q/EtherCat
              (no special mumbo jumbo)

        :param pkt: raw string containing the current layer
        :param pay: raw string containing the payload
        :return: <new current layer> + payload
        c                   @   s2   e Zd ZdZedddƒedddƒeddd	ƒgZdS )
z0EtherCat.post_build.<locals>._EtherCatLengthCalczP
            dummy class used to generate str representation easily
            r‰   Nrd   re   r   r(   r   r%   )r   r   r   r   r   r   r   r   r   r   Ú_EtherCatLengthCalc5  s
   


ýrŠ   rR   z>payload size {} exceeds maximum length {} of EtherCat message.r   r%   zmissing Ether layeró    )r‰   r   )r   r+   rV   r   r‰   Z
underlayerÚ
isinstancer   r   Ú	Exceptionr]   ÚETHER_FRAME_MIN_LENÚETHER_HEADER_LENÚETHERCAT_HEADER_LENÚETHER_FSC_LENr   Úloadr   r   )	r"   r#   rX   rŠ   Zpayload_lenZvlan_headers_total_sizeZupper_layerZpad_lenÚpadr   r   r   rZ   &  sL    
ÿ
ÿþýü
ÿÿÿÿÿzEtherCat.post_buildc                 C   sL   z|d }t j| W S  tyF   t d | jj¡¡ t 	| |¡ Y S 0 d S r[   r\   rb   r   r   r   ra   b  s    ÿÿzEtherCat.guess_payload_classN)r   r   r   r   r�   r‘   rŽ   r�   ZFRAME_TYPESr   r   ro   rr   rs   ru   rx   ry   r{   r|   r}   r~   r€   r‚   r„   r†   r^   rZ   ra   r   r   r   r   r]      s<   ý


ýò<r]   i¤ˆ  )r   r(   )0r   r1   Zscapy.compatr   Zscapy.errorr   r   Zscapy.fieldsr   r   r   r   r	   r
   r   r   Zscapy.layers.l2r   r   Zscapy.libs.sixZlibsrI   Zscapy.packetr   r   r   r   r   r?   rM   rj   rk   rQ   ro   rr   rs   ru   rx   ry   r{   r|   r}   r~   r€   r‚   r„   r†   r]   r   r   r   r   Ú<module>   sd   (	 6þþQ




	





m