
    hO                        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ZmZmZ 	  G d d	e          Z G d
 de          Z G d de          Z G d dee          ZdddZdddZ G d de          Z G d de          Z G d de          Z G d de          Z  G d de          Z! G d d e          Z" G d! d"e          Z# G d# d$e          Z$ G d% d&e          Z% G d' d(e          Z& G d) d*e          Z' G d+ d,e          Z( G d- d.e          Z) G d/ d0e          Z* G d1 d2e          Z+ G d3 d4e          Z, eee,d56            eee,d56            ee,ed76            ee,ed76            ee,e d76            ee,e!d76            ee,e"d76            ee,e#d76            ee,e$d76            ee,e%d76            ee,e&d76            ee,e'd76            ee,e(d76            ee,e)d76            ee,e*d76            ee,e+d76           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                       e Zd ZdZdS )LEBitFieldSequenceExceptionz,
    thrown by EtherCat structure tests
    N)__name__
__module____qualname____doc__     Z/mounts/lovelace/software/anaconda3/lib/python3.11/site-packages/scapy/contrib/ethercat.pyr   r   8   s          	Dr   r   c                   $    e Zd ZdZd Zd Zd ZdS )
LEBitFieldz1
    a little endian version of the BitField
    c                 j   |j                             |           }	 |j         ||z            }t          |          t          ur:|j        j        t          ur)t          d                    | j                            dS dS # t          $ r( t          d                    | j                            w xY w)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    my_idx
next_fields        r   _check_field_typezLEBitField._check_field_typeD   s     &&t,,	G%8JJz11#,J>>1 3DDJF49DUDUW W W 21>>  	G 	G 	G- /44:F494E4EG G G	Gs   A B   2B2c                    t          |          t          u r1t          |          dk    r|\  }}}}|                     |d           nd}g }|| j        z  }|                    | j        |                     ||          f           |dz  r.|                     |d           |||t          t                    fS |                                 d}d}t                      }	|D ]w\  }
}	 |
|k     r||
z
  }|||z  z  }n]|
|k    r5|
|z  }
|||
z	  z  }t          j        d|          |	z   }	d}d}|d|
z  dz
  z  }P||z  }t          j        d|          |	z   }	d}d}	 x||	z   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         Tz!B   )r!   tuplelenr+   sizeappendi2mr   reverse	bytearraystructpack)r'   r(   svalbitsdonedata_octetremaining_lenoctetsr4   s              r   addfieldzLEBitField.addfieldX   s    77eA!#$ Axq""3++++ HDDITYc 2 23444a< #	""3***hd:&6&666LLNNNEM[[F!  	cm++(5(<!55---,!'T5!9!9F!B !() da0  !'T5!9!9F!B !()6zr   c                 n   t          |          t          u rt          |          dk    r|\  }}}nd}g }|| j        z  }|                    |            |dz  r|||fdfS d}d}d}d}||         }	|	j        }
d}t          |          }|dz  }|d|         D ]}|dz  }d}|r|
|k    r|||z  z  }||j        |	j        <   	 d}|}nc|
|k     rC||d|
z  dz
  z  |z  z  }||j        |	j        <   ||
z  }||
z  }|dz  }||         }	|	j        }
d}d}n|
|k    r|||z  z  }||z  }|
|z  }
d}|||d         |f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/   Nr0   r1   )r!   r2   r3   r4   r5   r8   fieldsr%   )r'   r(   r;   bits_in_setrF   cur_valcur_val_bit_idxthis_val	field_idxfieldfield_required_bitsidxbf_total_byte_lengthr@   octet_bits_lefts                  r   getfieldzLEBitField.getfield   s    77eA!%&"A{FFKFty d? D	6{F+T11 GOHI9%E"'*C!A#.!#3 1112 1, 1,q"#% ,,*o==  5O#;;18
5:. +,#*,>>Ea3F.F!-K$LQ`#``18
5:. "55'+>> "Q	 &y 1.3j+*+"#,>>5O#;;'?:+>+*+Y & ,,\ )**+X55r   N)r   r   r   r   r+   rC   rQ   r   r   r   r   r   ?   sT         G G G(< < <|[6 [6 [6 [6 [6r   r   c                   ,    e Zd Zg dZddd fdZd ZdS )LEBitFieldLenField)	length_ofcount_ofadjustNc                     |S Nr   )r(   xs     r   <lambda>zLEBitFieldLenField.<lambda>   s    ab r   c                 j    t                               | |||           || _        || _        || _        d S rX   )r   __init__rT   rU   rV   )r'   r%   defaultr4   rT   rU   rV   s          r   r\   zLEBitFieldLenField.__init__   s5    D$666" r   c                 .    t          j        | ||          S rX   )r   r6   )r'   r(   rY   s      r   r6   zLEBitFieldLenField.i2m   s     sA...r   )r   r   r   	__slots__r\   r6   r   r   r   rS   rS      sM        333I6:TRbRb    / / / / /r   rS   c                   "    e Zd Zej        Zd ZdS )LEBitEnumFieldc                 r    t          j        | |||           |dk     | _        t          |          | _        d S )Nr   )r   r\   revabsr4   )r'   r%   r]   r4   enums        r   r\   zLEBitEnumField.__init__  s5    D$666!8II			r   N)r   r   r   r   r_   r\   r   r   r   ra   ra     s+        #I    r   ra   zFRAME-NOT-CIRCULATINGzFRAME-CIRCULATED-ONCE)r   r0   zLAST-TYPE12-PDUzTYPE12-PDU-FOLLOWSc                   $   e Zd ZdZd Zd Z edd           edd           edd           e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            edd          g
ZeZ edd           edd           e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            edd          g	Zd	S )EtherCatType12DLPDUz#
    Type12 message base class
    c                 P   t          | j                  }|dk    r#t          d                    |d                    | j        | j        rdnd}n|rd}nd}|rt          |d         dz  g          }nt          |d         dz  g          }|dd         |z   |d	d         z   |z   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/   )r3   r>   
ValueErrorr$   nextr8   )r'   r(   paydata_lenhas_next	next_flags         r   
post_buildzEtherCatType12DLPDU.post_build  s     ty>>d?? --3VHd-C-CE E E 9 #y3tteHH !  	9!3q6J#6"788II!3q6J#6"788I2A2w"SW,s22r   c                     	 |d         }t           j        |         S # t          $ rI t          j        d                    | j        j                             t          j	        | |          cY S w xY wNr   z8{}.guess_payload_class() - unknown or invalid DLPDU type
EtherCatETHERCAT_TYPE12_DLPDU_TYPESKeyErrorr   errorr$   r"   r   r   guess_payload_classr'   payload
dlpdu_types      r   r{   z'EtherCatType12DLPDU.guess_payload_class;  s    	= J7
CC 	= 	= 	=#VDN$;<<> > > -dG<<<<<		=    AA/.A/rN   r   adpador3   N   r>   )rU   	_reservedrE   cr0   rn   irq c                     | j         S rX   r3   r(   s    r   rZ   zEtherCatType12DLPDU.<lambda>R      cg r   )
count_fromwkcadrc                     | j         S rX   r   r   s    r   rZ   zEtherCatType12DLPDU.<lambda>a  r   r   )r   r   r   r   rs   r{   r   r   rS   r   ra   "ETHERCAT_TYPE_12_CIRCULATING_FRAMEETHERCAT_TYPE_12_NEXT_FRAMEr	   PHYSICAL_ADDRESSING_DESCBROADCAST_ADDRESSING_DESCr
   LOGICAL_ADDRESSING_DESCr   r   r   rg   rg     s        3 3 3<
= 
= 
= 		%UAUA5$V<<<
;1%%sAq"DEEvtQ(CDDUAvr99R#6#6"5"5	7 	7 	7UA  !9 		%
5!5$V<<<
;1%%sAq"DEEvtQ(CDDUAvr99R#6#6"5"5	7 	7 	7UAr   rg   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatAPRDz`
    APRD - Auto Increment Physical Read
    (IEC 61158-5-12, sec. 5.4.1.2 tab. 14 / p. 32)
    _cmdr0   Nr   r   r   r   r   rg   r   r   r   r   r   r   r   j  9         
 9VT**+45KKKr   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatFPRDzd
    FPRD - Configured address physical read
    (IEC 61158-5-12, sec. 5.4.1.3 tab. 15 / p. 33)
    r   r-   Nr   r   r   r   r   r   t  r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatBRDzQ
    BRD - Broadcast read
    (IEC 61158-5-12, sec. 5.4.1.4 tab. 16 / p. 34)
    r   rj   Nr   r   r   r   r   rg   r   r   r   r   r   r   r   ~  9         
 9VT**+56KKKr   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatLRDzO
    LRD - Logical read
    (IEC 61158-5-12, sec. 5.4.1.5 tab. 17 / p. 36)
    r   
   Nr   r   r   r   r   rg   r   r   r   r   r   r   r     9         
 9VT**+34KKKr   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatAPWRza
    APWR - Auto Increment Physical Write
    (IEC 61158-5-12, sec. 5.4.2.2 tab. 18 / p. 37)
    r   r1   Nr   r   r   r   r   r     r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatFPWRze
    FPWR - Configured address physical write
    (IEC 61158-5-12, sec. 5.4.2.3 tab. 19 / p. 38)
    r      Nr   r   r   r   r   r     r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatBWRzM
    BWR - Broadcast read (IEC 61158-5-12, sec. 5.4.2.4 tab. 20 / p. 39)
    r   r/   Nr   r   r   r   r   r     s9          9VT**+56KKKr   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatLWRzP
    LWR - Logical write
    (IEC 61158-5-12, sec. 5.4.2.5 tab. 21 / p. 40)
    r   r   Nr   r   r   r   r   r     r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatAPRWzf
    APRW - Auto Increment Physical Read Write
    (IEC 61158-5-12, sec. 5.4.3.1 tab. 22 / p. 41)
    r   rE   Nr   r   r   r   r   r     r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatFPRWzj
    FPRW - Configured address physical read write
    (IEC 61158-5-12, sec. 5.4.3.2 tab. 23 / p. 43)
    r      Nr   r   r   r   r   r     r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatBRWzW
    BRW - Broadcast read write
    (IEC 61158-5-12, sec. 5.4.3.3 tab. 24 / p. 39)
    r   	   Nr   r   r   r   r   r     r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatLRWzU
    LRW - Logical read write
    (IEC 61158-5-12, sec. 5.4.3.4 tab. 25 / p. 45)
    r      Nr   r   r   r   r   r     r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatARMWzo
    ARMW - Auto increment physical read multiple write
    (IEC 61158-5-12, sec. 5.4.3.5 tab. 26 / p. 46)
    r      Nr   r   r   r   r   r     r   r   r   c                   <    e Zd ZdZ edd          gej        z   ZdS )EtherCatFRMWzs
    FRMW - Configured address physical read multiple write
    (IEC 61158-5-12, sec. 5.4.3.6 tab. 27 / p. 47)
    r      Nr   r   r   r   r   r     r   r   r   c                       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 Zd ZdS )rw   z&
    Common EtherCat header layer
    r   r-   @   r1   zTYPE-12-PDUzNETWORK-VARIABLESMAILBOX)r0   r-   r   lengthr   r   r   r0   r!   )r0   r-   rj   r   r1   r   r/   r   rE   r   r   r   r   r   c                     G d dt                     }t          |          }|dk    r#t          d                    |d                    || _        d}| j        }|r8t          |t                    r#|dz  }|j        }|rt          |t                    #t          |t                    st          d          t          j        t          j        |z   t          j        z   |z   t          j        z   z
  }|dk    rOt                      }d|z  |_        t#           || j        | j        	                    |z   t#          |          z   S t#           || j        | j        	                    |z   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                   ^    e Zd ZdZ eddd           eddd           eddd	          gZdS )
0EtherCat.post_build.<locals>._EtherCatLengthCalczP
            dummy class used to generate str representation easily
            r   Nr   r   r   r0   r!   r-   )r   r   r   r   r   r   r   r   r   _EtherCatLengthCalcr   4  sT          
8T2..
;1--
61a((KKKr   r   ri   z>payload size {} exceeds maximum length {} of EtherCat message.r   r-   zmissing Ether layer    )r   r!   )r   r3   rm   r$   r   
underlayer
isinstancer   r   	Exceptionrw   ETHER_FRAME_MIN_LENETHER_HEADER_LENETHERCAT_HEADER_LENETHER_FSC_LENr   loadr   r!   )	r'   r(   ro   r   payload_lenvlan_headers_total_sizeupper_layerpad_lenpads	            r   rs   zEtherCat.post_build%  s   	 	 	 	 	& 	 	 	 #hh  44:F;4M4MO O O ""#o  	1je<< 	1#q(#%0K  	1je<< 	1 +u-- 	31222.(2K2I3J2:2N3O 3>3> 3;2H	3I J Q;;))C(CH**$+04	; ; ; < <>ABDGHHM M&&dk,0I7 7 7 8 8:=> 	>r   c                     	 |d         }t           j        |         S # t          $ rI t          j        d                    | j        j                             t          j	        | |          cY S w xY wru   rv   r|   s      r   r{   zEtherCat.guess_payload_classa  s    	= J7
CC 	= 	= 	=#VDN$;<<> > > -dG<<<<<		=r   N)r   r   r   r   r   r   r   r   FRAME_TYPESr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rx   rs   r{   r   r   r   rw   rw     s          M ! K 	
8Q##
;1%%
61a  K # #":> :> :>x= = = = =r   rw   i  )r!   r0   )-r   r9   scapy.compatr   scapy.errorr   r   scapy.fieldsr   r   r   r	   r
   r   r   r   scapy.layers.l2r   r   scapy.packetr   r   r   r   r   rS   ra   r   r   rg   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rw   r   r   r   <module>r      s   >        4 4 4 4 4 4 4 45 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 ( ( ( ( ( ( ( ( 5 5 5 5 5 5 5 5 5 5	 	 	 	 	/ 	 	 	r6 r6 r6 r6 r6 r6 r6 r6j
/ 
/ 
/ 
/ 
/ 
/ 
/ 
/    Z    "
!& & " 
  J J J J J& J J Jb5 5 5 5 5& 5 5 55 5 5 5 5& 5 5 56 6 6 6 6% 6 6 64 4 4 4 4% 4 4 45 5 5 5 5& 5 5 55 5 5 5 5& 5 5 56 6 6 6 6% 6 6 64 4 4 4 4% 4 4 45 5 5 5 5& 5 5 55 5 5 5 5& 5 5 56 6 6 6 6% 6 6 64 4 4 4 4% 4 4 45 5 5 5 5& 5 5 55 5 5 5 5& 5 5 5j= j= j= j= j=v j= j= j=Z E8& ) ) ) ) E8& ) ) ) ) Hl . . . . Hl . . . . Hk - - - - Hk - - - - Hl . . . . Hl . . . . Hk - - - - Hk - - - - Hl . . . . Hl . . . . Hk - - - - Hk - - - - Hl . . . . Hl . . . . . .r   