From 3832708eb34ac593546bad2512924c77337481e8 Mon Sep 17 00:00:00 2001 From: Brunno Vanelli Date: Wed, 26 Aug 2026 21:41:28 +0200 Subject: [PATCH] fix: Align all 0x34 and 0x36 framing bytes --- s7commplus/async_client.py | 7 ++++--- s7commplus/connection.py | 9 ++++----- s7commplus/protocol.py | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/s7commplus/async_client.py b/s7commplus/async_client.py index 93f4b4aa..fb218f6f 100644 --- a/s7commplus/async_client.py +++ b/s7commplus/async_client.py @@ -45,6 +45,7 @@ _set_s7_groups, ) from .protocol import ( + FLAGS_34_FUNCTION_CODES, READ_FUNCTION_CODES, S7COMMPLUS_LOCAL_TSAP, S7COMMPLUS_REMOTE_TSAP, @@ -737,8 +738,8 @@ async def _send_request( 0x0000, seq_num, self._session_id, - # Transport flags: 0x34 for GetMultiVariables and Explore, 0x36 otherwise. - 0x34 if function_code in (FunctionCode.GET_MULTI_VARIABLES, FunctionCode.EXPLORE) else 0x36, + # Transport flags: 0x34 for the function codes the reference sends with 0x34. + 0x34 if function_code in FLAGS_34_FUNCTION_CODES else 0x36, ) integrity_id_bytes = b"" @@ -992,7 +993,7 @@ async def _delete_session(self) -> None: 0x0000, seq_num, self._session_id, - 0x36, + 0x34, ) request += struct.pack(">I", 0) diff --git a/s7commplus/connection.py b/s7commplus/connection.py index 756fd5e3..861e091c 100644 --- a/s7commplus/connection.py +++ b/s7commplus/connection.py @@ -52,6 +52,7 @@ from .codec import decode_header, encode_header, encode_object_qualifier, parse_create_object_attributes from .protocol import ( + FLAGS_34_FUNCTION_CODES, READ_FUNCTION_CODES, S7COMMPLUS_LOCAL_TSAP, S7COMMPLUS_REMOTE_TSAP, @@ -716,10 +717,8 @@ def send_request(self, function_code: int, payload: bytes = b"", integrity_tail: seq_num, self._session_id, # Transport flags: 0x34 after SessionKey auth (matches TIA Portal), - # also for GetMultiVariables and Explore; 0x36 for other V1/TLS requests. - 0x34 - if self._session_key is not None or function_code in (FunctionCode.GET_MULTI_VARIABLES, FunctionCode.EXPLORE) - else 0x36, + # and for the function codes the reference sends with 0x34. + 0x34 if self._session_key is not None or function_code in FLAGS_34_FUNCTION_CODES else 0x36, ) integrity_id_bytes = b"" @@ -1470,7 +1469,7 @@ def _delete_session(self) -> None: 0x0000, seq_num, self._session_id, - 0x36, + 0x34, ) request += struct.pack(">I", 0) diff --git a/s7commplus/protocol.py b/s7commplus/protocol.py index 4d869630..bc05d20d 100644 --- a/s7commplus/protocol.py +++ b/s7commplus/protocol.py @@ -226,6 +226,26 @@ class Ids(IntEnum): } ) +# Function codes whose requests carry transport flags 0x34. The reference sets +# this per request class rather than by read/write, so it is a different split +# than READ_FUNCTION_CODES: the writes SetVariable, SetMultiVariables and +# DeleteObject use 0x34 too. Only CreateObject (0x36) and InitSSL (0x30) differ, +# and a session-setup CreateObject sent with 0x34 makes the PLC reset the +# connection. Subscription and alarm CreateObjects are the documented exception: +# the reference overrides those to 0x34. +# +# Reference: TransportFlags in thomas-v2/S7CommPlusDriver/Core/*Request.cs +FLAGS_34_FUNCTION_CODES: frozenset[int] = frozenset( + { + FunctionCode.DELETE_OBJECT, + FunctionCode.EXPLORE, + FunctionCode.GET_MULTI_VARIABLES, + FunctionCode.GET_VAR_SUBSTREAMED, + FunctionCode.SET_MULTI_VARIABLES, + FunctionCode.SET_VARIABLE, + } +) + class AccessLevel(IntEnum): """Protection levels reported by `Ids.EFFECTIVE_PROTECTION_LEVEL`.