← Articles
SECS/GEM/10 min read/— views

Your HSMS Deselect.req Got No Reply, and the Session Is Still Up

A capture where Deselect.req, Reject.req and two unassigned STypes all draw silence, while Linktest answers instantly and the session stays SELECTED.

SECS/GEMMESSCADATroubleshootingChecklists

The host shutdown path sends Deselect.req and waits for the answer. It times out, and the log gets a deselect timeout line. The equipment is fine. Push a Linktest.req down the same socket and Linktest.rsp comes straight back.

Below is a capture taken by opening a socket against a passive HSMS listener directly. Acting as the host, I sent Select.req, got Select.rsp, and had a session. Then, on that same socket, I walked the SType byte: Deselect.req (3), Linktest.req (5), Reject.req (7), the not used value 8, and the unassigned 11. Only Linktest came back. Every other one got no reply — and the equipment logged each of them as RX, so silence here is a decision, not a parse failure.

In an HSMS session Select.req/Select.rsp and Linktest.req/Linktest.rsp are pairs, but Deselect.req and SType 11 get no reply HostEquipment Select.req Select.rsp Linktest.req Linktest.rsp Deselect.req SType 11 no reply no reply

The capture

One socket, one session. Only what the equipment side logged as RX is reproduced here.

TX Select.req             00 00 00 0A 00 0B 00 00 00 01 00 00 04 01
RX Select.rsp             00 00 00 0A 00 0B 00 00 00 02 00 00 04 01
TX Deselect.req           00 00 00 0A 00 0B 00 00 00 03 00 00 04 02
RX (nothing — waited 1.5 s)
TX Linktest.req           00 00 00 0A 00 0B 00 00 00 05 00 00 04 03
RX Linktest.rsp           00 00 00 0A 00 0B 00 00 00 06 00 00 04 03
TX Reject.req (SType 7)   00 00 00 0A 00 0B 00 00 00 07 00 00 04 04
RX (nothing — waited 1.5 s)
TX SType 8 (not used)     00 00 00 0A 00 0B 00 00 00 08 00 00 04 05
RX (nothing — waited 1.5 s)
TX SType 11 (unassigned)  00 00 00 0A 00 0B 00 00 00 0B 00 00 04 06
RX (nothing — waited 1.5 s)
TX Separate.req           00 00 00 0A 00 0B 00 00 00 09 00 00 04 07
RX (EOF — the equipment closed the socket)

You read it the way you read every other capture in this series. 00 00 00 0A says ten bytes follow, and control messages carry no body, so it is always ten. 00 0B is the SessionID and the last four bytes are the SystemBytes. The only interesting byte here is the tenth, the SType. They went out as 01, 03, 05, 07, 08, 0B, 09, and only 01 and 05 drew anything back.

SystemBytes came back unchanged on exactly the two that were answered — 00 00 04 01 for 00 00 04 01, 00 00 04 03 for 00 00 04 03. 04 02, 04 04, 04 05, 04 06 and 04 07 have no partner. Every one of the unanswered frames was logged RX on the equipment side, so nothing was dropped by the parser; the listener read them and chose not to answer.

Why only Deselect went quiet

SEMI E37's SType table is worth keeping open while you read a capture, because the gaps in it are the whole story:

STypemessagewho answers it
0data messagedepends on the W-bit
1Select.reqSelect.rsp
2Select.rsp—
3Deselect.reqDeselect.rsp
4Deselect.rsp—
5Linktest.reqLinktest.rsp
6Linktest.rsp—
7Reject.req—
8not used—
9Separate.req—
10–127reserved for subsidiary standards—
128–255reserved, not used—

3 and 4 are plainly a pair. Deselect.req is a request/response transaction, and when the response does not arrive, T6 — the control transaction timeout — is what fires. E37's timer table gives T6 a typical value of 5 s; that is a typical value, not a mandated default, and every stack I have worked with exposes it as a setting. Deselect.rsp would carry its verdict in Header Byte 3, the Deselect Status, the same slot Select.rsp uses for Select Status — zero for accepted. None of that matters here, because no Deselect.rsp arrives at all. Waiting for the answer is still the correct thing to do.

This listener just never sends it. The implementation handles SType 1, 5 and 9 and drops 3 on the floor. That is not what the standard describes, but meeting equipment that implements Deselect at all is rare in the field — everyone tears sessions down with Separate.req instead. Let me be exact about what the capture proves, though: it proves it for this one implementation. Whether some other tool returns a proper Deselect.rsp is something you find out by connecting to that tool.

The Separate.req side of this is covered separately in Why Your HSMS Separate.req Never Gets a Reply, and What Happens If You Skip It. There, silence is correct — Separate.req has no matching rsp in the first place. Deselect.req is different. The partner exists and does not show up.

Linktest is the diagnostic

Silence has two main causes. The peer is dead, or the peer does not implement that SType. From the host log they are the same single timeout line.

The capture separates them. Immediately after Deselect.req sat for 1.5 seconds with nothing, Linktest.req on the same socket was answered within a millisecond. The socket is alive and so is the peer. The only dead thing is that one message.

This is the field move: when a control message gets no answer, do not reconnect first — send one Linktest. If it comes back, the link is not your problem. If it does not, now you can suspect the link. The opposite case, where Linktest passes but Select never completes, is in A Tool That Answers Linktest But Never Completes Select.

The session stays SELECTED

Do not read silence as "the request was half processed". I ran the same sequence again and queried the equipment's state between steps.

after Select.req      reply      equipment hsmsState = SELECTED
after Deselect.req    no reply   equipment hsmsState = SELECTED

As far as the equipment is concerned, nothing happened. The session is untouched.

The host is where this turns into an incident. Some implementations send Deselect.req, eat the T6 timeout, and drop their own state to NOT SELECTED anyway — treating a timeout as "finished, one way or another" when a missing response should mean no state transition at all. Now the host thinks NOT SELECTED and the equipment thinks SELECTED. What the next Select.req does with that is up to the equipment, and from there the cause is a long way from the symptom. If you want the state down for certain, send Separate.req and close the socket.

Reject.req is the message that was supposed to explain this

Three of the frames above sit outside the answered pairs, and they behave identically. 08 is the one value E37's table marks not used. 0B falls in the 10–127 band E37 reserves for subsidiary standards, so no HSMS meaning attaches to it. And 07 is Reject.req itself, sent inbound to see what a listener does with it. All three were logged RX on the equipment side — the frames parsed, the SType was simply not acted on — and all three drew nothing.

Reject.req is the mechanism E37 provides for exactly this. A peer that receives an SType it does not support is supposed to answer with SType 7 saying so. It is a control message, so — like every other control message in this capture — it has no body; its ten-byte header is the entire message. The explanation lives in two header bytes that data messages use for something else:

header byteon Reject.reqnotes
Byte 2the SType or PType being rejectedStream on a data message
Byte 3Reason CodeFunction on a data message, Select Status on Select.rsp

E37's reason-code table:

Reason Codemeaningwhat Byte 2 holds
1SType not supportedthe offending SType
2PType not supportedthe offending PType
3Transaction not opena .rsp arrived with no matching .req
4Entity not selecteda data message arrived while NOT SELECTED

Read those numbers as taken from the standard, not measured. This listener never sends Reject.req, so nothing in my capture exercises them — the codes are a citation, and the byte placement is the part I would defend hardest, because getting Reason Code and Function confused puts a 04 where a decoder expects a Function number.

So a rejection you send by mistake, and a rejection the peer sends back at you, both come out of your log as the same thing: silence. Do not write code that assumes the peer will tell you. And keep the raw SType byte in your diagnostic logging, not only the decoded name — a line that reads Unknown control message will never tell you that you sent 0B.

What to check on the host side

  • Does the shutdown path use Deselect.req at all? If it does, find out what it does when Deselect.rsp never arrives.
  • Does a control message timeout change your state? Transitioning without a response is how the two sides drift apart.
  • Is there one Linktest inside the timeout handler? Cheapest way to tell a link fault from an unimplemented message.
  • Does the log keep the SType as a raw byte? Names alone collapse every undefined value into the same line.
  • Does the decoder read Header Byte 3 as a Function even on control messages? On Select.rsp it is Select Status, on Deselect.rsp Deselect Status, on Reject.req the Reason Code.

The captures were made against the passive listener in the SECS/GEM simulator. Open a socket, send SType 3, 7, 8 or 11, and you get the same silence from all four.