X.25 Call User Data (CUD) for TAD Protocol Identification¶
Overview¶
This document specifies how TAD (Terminal Access Device) connections are identified in X.25 networks using the Call User Data (CUD) field of X.25 Call Request packets.
Purpose: Enable proper protocol identification and routing for TAD terminal connections over X.25 packet-switched networks.
Related Documents:
- TAD-Protocol-Analysis.md - TAD protocol specification
- TAD-HDLC-Encapsulation.md - Complete protocol stack
- PAD_Connection_Analysis.md - PAD connection sequences
X.25 Call Request Packet Structure¶
Complete X.25 Call Request Format¶
┌──────────────────────────────────────────────────────────────┐
│ HDLC Frame │
├───────┬────────┬────────┬─────────────────────────────────────┤
│ Flag │ Addr │ Ctrl │ Data Field │
│ 7E │ 03 │ 00 │ (X.25 Call Request) │
└───────┴────────┴────────┴─────────────────────────────────────┘
X.25 Call Request Packet (in HDLC Data Field):
┌──────┬──────┬────────┬──────────┬───────────┬──────────┬──────────┬───────┐
│ GFI │ LCN │ Packet │ Called │ Calling │ Facility │ CUD │ ... │
│ (1) │ (1) │ Type │ Address │ Address │ Length │ (0-128) │ │
│ │ │ (1) │ (var) │ (var) │ (1) │ │ │
└──────┴──────┴────────┴──────────┴───────────┴──────────┴──────────┴───────┘
Field Details:
| Field | Size | Purpose | TAD Value |
|---|---|---|---|
| GFI | 1 byte | General Format Identifier | 0x11 (Q=0, D=0, Modulo=8) |
| LCN | 1 byte | Logical Channel Number | Varies (0x01-0x0F) |
| Packet Type | 1 byte | Call Request = 0x0B |
0x0B |
| Called Addr Len | 4 bits | BCD digit count | Varies |
| Calling Addr Len | 4 bits | BCD digit count | Varies |
| Called Address | Variable | Destination address (BCD) | Target node address |
| Calling Address | Variable | Source address (BCD) | Local node address |
| Facility Length | 1 byte | Optional facilities length | Usually 0x00 |
| Facilities | Variable | Optional facilities | (none for basic TAD) |
| CUD Length | Implicit | Calculated from packet | Variable (4-128 bytes) |
| CUD | 0-128 bytes | Protocol Identification | TAD Protocol ID |
TAD Protocol Identification in CUD¶
Standard TAD CUD Format¶
Based on SINTRAN PAD implementation and X.25 standards:
┌──────────┬──────────┬──────────┬──────────┬─────────────┐
│ Protocol │ Service │ Terminal │ Options │ User Data │
│ ID │ Type │ Type │ Flags │ (optional) │
│ (4) │ (1) │ (2) │ (1) │ (0-120) │
└──────────┴──────────┴──────────┴──────────┴─────────────┘
Minimum CUD Size: 8 bytes Maximum CUD Size: 128 bytes (X.25 limit)
CUD Field Definitions¶
Protocol ID (4 bytes)¶
Purpose: Identify protocol family
TAD Protocol ID: 0x01 0x02 0x00 0x00 or ASCII "TAD\0"
Alternatives:
- 0x01 0x02 0x00 0x00 - SINTRAN TAD protocol (binary format)
- "TAD\0" (0x54 0x41 0x44 0x00) - ASCII TAD identifier
- "XMSG" (0x58 0x4D 0x53 0x47) - XMSG message protocol
- "NORD" (0x4E 0x4F 0x52 0x44) - NORD-NET protocol
Recommended: Use 0x01 0x02 0x00 0x00 for SINTRAN compatibility
Service Type (1 byte)¶
Purpose: Identify service type within TAD protocol
| Value | Hex | Service Type | Description |
|---|---|---|---|
| 0 | 0x00 | Interactive Terminal | Standard terminal session |
| 1 | 0x01 | Batch Terminal | Batch job submission |
| 2 | 0x02 | File Transfer | TAD file transfer mode |
| 3 | 0x03 | Mail Service | TAD mail delivery |
| 4 | 0x04 | Remote Procedure | TAD RPC service |
| 255 | 0xFF | Unspecified | Generic TAD service |
Default: 0x00 (Interactive Terminal)
Terminal Type (2 bytes)¶
Purpose: Specify terminal characteristics
Format: 16-bit terminal type code (same as 7TTYP message)
Common Values:
- 0x0001 - Basic ASCII terminal
- 0x0002 - VT52 compatible
- 0x0003 - VT100 compatible
- 0x0010 - NORD-1 terminal
- 0x0020 - NORD-10 terminal
- 0x0100 - Generic terminal
- 0xFFFF - Negotiate terminal type
Default: 0x0100 (Generic terminal)
Options Flags (1 byte)¶
Purpose: Optional features and modes
Bit Layout:
Bit 7: 8-bit mode (1=8-bit, 0=7-bit)
Bit 6: Echo mode (1=remote echo, 0=local echo)
Bit 5: Binary mode (1=binary, 0=ASCII)
Bit 4: Break enabled (1=yes, 0=no)
Bit 3: Flow control (1=XON/XOFF, 0=none)
Bit 2: Protocol version (1=v3+, 0=v1-2)
Bit 1: Reserved (0)
Bit 0: Reserved (0)
Common Configurations:
- 0x00 - Basic 7-bit ASCII, local echo
- 0x40 - 7-bit with remote echo
- 0x80 - 8-bit mode, local echo
- 0xC0 - 8-bit mode, remote echo
- 0xD8 - 8-bit, remote echo, binary, break, flow control
Default: 0x40 (7-bit with remote echo)
User Data (0-120 bytes)¶
Optional field containing: - Username (null-terminated string) - Password (null-terminated string) - Connection parameters - Application-specific data
Example:
User: "john\0"
Pass: "secret\0"
Complete TAD CUD Examples¶
Example 1: Basic Interactive Terminal¶
CUD (8 bytes):
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ 01 │ 02 │ 00 │ 00 │ 00 │ 01 │ 00 │ 40 │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
Protocol ID │ Svc │ TermType │ Opt │
(TAD) │ 0 │ 0x0100 │0x40 │
Interactive Generic Remote
Terminal Terminal Echo
Interpretation: - Protocol: TAD (0x01020000) - Service: Interactive terminal (0x00) - Terminal Type: Generic (0x0100) - Options: 7-bit, remote echo (0x40)
Example 2: VT100 Terminal with 8-bit Mode¶
CUD (8 bytes):
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ 01 │ 02 │ 00 │ 00 │ 00 │ 00 │ 03 │ C0 │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
Protocol ID │ Svc │ TermType │ Opt │
(TAD) │ 0 │ 0x0003 │0xC0 │
Interactive VT100 8-bit +
Terminal Terminal Echo
Interpretation: - Protocol: TAD (0x01020000) - Service: Interactive terminal (0x00) - Terminal Type: VT100 (0x0003) - Options: 8-bit mode, remote echo (0xC0)
Example 3: TAD with Username¶
CUD (18 bytes):
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬──────────────────┐
│ 01 │ 02 │ 00 │ 00 │ 00 │ 01 │ 00 │ 40 │ User Data (10) │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴──────────────────┘
Protocol ID │ Svc │ TermType │ Opt │ "john\0\0\0\0\0"
(TAD) │ 0 │ 0x0100 │0x40 │ Username field
User Data Field:
6A 6F 68 6E 00 00 00 00 00 00
"j o h n \0 \0 \0 \0 \0"
Example 4: NORD-NET PAD Connection¶
From actual trace (PAD_Connection_Analysis.md):
Frame payload: 04 00 DA 10
Likely CUD structure:
┌─────┬─────┬─────┬─────┐
│ 04 │ 00 │ DA │ 10 │
└─────┴─────┴─────┴─────┘
Seq │ Opt │ Parameters │
4 │ 0 │ 0xDA10 │
Note: This appears to be a shortened/proprietary format used in NORD-NET routing protocol.
X.25 Call Request Packet Examples¶
Full Call Request Packet with TAD CUD¶
Example: Node 100 → Node 102¶
X.25 Call Request Packet:
┌──────┬──────┬──────┬──────────────┬──────────────┬──────┬─────────────────┐
│ GFI │ LCN │ Type │ Addr Lengths │ Addresses │ Fac │ CUD │
│ 0x11 │ 0x01 │ 0x0B │ 0x24 │ (BCD) │ 0x00 │ (8 bytes) │
└──────┴──────┴──────┴──────────────┴──────────────┴──────┴─────────────────┘
Complete bytes:
11 01 0B 24 01 00 01 02 00 01 02 00 00 00 01 00 40
Breakdown:
11 - GFI (Q=0, D=0, Modulo 8, LCN high=0001)
01 - LCN low (full LCN = 0x101)
0B - Packet type (Call Request)
24 - Address lengths (Called=2 digits, Calling=4 digits)
01 00 - Called address "100" (BCD: node 100, 0x64 decimal)
01 02 - Calling address "102" (BCD: node 102, 0x66 decimal)
00 - Facility length (no facilities)
01 02 00 00 - Protocol ID (TAD)
00 - Service type (Interactive)
01 00 - Terminal type (0x0100 = Generic)
40 - Options (Remote echo, 7-bit)
Total Size: 17 bytes (X.25 packet)
Complete HDLC Frame with Call Request¶
HDLC Frame:
┌──────┬──────┬──────┬────────────────────────────────────┬───────┬──────┐
│ Flag │ Addr │ Ctrl │ X.25 Call Request (17) │ FCS │ Flag │
│ 7E │ 03 │ 00 │ (from above) │ (CRC) │ 7E │
└──────┴──────┴──────┴────────────────────────────────────┴───────┴──────┘
Complete frame:
7E 03 00 11 01 0B 24 01 00 01 02 00 01 02 00 00 00 01 00 40 [FCS] 7E
Total Size: 23 bytes (HDLC frame without FCS calculation)
CUD Processing in SINTRAN¶
Sending TAD Connection Request¶
Source: MP-P2-TAD.NPL:384 (INIBDR)
INIBDR: CALL STADIWINDOW
IF PORTNO=0 THEN
0=:TDRADDR.BXTADD; T:=XFOPN; CALL MXMSG; GO IERR % OPEN PORT
A=:PORTNO
% ... allocate buffers ...
FI
XFOPN Function: Opens X.25 virtual circuit - Likely includes CUD in XMSG internal structures - CUD derived from PORTNO, PARTNER, OSVTPN fields
Hypothetical CUD Construction:
% Construct CUD for TAD connection
CUD_PROTOCOL: "0102"; 0; 0 % TAD protocol ID
CUD_SERVICE: 0 % Interactive terminal
CUD_TERMTYPE: CTTYP % From datafield
CUD_OPTIONS: DFLAG/\177 % From datafield flags
Receiving TAD Connection Request¶
Processing on remote side:
% X.25 Call Indication received
% Extract CUD from Call packet
% Check Protocol ID
IF CUD_PROTOCOL = "0102" OR = "TAD" THEN
% TAD connection request
% Create TAD input/output datafields
% Accept call with X.25 Call Accepted
% Send 7TMOD, 7TTYP, 7DESC configuration messages
FI
Protocol Identification Matrix¶
CUD Protocol IDs in SINTRAN¶
| Protocol ID | Bytes | Service | Description |
|---|---|---|---|
| TAD | 01 02 00 00 | Terminal Access Device | Interactive terminal over X.25 |
| XMSG | 01 01 00 00 | XMSG Protocol | Direct XMSG message passing |
| PAD | 01 03 00 00 | Packet Assembly/Disassembly | X.3/X.28/X.29 PAD service |
| RJE | 01 04 00 00 | Remote Job Entry | Batch job submission |
| FTP | 01 05 00 00 | File Transfer Protocol | SINTRAN file transfer |
| 01 06 00 00 | Mail Transfer Protocol | Electronic mail | |
| ROUTING | 21 13 00 00 | Network Routing | Topology exchange (not TAD) |
Service Type Matrix¶
| Service | Value | TAD Support | Description |
|---|---|---|---|
| Interactive | 0x00 | Yes | Standard terminal session |
| Batch | 0x01 | Yes | Batch terminal mode |
| File Transfer | 0x02 | Optional | TAD file transfer |
| 0x03 | Optional | TAD mail service | |
| RPC | 0x04 | No | Remote procedure calls |
Emulator Implementation¶
Sending TAD Call Request¶
public class TadCallRequest
{
public byte[] CreateCallRequestPacket(
byte lcn,
string calledAddress,
string callingAddress,
ushort terminalType = 0x0100,
byte options = 0x40)
{
List<byte> packet = new List<byte>();
// GFI
packet.Add(0x11);
// LCN
packet.Add(lcn);
// Packet Type (Call Request)
packet.Add(0x0B);
// Address Lengths (BCD digit counts)
byte addrLen = (byte)((calledAddress.Length << 4) | callingAddress.Length);
packet.Add(addrLen);
// Called Address (BCD encoding)
packet.AddRange(EncodeBcdAddress(calledAddress));
// Calling Address (BCD encoding)
packet.AddRange(EncodeBcdAddress(callingAddress));
// Facility Length (none)
packet.Add(0x00);
// CUD - Protocol ID (TAD)
packet.Add(0x01);
packet.Add(0x02);
packet.Add(0x00);
packet.Add(0x00);
// CUD - Service Type (Interactive)
packet.Add(0x00);
// CUD - Terminal Type
packet.Add((byte)(terminalType >> 8));
packet.Add((byte)(terminalType & 0xFF));
// CUD - Options
packet.Add(options);
return packet.ToArray();
}
private byte[] EncodeBcdAddress(string address)
{
// Convert decimal string to BCD
// "100" -> 0x01 0x00
List<byte> bcd = new List<byte>();
for (int i = 0; i < address.Length; i += 2)
{
byte high = (byte)(address[i] - '0');
byte low = (i + 1 < address.Length) ? (byte)(address[i + 1] - '0') : (byte)0;
bcd.Add((byte)((high << 4) | low));
}
return bcd.ToArray();
}
}
// Usage:
var callRequest = new TadCallRequest();
byte[] x25Packet = callRequest.CreateCallRequestPacket(
lcn: 0x01,
calledAddress: "102", // Node 102
callingAddress: "100", // Node 100
terminalType: 0x0100, // Generic terminal
options: 0x40 // Remote echo, 7-bit
);
// Wrap in HDLC frame
byte[] hdlcFrame = CreateHdlcFrame(0x03, 0x00, x25Packet);
Receiving and Parsing TAD Call Request¶
public class TadCallParser
{
public struct TadCallInfo
{
public byte LogicalChannel;
public string CalledAddress;
public string CallingAddress;
public uint ProtocolId;
public byte ServiceType;
public ushort TerminalType;
public byte Options;
public bool IsTadProtocol;
}
public TadCallInfo ParseCallRequest(byte[] x25Packet)
{
TadCallInfo info = new TadCallInfo();
int offset = 0;
// GFI
byte gfi = x25Packet[offset++];
// LCN
info.LogicalChannel = x25Packet[offset++];
// Packet Type
byte packetType = x25Packet[offset++];
if (packetType != 0x0B)
throw new Exception("Not a Call Request packet");
// Address Lengths
byte addrLen = x25Packet[offset++];
int calledLen = (addrLen >> 4) & 0x0F;
int callingLen = addrLen & 0x0F;
// Called Address
info.CalledAddress = DecodeBcdAddress(x25Packet, ref offset, calledLen);
// Calling Address
info.CallingAddress = DecodeBcdAddress(x25Packet, ref offset, callingLen);
// Facility Length
byte facLen = x25Packet[offset++];
offset += facLen; // Skip facilities
// CUD - Check if TAD protocol
if (offset + 8 <= x25Packet.Length)
{
// Protocol ID
info.ProtocolId = (uint)((x25Packet[offset] << 24) |
(x25Packet[offset + 1] << 16) |
(x25Packet[offset + 2] << 8) |
x25Packet[offset + 3]);
offset += 4;
// Check if TAD (0x01020000)
info.IsTadProtocol = (info.ProtocolId == 0x01020000);
if (info.IsTadProtocol)
{
// Service Type
info.ServiceType = x25Packet[offset++];
// Terminal Type
info.TerminalType = (ushort)((x25Packet[offset] << 8) | x25Packet[offset + 1]);
offset += 2;
// Options
info.Options = x25Packet[offset++];
}
}
return info;
}
private string DecodeBcdAddress(byte[] data, ref int offset, int digitCount)
{
StringBuilder addr = new StringBuilder();
int byteCount = (digitCount + 1) / 2;
for (int i = 0; i < byteCount; i++)
{
byte bcdByte = data[offset++];
addr.Append((bcdByte >> 4) & 0x0F);
if (addr.Length < digitCount)
addr.Append(bcdByte & 0x0F);
}
return addr.ToString();
}
}
// Usage:
var parser = new TadCallParser();
TadCallInfo info = parser.ParseCallRequest(x25Packet);
if (info.IsTadProtocol)
{
Console.WriteLine($"TAD Call from {info.CallingAddress} to {info.CalledAddress}");
Console.WriteLine($"Terminal Type: 0x{info.TerminalType:X4}");
Console.WriteLine($"Service: {info.ServiceType}");
Console.WriteLine($"Options: 0x{info.Options:X2}");
// Send Call Accepted
SendCallAccepted(info.LogicalChannel);
// Send TAD configuration messages
SendTadConfig(info.TerminalType, info.Options);
}
Testing and Validation¶
Unit Test: Create TAD Call Request¶
[TestMethod]
public void TestCreateTadCallRequest()
{
var callRequest = new TadCallRequest();
byte[] packet = callRequest.CreateCallRequestPacket(
lcn: 0x01,
calledAddress: "102",
callingAddress: "100",
terminalType: 0x0003, // VT100
options: 0xC0 // 8-bit, remote echo
);
// Verify structure
Assert.AreEqual(0x11, packet[0]); // GFI
Assert.AreEqual(0x01, packet[1]); // LCN
Assert.AreEqual(0x0B, packet[2]); // Call Request
// Verify CUD Protocol ID
Assert.AreEqual(0x01, packet[9]); // TAD protocol
Assert.AreEqual(0x02, packet[10]);
Assert.AreEqual(0x00, packet[11]);
Assert.AreEqual(0x00, packet[12]);
// Verify Service Type
Assert.AreEqual(0x00, packet[13]); // Interactive
// Verify Terminal Type
Assert.AreEqual(0x00, packet[14]); // VT100 high byte
Assert.AreEqual(0x03, packet[15]); // VT100 low byte
// Verify Options
Assert.AreEqual(0xC0, packet[16]); // 8-bit + remote echo
}
Unit Test: Parse TAD Call Request¶
[TestMethod]
public void TestParseTadCallRequest()
{
byte[] packet = new byte[] {
0x11, 0x01, 0x0B, 0x33, // GFI, LCN, Type, AddrLen
0x01, 0x02, // Called: "102"
0x01, 0x00, // Calling: "100"
0x00, // Facility length
0x01, 0x02, 0x00, 0x00, // Protocol ID (TAD)
0x00, // Service (Interactive)
0x01, 0x00, // Terminal type (Generic)
0x40 // Options (Remote echo)
};
var parser = new TadCallParser();
var info = parser.ParseCallRequest(packet);
Assert.IsTrue(info.IsTadProtocol);
Assert.AreEqual("102", info.CalledAddress);
Assert.AreEqual("100", info.CallingAddress);
Assert.AreEqual(0x0100, info.TerminalType);
Assert.AreEqual(0x00, info.ServiceType);
Assert.AreEqual(0x40, info.Options);
}
Summary¶
Key Points for TAD Identification¶
- CUD Protocol ID:
0x01 0x02 0x00 0x00identifies TAD protocol - Minimum CUD Size: 8 bytes (Protocol ID + Service + Terminal Type + Options)
- Location: CUD appears in X.25 Call Request packet after addresses and facilities
- Encapsulation: CUD is inside X.25 packet, which is inside HDLC frame
Complete Protocol Stack for TAD Call¶
┌─────────────────────────────────────────┐
│ HDLC Frame (Flag, Addr, Control, FCS) │
│ ┌───────────────────────────────────┐ │
│ │ X.25 Call Request │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ CUD (Call User Data) │ │ │
│ │ │ ┌───────────────────────┐ │ │ │
│ │ │ │ TAD Protocol ID │ │ │ │
│ │ │ │ Service Type │ │ │ │
│ │ │ │ Terminal Type │ │ │ │
│ │ │ │ Options │ │ │ │
│ │ │ └───────────────────────┘ │ │ │
│ │ └─────────────────────────────┘ │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
Implementation Checklist¶
- [ ] Create X.25 Call Request with CUD
- [ ] Encode Protocol ID as
0x01 0x02 0x00 0x00 - [ ] Include Service Type (0x00 for interactive)
- [ ] Include Terminal Type (from user configuration)
- [ ] Include Options byte (from terminal capabilities)
- [ ] Wrap in HDLC frame
- [ ] Parse incoming Call Requests for TAD CUD
- [ ] Validate Protocol ID before accepting call
- [ ] Extract terminal configuration from CUD
- [ ] Send Call Accepted + TAD configuration messages
Document Path: Source Code\Sintran L\NPL\TAD-X25-CUD-Specification.md
Related Documents:
- TAD-Protocol-Analysis.md - TAD protocol specification
- TAD-Message-Formats.md - TAD message formats
- TAD-HDLC-Encapsulation.md - Complete encapsulation
- PAD_Connection_Analysis.md - Actual connection traces