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.
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
crcfield is computed the same, but spread across
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 field is always the value
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
┌──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.
This is the length of the
┌────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
type fields. Therefore, to
compute the length of just the
data field, take the value of the
length field and subtract three.
These fields are the transmission (
tx_seq) and receive (
numbers. They are used to determine the proper ordering of messages,
acknowledge which messages have been received by each side, and for flow
tx_seq field is incremented by one for each
DATA packet that is
- This is unlike TCP sequence numbers, which are incremented based on the size of data transmitted.
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 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|
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
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 field is used to transmit both information from higher layers (e.g
tokens) and some P3 control information (e.g a
This is the last byte of the packet. It is always the value
This section covers the different types of packets in more depth.
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:
This is the layout of an
INIT packet for the 32-bit version of the 3.0
client. Other versions have a different layout.
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 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:
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 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 packet ("synchronize sequence"?) is used to elicit an
SSR packet from
the other side.
SSR packet ("synchronize sequence response"?) is the response to an
packet. It instructs the receiver to resend messages not received by the sender