P3 Packets
Initially used over dialup modems, P3 was designed to be a link layer protocol. However some client software supports TCP/IP in addition to dialup. In these cases P3 is still used, however it is encapsulated in the payload portion of TCP.
│◀──── P3 ───▶│ ┌─────────────┬──────────────┬─────────────┐ │ IP Header │ TCP Header │ TCP Payload │ └─────────────┴──────────────┴─────────────┘
When encapsulated inside TCP, some features of P3 are redundant (e.g. CRC computation). Rather than create a new protocol, the existing P3 code was largely reused. Thus decoding P3 traffic sent over modem or over TCP/IP is the essentially the same.
Packet Fields
A P3 packet consists of the following fields in big endian (network) byte order: (1)
- This is the format of a P3 packet for the America Online client. P3 with
the Quantum Link client is similar, but does not include a
length
field. Thecrc
field is computed the same, but spread across4
bytes.
Byte Offset | Length | Type | Field |
---|---|---|---|
0x00 | 0x01 | uint8 | sync |
0x01 | 0x02 | uint16 | crc |
0x03 | 0x02 | uint16 | length |
0x05 | 0x01 | uint8 | tx_seq |
0x06 | 0x01 | uint8 | rx_seq |
0x07 | 0x01 | uint8 | type |
0x08 | varies | raw bytes | data |
last byte | 0x01 | uint8 | msg_end |
Here is an example P3 packet with the fields labeled:
crc tx_seq type msg_end │ │ │ │ ▼ ▼ ▼ ▼ ┌─────┐ ┌──┐ ┌──┐ ┌──┐ 5A F1 02 00 3C 10 7F A0 44 64 .. .. .. 0D └──┘ └─────┘ └──┘ └──────────────┘ ▲ ▲ ▲ ▲ │ │ │ │ sync length rx_seq data
sync
The sync
field is always the value 0x5A
crc
The crc
field is a 16-bit CRC computed over the packet, starting from the
first byte of the length
field, going up to (but not including) the msg_end
field.
Graphically:
┌──computed over──┐ │ ▼ │ ┌─────────────────────────────┐ ┌──┬─────┬─────┬──┬──┬──┬──────────────┬──┐ │5A│F1 02│00 3C│10│7F│A0│44 64 .. .. ..│0D│ └──┴─────┴─────┴──┴──┴──┴──────────────┴──┘ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ │ │ │ │ │ │ │ │ sync crc length │rx_seq│ data msg_end │ │ tx_seq type
The specific CRC algorithm used is CRC16-ARC. If developing your own tools, you can verify the results using this online CRC calculator. (1)
- Make sure to click the CRC-16 button, and look at the result for CRC-16/ARC.
An example implementation in Python, using a lookup table can be found in the PyOL project.
length
This is the length of the tx_seq
, rx_seq
, type
, and data
fields.
Graphically:
┌────covers────┐ │ ▼ │ ┌───────────────────────┐ ┌──┬─────┬─────┬──┬──┬──┬──────────────┬──┐ │5A│F1 02│00 3C│10│7F│A0│44 64 .. .. ..│0D│ └──┴─────┴─────┴──┴──┴──┴──────────────┴──┘ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ │ │ │ │ │ │ │ │ sync crc length │rx_seq│ data msg_end │ │ tx_seq type
The minimal value for this field is 3
, since a packet with no data
will still have the tx_seq
, rx_seq
, and type
fields. Therefore, to
compute the length of just the data
field, take the value of the
length
field and subtract three.
tx_seq
and rx_seq
These fields are the transmission (tx_seq
) and receive (rx_seq
) sequence
numbers. They are used to determine the proper ordering of messages,
acknowledge which messages have been received by each side, and for flow
control.
The tx_seq
field is incremented by one for each DATA
packet that is
transmitted. (1)
- This is unlike TCP sequence numbers, which are incremented based on the size of data transmitted.
The rx_seq
field is an acknowledgement of all packets up to and including
the value in the rx_seq
field. More information and examples can be found on
the sliding window page.
type
The type
field indicates the type of P3 packet, and how to interpret the
DATA
field (if present). The following are types are currently defined:
Value | Type of Packet |
---|---|
0x20 | DATA |
0x21 | SS |
0x22 | SSR |
0x23 | INIT |
0x24 | ACK |
0x25 | NAK |
0x26 | HEARTBEAT |
To detect packets that have been reflected back (e.g. due to a poor quality
transmission medium) the type
field for all packets sent from the client
have the high bit set. That is, the field is bitwise-OR'd with the value
0x80
.
To interpret the packet type field transmitted across the wire, ignore the high
bit by doing a bitwise-AND with the value 0x7F
. For example if the
value of the type
field is 0xA3
, this is an INIT
packet since
0x23 == 0xA3 & 0x7F
data
The data
field is used to transmit both information from higher layers (e.g
tokens) and some P3 control information (e.g a NAK
reason code).
msg_end
This is the last byte of the packet. It is always the value 0x0D
.
Packet Types
This section covers the different types of packets in more depth.
INIT
Packets
These packets are used to "initialize" (start) communication between the client and server. They are the first packet the client sends after a connection is established.
The data in an INIT
packet is laid out as follows:
Note
This is the layout of an INIT
packet for the 32-bit version of the 3.0
client. Other versions have a different layout.
Offset | Length | Type | Field |
---|---|---|---|
0x00 | 0x01 | uint8 | platform |
0x01 | 0x01 | uint8 | version_num |
0x02 | 0x01 | uint8 | sub_version_num |
0x03 | 0x01 | uint8 | unused |
0x04 | 0x01 | uint8 | machine_memory |
0x05 | 0x01 | uint8 | app_memory |
0x06 | 0x02 | uint16 | pc_type |
0x08 | 0x01 | uint8 | release_month |
0x09 | 0x01 | uint8 | release_day |
0x0A | 0x02 | uint16 | customer_class |
0x0C | 0x04 | uint32 | udo_timestamp |
0x10 | 0x02 | uint16 | dos_version |
0x12 | 0x02 | uint16 | session_flags |
0x14 | 0x01 | uint8 | video_type |
0x15 | 0x01 | uint8 | processor_type |
0x16 | 0x04 | uint32 | media_type |
0x1A | 0x04 | uint32 | windows_version |
0x1E | 0x01 | uint8 | memory_mode |
0x1F | 0x02 | uint16 | horizontal_res |
0x21 | 0x02 | uint16 | vertical_res |
0x23 | 0x02 | uint16 | num_colors |
0x25 | 0x01 | uint8 | filler |
0x26 | 0x02 | uint16 | region |
0x28 | 0x08 | uint16[4] | language |
0x30 | 0x01 | uint8 | connect_speed |
ACK
Packets
ACK
packets are used to acknowledge the tx_seq
of the most recent,
correctly received packet. Unlike TCP, P3 ACK packets are not sent for every
tx_seq
change. Instead, a P3 ACK is sent if a receiver buffer passes a certain
threshold, and in response to INIT and HEARTBEAT packets.
NAK
Packets
NAK
packets are sent in response to invalid packets. This can be if the
packet has an invalid crc
field, if the packet is received out of sequence
(as determined by tx_seq
) or if the packet is too large.
The payload of a NAK
packet decribes the error condition. The values are:
Value | Meaning |
---|---|
0x01 |
Invalid crc |
0x02 |
Incorrect sequence |
0x03 |
Incorrect length |
DATA
Packets
DATA
Packets usually form the bulk of P3 traffic. The first two bytes of a
DATA
packet contain a token
, which determines where and how the rest of the
payload is processed.
HEARTBEAT
Packets
HEARTBEAT
packets are sent when a previously sent DATA
packet is
unacknowledged by the receiver after a certain time. An ACK
packet is sent in
response. See the sliding window page
for more details.
SS
Packets
An SS
packet ("synchronize sequence"?) is used to elicit an SSR
packet from
the other side.
SSR
Packets
An SSR
packet ("synchronize sequence response"?) is the response to an SS
packet. It instructs the receiver to resend messages not received by the sender
(of the SSR
).