What Is the DNP3 Transport Function?
Between the DNP3 link layer, which moves individual frames, and the application layer, which builds meaningful messages, sits a thin but essential piece: the transport function. It exists because a DNP3 link frame is limited in size, while an application message can be much larger. This page explains what the transport function does, the single control byte it adds to each segment, and why it matters when you are decoding a multi-frame exchange.
DNP3 Transport Function in one line: The DNP3 transport function is the middle layer that splits a large application fragment into multiple link frames and reassembles them at the receiver. Each segment carries one transport header byte with a first (FIR) bit, a final (FIN) bit, and a rolling sequence number. The receiver uses those bits to know where a fragment begins and ends and to detect a missing or out-of-order segment, discarding the whole fragment if the sequence breaks.
Why DNP3 Needs a Transport Layer
A single DNP3 link frame can hold only a limited amount of user data. An application-layer fragment - a full class poll response, for example, carrying many analog and binary points - often will not fit in one frame. The transport function bridges that gap by chopping the fragment into segments small enough to become link frames, and by reassembling them on the far side.
This is why DNP3 is sometimes described as having a pseudo-transport function rather than a true transport layer. It does not do end-to-end connection management the way TCP does; it only handles segmentation and reassembly of one application fragment across the frames that carry it. When a fragment spans many frames, the transport bytes are what keep them in order.
The Transport Header Byte
Each transport segment begins with a single header byte. The top two bits are FIR (first) and FIN (final): FIR is set on the first segment of a fragment and FIN on the last. A short fragment that fits in one segment has both bits set. The remaining six bits are a sequence number that increments with each segment and rolls over, so the receiver can confirm segments arrive contiguously.
If the receiver sees a sequence gap - a segment missing between FIR and FIN - it cannot trust the reassembled fragment and discards the entire thing. This matters when reading a capture: a broken transport sequence explains why a technically-present message never appears at the application layer, and it is distinct from a link-layer CRC failure. The application-layer message that finally emerges is the DNP3 fragment that confirmation and event handling operate on.
A Segmented Fragment, Step by Step
Work it through symbolically. Suppose an outstation has an application fragment too large for one link frame, and the transport function splits it into k segments. Segment one goes out with FIR set, FIN clear, and sequence s. Each middle segment carries FIR clear, FIN clear, and the next sequence value - s plus one, s plus two, and so on, wrapping around after 63 because the sequence field is six bits. The final segment carries FIN set and sequence s plus k minus one. Nothing else marks the boundaries: those two bits and the counter are the entire protocol.
The receiver's side is just as simple. It opens a reassembly buffer when it sees FIR, appends each segment whose sequence is exactly one more than the last, and hands the completed fragment up to the application layer when FIN arrives. A segment repeating the previous sequence number is treated as a duplicate and dropped. A gap - any sequence that is not the expected next value - poisons the buffer: the receiver discards the partial fragment and ignores everything until the next FIR starts a fresh one. That discard-and-restart behavior is what makes the transport function cheap, and also what makes it unforgiving.
The Transport Byte at a Glance
Every segment spends exactly one byte on transport bookkeeping, laid out like this:
| Field | Width | Purpose |
|---|---|---|
| FIN | 1 bit | Set on the final segment of a fragment |
| FIR | 1 bit | Set on the first segment of a fragment |
| Sequence | 6 bits | Increments per segment, 0 through 63 with rollover, proving contiguity |
What the Transport Function Leaves to Other Layers
It is worth being explicit about what this layer does not do. There is no acknowledgement of segments, no retransmission, and no flow control. If a segment dies, the transport function's only contribution is to make sure the receiver notices and throws the fragment away cleanly; actual recovery happens above, when the master re-polls, or below, if link-layer confirms are enabled and a frame gets resent. Whether those link confirms are worth their overhead depends on the channel, which is part of the DNP3 over serial vs TCP decision.
Over TCP the transport function still runs, unchanged, inside the stream - the layering does not know or care that the bytes now travel through a reliable pipe. TCP's ordering guarantees make transport sequence gaps rare in steady state, but they still appear around connection resets, when one side restarts mid-fragment and the survivor sees a discontinuity it resolves by discarding. Over serial with link confirms turned off, the transport sequence check is effectively the only integrity mechanism above the frame CRCs, which is why a marginal radio path so often shows up first as fragments that never finish reassembling.
Frequently Asked Questions
What do FIR and FIN mean in DNP3?
FIR (first) marks the first transport segment of an application fragment; FIN (final) marks the last. A single-segment fragment sets both. Between them the receiver expects contiguous sequence numbers with no gaps.
Is the DNP3 transport function the same as TCP?
No. It only segments and reassembles one application fragment across link frames. It does not do connection setup, flow control, or end-to-end retransmission the way TCP does; DNP3 over TCP runs the transport function inside the TCP stream.
What happens if a transport segment is lost?
The sequence number breaks, the receiver cannot reassemble a complete fragment, and it discards the whole fragment. The application layer never sees a partial message, so the master must poll again to recover the data.
Does the receiver acknowledge transport segments?
No. The transport header has no acknowledgement mechanism at all. Delivery assurance comes from other layers: optional link-layer confirms below it, and application confirmation plus re-polling above it. The transport function only detects that reassembly failed and discards cleanly.
Why does my capture show all the frames but no application message?
Almost always a broken transport sequence. If a segment went missing or arrived out of order, the receiver silently discarded the partial fragment, so the application layer never saw a message even though the frames look present. Step through the transport bytes checking that each sequence increments by one from FIR to FIN - the first gap you find is your culprit. A methodical way to do this is to capture and decode the traffic and walk the exchange segment by segment.
Sources and verification
This page references the protocol specifications published by the organizations below. Editions, product capabilities, and documentation change over time - confirm current requirements and specifications directly with the source.
- Overview of DNP3 (IEEE Std 1815) - DNP Users Group
Merobix is not affiliated with, endorsed by, or sponsored by these organizations; their names are used only to identify the standards and products discussed.
Automation services
Need help turning this into a working system?
Merobix integrates SCADA, programs Allen-Bradley and Siemens PLCs, and designs and fabricates industrial control panels.
Meeting requests are reviewed before confirmation.