Files
Reticulum-Go/pkg/packet/packet.go
2024-12-30 01:56:25 -06:00

171 lines
3.8 KiB
Go

package packet
import (
"encoding/binary"
"errors"
)
const (
HeaderSize = 2
AddressSize = 16
ContextSize = 1
MaxDataSize = 465 // Maximum size of payload data
)
// Header flags and types
const (
// First byte flags
IFACFlag = 0x80 // Interface authentication code flag
HeaderTypeFlag = 0x40 // Header type flag
ContextFlag = 0x20 // Context flag
PropagationFlags = 0x18 // Propagation type flags (bits 3-4)
DestinationFlags = 0x06 // Destination type flags (bits 1-2)
PacketTypeFlags = 0x01 // Packet type flags (bit 0)
// Second byte
HopsField = 0xFF // Number of hops (entire byte)
)
type Packet struct {
Header [2]byte
Addresses []byte // Either 16 or 32 bytes depending on header type
Context byte
Data []byte
AccessCode []byte // Optional: Only present if IFAC flag is set
}
func NewPacket(headerType, propagationType, destinationType, packetType byte, hops byte) *Packet {
p := &Packet{
Header: [2]byte{0, hops},
Addresses: make([]byte, 0),
Data: make([]byte, 0),
}
// Set header type
if headerType == HeaderType2 {
p.Header[0] |= HeaderTypeFlag
p.Addresses = make([]byte, 2*AddressSize) // Two address fields
} else {
p.Addresses = make([]byte, AddressSize) // One address field
}
// Set propagation type
p.Header[0] |= (propagationType << 3) & PropagationFlags
// Set destination type
p.Header[0] |= (destinationType << 1) & DestinationFlags
// Set packet type
p.Header[0] |= packetType & PacketTypeFlags
return p
}
func (p *Packet) SetAccessCode(code []byte) {
p.AccessCode = code
p.Header[0] |= IFACFlag
}
func (p *Packet) SetContext(context byte) {
p.Context = context
p.Header[0] |= ContextFlag
}
func (p *Packet) SetData(data []byte) error {
if len(data) > MaxDataSize {
return errors.New("data exceeds maximum allowed size")
}
p.Data = data
return nil
}
func (p *Packet) SetAddress(index int, address []byte) error {
if len(address) != AddressSize {
return errors.New("invalid address size")
}
offset := index * AddressSize
if offset+AddressSize > len(p.Addresses) {
return errors.New("address index out of range")
}
copy(p.Addresses[offset:], address)
return nil
}
func (p *Packet) Serialize() ([]byte, error) {
totalSize := HeaderSize + len(p.Addresses) + ContextSize + len(p.Data)
if p.AccessCode != nil {
totalSize += len(p.AccessCode)
}
buffer := make([]byte, totalSize)
offset := 0
// Write header
copy(buffer[offset:], p.Header[:])
offset += HeaderSize
// Write access code if present
if p.AccessCode != nil {
copy(buffer[offset:], p.AccessCode)
offset += len(p.AccessCode)
}
// Write addresses
copy(buffer[offset:], p.Addresses)
offset += len(p.Addresses)
// Write context
buffer[offset] = p.Context
offset += ContextSize
// Write data
copy(buffer[offset:], p.Data)
return buffer, nil
}
func ParsePacket(data []byte) (*Packet, error) {
if len(data) < HeaderSize {
return nil, errors.New("packet data too short")
}
p := &Packet{
Header: [2]byte{data[0], data[1]},
}
offset := HeaderSize
// Handle access code if present
if p.Header[0]&IFACFlag != 0 {
// Access code handling would go here
// For now, we'll assume no access code
return nil, errors.New("access code handling not implemented")
}
// Determine address size based on header type
addrLen := AddressSize
if p.Header[0]&HeaderTypeFlag != 0 {
addrLen = 2 * AddressSize
}
if len(data[offset:]) < addrLen+ContextSize {
return nil, errors.New("packet data too short for addresses and context")
}
// Copy addresses
p.Addresses = make([]byte, addrLen)
copy(p.Addresses, data[offset:offset+addrLen])
offset += addrLen
// Copy context
p.Context = data[offset]
offset++
// Copy remaining data
p.Data = make([]byte, len(data)-offset)
copy(p.Data, data[offset:])
return p, nil
}