shadow1ng/fscan · error
Invalid expected MCS opcode receive data
Error message
Invalid expected MCS opcode receive data
What it means
In recvData, after ruling out DISCONNECT_PROVIDER_ULTIMATUM, the header must match c.recvOpCode (normally SEND_DATA_INDICATION). If readMCSPDUHeader(option, c.recvOpCode) fails, the client received an MCS PDU it did not expect in the data phase and emits this error. It indicates a protocol sequence violation or unhandled PDU type mid-session.
Source
Thrown at libs/grdp/protocol/t125/mcs.go:454
c.transport.Write(buff.Bytes())
}
func (c *MCSClient) recvData(s []byte) {
glog.Debug("msc on data recvData:", hex.EncodeToString(s))
r := bytes.NewReader(s)
option, err := core.ReadUInt8(r)
if err != nil {
c.Emit("error", err)
return
}
if readMCSPDUHeader(option, DISCONNECT_PROVIDER_ULTIMATUM) {
c.Emit("error", errors.New("MCS DISCONNECT_PROVIDER_ULTIMATUM"))
c.transport.Close()
return
} else if !readMCSPDUHeader(option, c.recvOpCode) {
c.Emit("error", errors.New("Invalid expected MCS opcode receive data"))
return
}
userId, _ := per.ReadInteger16(r)
userId += MCS_USERCHANNEL_BASE
channelId, _ := per.ReadInteger16(r)
per.ReadEnumerates(r)
size, _ := per.ReadLength(r)
// channel ID doesn't match a requested layer
found := false
channelName := ""
for _, channel := range c.channels {
if channel.ID == channelId {
found = true
channelName = channel.Name
break
}View on GitHub (pinned to 95cc12e753)
Solutions
- Log the unexpected opcode (option>>2) to identify which PDU type arrived and add a handler or skip logic for it.
- Ensure all request/response pairs (channel join etc.) complete before registering recvData as the permanent 'data' handler.
- Consider buffering/skipping unknown PDUs instead of erroring out, matching FreeRDP's tolerant behavior.
- If desynchronization is suspected, dump the hex stream and verify PDU boundaries against T.125 framing.
Example fix
// before
} else if !readMCSPDUHeader(option, c.recvOpCode) {
c.Emit("error", errors.New("Invalid expected MCS opcode receive data"))
return
}
// after
} else if !readMCSPDUHeader(option, c.recvOpCode) {
glog.Warn("unexpected MCS opcode", option>>2, "- skipping")
return
} Defensive patterns
Strategy: fallback
Validate before calling
// Pre-dispatch check of the opcode in the data stream:
op := (buf[0] >> 2)
if op != 26 { // SEND_DATA_INDICATION
glog.Warn("unexpected MCS opcode during data phase:", op)
} Try / catch
mcs.On("error", func(err error) {
if strings.Contains(err.Error(), "Invalid expected MCS opcode") {
// log opcode, skip or resynchronize instead of hard-failing
}
}) Prevention
- Finish all Once('data') request/response exchanges before installing recvData as permanent handler.
- Log and skip unknown PDU opcodes rather than aborting the session.
- Validate PDU framing against T.125 when adding new message types.
When it happens
Trigger: A 'data' event in the established-session phase carries an MCS PDU whose opcode (option>>2) is neither DISCONNECT_PROVIDER_ULTIMATUM nor SEND_DATA_INDICATION — e.g. a CHANNEL_JOIN_CONFIRM arriving late, or a server-to-client PDU type this fork doesn't handle.
Common situations: Responses to earlier requests arriving after the client switched to recvData (handler registration race between Once('data', ...) and On('data', recvData)); servers sending proprietary/extension PDUs; framing desynchronization after a partial read.
Related errors
- NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER
- bad BER tags
- invalid expected BER tag
- unsupported Capability type 0x%04x
- Unknown data pdu type2 0x%02x
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/9acacec148f12b0a.
Report an issue: GitHub.