If you have ever opened Wireshark on a network with Siemens PLCs, you have seen S7comm. It is the language Siemens controllers use to talk to TIA Portal, to WinCC, to SCADA front-ends, and to each other. The protocol has been around since 1994 and it is still the default way to move data in and out of S7-300, S7-400, S7-1200 and S7-1500 controllers.
This article is a working engineer’s guide. No theory for the sake of theory. Just what S7comm is, how the frame is built, what the function codes mean, and what to check first when something does not work.
Table of Contents
What is S7comm in one paragraph
S7comm (S7 Communication) is a proprietary Siemens protocol that rides on top of ISO-on-TCP (RFC 1006) using TCP port 102. It is not an open standard. Most of what the industry knows about it comes from open-source projects like Snap7, the Wireshark dissector, and libnodave. It is used for three jobs: programming the PLC, reading and writing data, and diagnostics. On newer S7-1200 and S7-1500 controllers, Siemens introduced an encrypted variant called S7CommPlus, which uses protocol ID 0x72 instead of 0x32.
Where S7comm sits in the stack
S7comm is not a flat protocol. It is wrapped inside two other layers before it touches TCP. Understanding this stack saves hours of debugging:
| Layer | Protocol | Job |
|---|---|---|
| 7 — Application | S7comm | Actual read/write/program commands |
| 6 — Presentation | COTP (ISO 8073) | Connection-oriented transport, TSAP addressing |
| 5 — Session | TPKT (RFC 1006) | Wraps ISO traffic in TCP packets |
| 4 — Transport | TCP | Port 102 |
| 3 — Network | IP | — |
So when you capture S7 traffic, Wireshark shows you the layers in this order: Ethernet → IP → TCP → TPKT → COTP → S7comm. If any one of those layers fails, the connection drops. Most “S7 not connecting” issues are actually COTP-level — a wrong TSAP or a closed port 102.
Port 102 and the IEC 61850 conflict
Port 102 is the standard TCP port for ISO-TSAP Class 0. Siemens uses it for every S7 product. But here is the catch: IEC 61850 MMS also runs on port 102. If you run an IEC 61850 server on a machine that also has SIMATIC software listening, one of them will refuse to start. You will see a “port already in use” error.
Quick fix on Windows: open a command prompt and run netstat -a -b to find which process owns 102. Usually it is the Siemens SIMATIC service. Stop it before launching tools like IEDScout. For more on this overlap, see our guide on IEC 61850 MMS and TCP port 102.
How a connection gets established
S7comm needs three steps before any data moves. Skip one and nothing works.
- TCP handshake on port 102. Normal SYN, SYN-ACK, ACK. Standard stuff.
- COTP Connect Request. The client sends a TSAP pair. The source TSAP is usually
0x0100(PG/programming). The destination TSAP encodes the connection type and the rack/slot of the CPU. First byte:0x01for PG,0x02for OP (HMI). Second byte: rack number in the upper nibble, slot number in the lower nibble. For an S7-1200, this is typically0x0102(rack 0, slot 2). - S7comm Setup Communication. Function code
0xF0. Both sides negotiate the max PDU size and how many parallel jobs they will allow without acknowledgment. Typical PDU sizes are 240, 480, or 960 bytes.
Only after step three can the master start sending read or write requests.
The S7comm PDU header
Once communication is set up, every S7comm message carries a header that is either 10 or 12 bytes. The 12-byte version is used for Ack_Data responses because it carries two extra error bytes. Here is what each field does:
| Field | Size | What it does |
|---|---|---|
| Protocol ID | 1 byte | Always 0x32 for S7comm. 0x72 means S7CommPlus. |
| Message Type (ROSCTR) | 1 byte | 0x01 Job, 0x02 Ack, 0x03 Ack_Data, 0x07 Userdata |
| Reserved | 2 bytes | Always 0x0000. Ignored on receive. |
| PDU Reference | 2 bytes | Master-generated counter. Used to match a response to a request. Little-endian. |
| Parameter Length | 2 bytes | Size of the parameter field. Big-endian. |
| Data Length | 2 bytes | Size of the data field. Big-endian. |
| Error Class | 1 byte | Only in Ack_Data. 0x00 means no error. |
| Error Code | 1 byte | Only in Ack_Data. Specific error reason. |
Notice the mixed endianness. PDU Reference is little-endian. Parameter and Data Length are big-endian. This trips up a lot of people writing their own parsers.
Message types (ROSCTR)
The Message Type byte — also called ROSCTR (Remote Operating Service Control) — tells you what kind of PDU you are looking at. There are only four valid values:
- 0x01 Job — A request from the master. Read data, write data, start CPU, stop CPU, upload program.
- 0x02 Ack — A bare acknowledgment with no data. Rarely seen in S7-300/400 traffic.
- 0x03 Ack_Data — Acknowledgment with a payload. This is what the PLC sends back for almost every Job request.
- 0x07 Userdata — An extension. Carries SZL reads, time sync, security functions, cyclic reads, and alarm acknowledgments. Has a different parameter structure.
Function codes you will actually see
Inside Job and Ack_Data PDUs, the parameter field starts with a function code. This byte decides what the PLC will do. Here are the ones that matter in the field:
| Code | Function | What it does |
|---|---|---|
| 0xF0 | Setup Communication | The first message after COTP connect. Negotiates PDU size and Ack queue length. |
| 0x04 | Read Variable | The bread-and-butter read. Pulls values from DB, I, Q, M, T, C areas. |
| 0x05 | Write Variable | Writes values into the same areas. Returns a per-item status byte. |
| 0x1A | Request Download | Begin sending a program block from PG to PLC. |
| 0x1B | Download Block | The actual program data chunks. |
| 0x1C | Download Ended | Tells the PLC the download is finished. |
| 0x1D / 0x1E / 0x1F | Upload (Start / Block / End) | Reading the PLC program back into Step 7 or TIA. |
| 0x28 | PI Service | Program Invocation — used to start or restart the CPU. |
| 0x29 | PLC Stop | Stops the CPU. Yes, this exists. Yes, it works over the network with no authentication on older PLCs. |
The last few codes are why S7comm gets flagged by ICS security tools like Dragos and Claroty. On an S7-300 or S7-400, any device that can reach port 102 can issue a Stop CPU command. The protocol has no built-in authentication. The PLC password, when enabled, is exchanged in clear text in the Userdata function. This is one of the main reasons Siemens introduced S7CommPlus.
How addressing works
When you do a Read Variable (0x04), you build a Request Item that points to a specific spot in PLC memory. There are three addressing modes:
- Any-type addressing — The default for S7-300/400. You specify the memory area (DB, I, Q, M, T, C), the address, and the data type. This is what libnodave and Snap7 use by default.
- DB-type addressing — A more compact form for data blocks specifically.
- Symbolic addressing — Used by S7-1200 and S7-1500 only. You address variables by their tag name instead of an offset. Rarely used in practice because it requires Symbol Server access.
The memory area is identified by a single byte:
| Code | Area | Meaning |
|---|---|---|
| 0x81 | I | Process Inputs |
| 0x82 | Q | Process Outputs |
| 0x83 | M | Flags / Merkers |
| 0x84 | DB | Data Blocks |
| 0x85 | DI | Instance DB |
| 0x86 | L | Local data (should not be exposed over network) |
| 0x1C | C | Counters |
| 0x1D | T | Timers |
S7comm vs S7CommPlus
Siemens introduced S7CommPlus around the S7-1200 V4 firmware. The big differences:
- Protocol ID is 0x72, not 0x32.
- Encryption. S7CommPlus encrypts the payload. The exact scheme is undocumented but has been reverse-engineered.
- Integrity check. Each message carries an integrity hash, which makes replay attacks much harder.
- Anti-replay. Session keys make recorded traffic unusable.
If you need to read or write data from a modern PLC and your tooling does not speak S7CommPlus, you have two options. First, in TIA Portal, enable “Permit access with PUT/GET communication from remote partner” under the CPU’s protection settings. This forces the PLC to also accept legacy S7comm. Second, switch to a documented protocol — OPC UA on S7-1500 works very well and avoids the proprietary mess entirely. See our guide on connecting any PLC to OPC UA.
Capturing S7comm in Wireshark
Wireshark has a built-in S7comm dissector. It works out of the box for the classic 0x32 protocol. A few practical filters:
tcp.port == 102— Catches everything on the S7 port, including the COTP and TPKT layers.s7comm— Shows only frames that the dissector successfully parses as S7.s7comm.header.rosctr == 1— Only Job requests.s7comm.param.func == 0x05— Only Write Variable. Useful when you suspect an unauthorized write.s7comm.param.func == 0x29— PLC Stop commands. Anything matching this on a production network is worth investigating immediately.
If you are testing without a real PLC, Snap7 ships a free server simulator. You can run it on your laptop and point TIA Portal or any S7 client at it.
Common problems and what they actually mean
Most S7comm errors are not really S7comm errors. They are COTP or firewall issues misreported by the client software.
| Symptom | Likely cause | What to check |
|---|---|---|
| Cannot connect at all | Port 102 blocked or PLC unreachable | Ping the PLC, then telnet <ip> 102. If telnet fails, it is a network problem. |
| TCP connects but COTP rejects | Wrong TSAP — wrong rack or slot | S7-300 is usually rack 0, slot 2. S7-1500 is rack 0, slot 1. Check the hardware config. |
| Read returns 0x03 (Access not allowed) | PUT/GET disabled | In TIA Portal, enable PUT/GET in the CPU properties under Protection & Security. |
| Read returns 0x05 (Address out of range) | You asked for a DB that does not exist or an offset past the end of the DB | Verify the DB number and the actual size of the block in TIA. |
| Random disconnects after minutes | Idle timeout or TCP keepalive missing | Send a dummy read every 30 seconds, or enable TCP keepalive in your client library. |
| Works for HMI but not for custom code | Wrong source TSAP (you used PG instead of OP, or vice versa) | For OP/HMI traffic, use source TSAP 0x0200 instead of 0x0100. |
Libraries for talking S7
You almost never want to write S7comm from scratch. These libraries already handle the COTP and TPKT layers and expose a clean API:
- Snap7 — Open source, C/C++ core with bindings for Python (python-snap7), C#, Java, and Node.js. Free for commercial use. Works with S7-200, S7-300, S7-400, S7-1200, S7-1500 and LOGO.
- Sharp7 — A pure C# port of Snap7. No native DLL needed. Useful for .NET projects on non-Windows targets.
- libnodave — Older C library. Still works but the project is mostly dormant. Snap7 superseded it.
- plc4x — Apache project. Wraps multiple PLC protocols including S7 behind a single interface. Good if your code needs to support Allen-Bradley and Siemens at the same time.
Should you still use S7comm in new designs?
Honest answer: only if you have to. For a brownfield site full of S7-300 and S7-400 PLCs, you have no choice. The protocol works and there are mature tools.
For new designs on S7-1500 hardware, OPC UA is the better path. It is standardized, encrypted by default, and Siemens has invested heavily in making the on-board OPC UA server perform well. You get documented behavior, certificate-based auth, and no port 102 conflicts with IEC 61850 in mixed substations.
That said, S7comm is not going away. Too many controllers in the field speak only this protocol, and the engineering software still defaults to it. Knowing how the frame is built is part of the job.
Frequently asked questions
Is S7comm the same as Profinet?
No. Profinet is a real-time Ethernet protocol used between the CPU and field devices like distributed I/O, drives, and remote stations. S7comm is what TIA Portal, WinCC and other higher-level tools use to talk to the CPU itself. A Siemens PLC will speak both at the same time.
What port does S7comm use?
TCP port 102. This is the ISO-TSAP Class 0 port and it is shared with IEC 61850 MMS.
Can S7comm work over Profibus or MPI?
Yes. S7comm is transport-agnostic. It runs over Industrial Ethernet (most common today), Profibus, and MPI. The application-layer behavior is identical. Only the lower layers change.
Is S7comm encrypted?
No. Classic S7comm (protocol ID 0x32) sends everything in clear text, including the PLC password. S7CommPlus (protocol ID 0x72) on newer PLCs adds encryption and integrity checks.
How do I stop someone from sending a PLC Stop command over the network?
Network segmentation. Put the PLC behind a firewall that only allows port 102 traffic from authorized engineering stations. On S7-1200/1500, also set a CPU password and enable “Full protection” or “Read-only access” under the CPU’s Protection settings. These controls are described in IEC 62443 Foundational Requirements.
Why does my S7-1500 reject S7comm reads from my custom application?
Because PUT/GET is disabled by default. Open the CPU properties in TIA Portal, go to Protection & Security → Connection mechanisms, and tick “Permit access with PUT/GET communication from remote partner”. Rebuild the project completely (Software → Rebuild all) and download. A partial compile is not enough.
