jrouter/aurp/aurp.go

258 lines
5.6 KiB
Go
Raw Normal View History

2024-03-10 11:57:03 +11:00
// Package aurp implements types for encoding and decoding AppleTalk
// Update-Based Routing Protocol (AURP, RFC 1504) messages.
package aurp
import (
"encoding/binary"
"fmt"
2024-03-15 15:17:21 +11:00
"io"
2024-03-10 11:57:03 +11:00
)
2024-03-15 15:17:21 +11:00
// Header represents an AURP packet header. It includes the AURP-Tr header,
// which includes the domain header.
2024-03-10 11:57:03 +11:00
type Header struct {
2024-03-17 13:31:26 +11:00
TrHeader
2024-03-15 15:17:21 +11:00
2024-03-10 11:57:03 +11:00
CommandCode CmdCode
Flags RoutingFlag
}
2024-03-15 15:17:21 +11:00
// WriteTo writes the encoded form of the header to w.
func (h *Header) WriteTo(w io.Writer) (int64, error) {
a := acc(w)
2024-03-17 13:31:26 +11:00
a.writeTo(&h.TrHeader)
2024-03-15 15:17:21 +11:00
a.write16(uint16(h.CommandCode))
a.write16(uint16(h.Flags))
return a.ret()
}
2024-03-17 13:31:26 +11:00
func parseHeader(p []byte) (Header, []byte, error) {
2024-03-15 16:15:24 +11:00
if len(p) < 4 {
2024-03-17 13:31:26 +11:00
return Header{}, p, fmt.Errorf("insufficient input length %d for header", len(p))
2024-03-15 16:15:24 +11:00
}
2024-03-17 13:31:26 +11:00
return Header{
2024-03-15 16:15:24 +11:00
CommandCode: CmdCode(binary.BigEndian.Uint16(p[:2])),
Flags: RoutingFlag(binary.BigEndian.Uint16(p[2:4])),
}, p[4:], nil
}
2024-03-10 11:57:03 +11:00
// CmdCode is the command code used in AURP packets.
type CmdCode uint16
// Various command codes.
const (
CmdCodeRIReq CmdCode = 0x0001
CmdCodeRIRsp CmdCode = 0x0002
CmdCodeRIAck CmdCode = 0x0003
CmdCodeRIUpd CmdCode = 0x0004
CmdCodeRD CmdCode = 0x0005
CmdCodeZoneReq CmdCode = 0x0006 // has subcodes
CmdCodeZoneRsp CmdCode = 0x0007 // has subcodes
CmdCodeOpenReq CmdCode = 0x0008
CmdCodeOpenRsp CmdCode = 0x0009
CmdCodeTickle CmdCode = 0x000e
CmdCodeTickleAck CmdCode = 0x000f
)
// RoutingFlag is used in the flags field
type RoutingFlag uint16
const (
2024-03-22 14:20:31 +11:00
// Open-Req and RI-Req (SUI flags)
2024-03-10 11:57:03 +11:00
RoutingFlagSUINA RoutingFlag = 0x4000
RoutingFlagSUINDOrNRC RoutingFlag = 0x2000
RoutingFlagSUINDC RoutingFlag = 0x1000
RoutingFlagSUIZC RoutingFlag = 0x0800
2024-03-22 14:20:31 +11:00
// The combination of the above four flags (the SUI flags).
RoutingFlagAllSUI RoutingFlag = 0x7800
2024-03-10 11:57:03 +11:00
// RI-Rsp and GDZL-Rsp
RoutingFlagLast RoutingFlag = 0x8000
2024-03-22 14:20:31 +11:00
// Open-Rsp (environment flags)
2024-03-10 11:57:03 +11:00
RoutingFlagRemappingActive RoutingFlag = 0x4000
RoutingFlagHopCountReduction RoutingFlag = 0x2000
RoutingFlagReservedEnv RoutingFlag = 0x1800
// RI-Ack
RoutingFlagSendZoneInfo RoutingFlag = 0x4000
)
2024-03-15 15:17:21 +11:00
// Packet represents a full AURP packet, not including UDP or lower layers, but
// including the domain header and higher layers.
type Packet interface {
io.WriterTo
}
2024-03-15 16:15:24 +11:00
// ParsePacket parses the body of a UDP packet for a domain header, and then
// based on the packet type, an AURP-Tr header, an AURP routing header, and
// then a particular packet type.
//
// (This function contains the big switch statement.)
2024-03-15 15:17:21 +11:00
func ParsePacket(p []byte) (Packet, error) {
2024-03-22 16:14:55 +11:00
dh, p, err := ParseDomainHeader(p)
2024-03-15 16:15:24 +11:00
if err != nil {
return nil, err
}
if dh.Version != 1 {
return nil, fmt.Errorf("unsupported domain header version %d", dh.Version)
}
switch dh.PacketType {
case PacketTypeAppleTalk:
return &AppleTalkPacket{
DomainHeader: dh,
Data: p,
}, nil
case PacketTypeRouting:
tr, p, err := parseTrHeader(p)
if err != nil {
return nil, err
}
tr.DomainHeader = dh
h, p, err := parseHeader(p)
if err != nil {
return nil, err
}
h.TrHeader = tr
switch h.CommandCode {
case CmdCodeOpenReq:
oreq, err := parseOpenReq(p)
if err != nil {
return nil, err
}
oreq.Header = h
return oreq, nil
case CmdCodeOpenRsp:
orsp, err := parseOpenRsp(p)
if err != nil {
return nil, err
}
orsp.Header = h
return orsp, nil
2024-03-15 16:38:02 +11:00
2024-03-15 16:49:53 +11:00
case CmdCodeRIReq:
return &RIReqPacket{
Header: h,
}, nil
case CmdCodeRIRsp:
2024-03-17 12:56:56 +11:00
rir, err := parseRIRsp(p)
if err != nil {
return nil, err
}
rir.Header = h
return rir, nil
2024-03-15 16:49:53 +11:00
case CmdCodeRIAck:
return &RIAckPacket{
Header: h,
}, nil
2024-03-16 22:38:20 +11:00
case CmdCodeRIUpd:
riu, err := parseRIUpd(p)
if err != nil {
return nil, err
}
riu.Header = h
return riu, nil
2024-03-17 13:35:50 +11:00
case CmdCodeRD:
rd, err := parseRD(p)
if err != nil {
return nil, err
}
rd.Header = h
return rd, nil
2024-03-17 18:19:36 +11:00
case CmdCodeZoneReq:
sc, p, err := parseSubcode(p)
if err != nil {
return nil, err
}
switch sc {
2024-03-17 21:08:18 +11:00
case SubcodeZoneInfoReq:
2024-03-17 18:19:36 +11:00
zir, err := parseZIReqPacket(p)
if err != nil {
return nil, err
}
zir.Header = h
return zir, nil
2024-03-17 21:08:18 +11:00
case SubcodeGetDomainZoneList:
gdzl, err := parseGDZLReqPacket(p)
if err != nil {
return nil, err
}
gdzl.Header = h
return gdzl, nil
2024-03-17 18:19:36 +11:00
2024-03-17 21:08:18 +11:00
case SubcodeGetZonesNet:
gzn, err := parseGZNReqPacket(p)
if err != nil {
return nil, err
}
gzn.Header = h
return gzn, nil
2024-03-17 18:19:36 +11:00
default:
return nil, fmt.Errorf("unknown subcode %d", sc)
}
case CmdCodeZoneRsp:
sc, p, err := parseSubcode(p)
if err != nil {
return nil, err
}
switch sc {
2024-03-17 21:08:18 +11:00
case SubcodeZoneInfoNonExt, SubcodeZoneInfoExt:
2024-03-17 18:19:36 +11:00
zir, err := parseZIRspPacket(p)
if err != nil {
return nil, err
}
zir.Header = h
2024-03-17 21:08:18 +11:00
zir.Subcode = sc // 1 or 2, only known at this layer
2024-03-17 18:19:36 +11:00
return zir, nil
2024-03-17 21:08:18 +11:00
case SubcodeGetDomainZoneList:
gdzl, err := parseGDZLRspPacket(p)
if err != nil {
return nil, err
}
gdzl.Header = h
return gdzl, nil
2024-03-17 18:19:36 +11:00
2024-03-17 21:08:18 +11:00
case SubcodeGetZonesNet:
gzn, err := parseGZNRspPacket(p)
if err != nil {
return nil, err
}
gzn.Header = h
return gzn, nil
2024-03-17 18:19:36 +11:00
default:
return nil, fmt.Errorf("unknown subcode %d", sc)
}
case CmdCodeTickle:
return &TicklePacket{
Header: h,
}, nil
case CmdCodeTickleAck:
return &TickleAckPacket{
Header: h,
}, nil
2024-03-15 16:38:02 +11:00
default:
return nil, fmt.Errorf("unknown routing packet command code %d", h.CommandCode)
2024-03-15 16:15:24 +11:00
}
default:
return nil, fmt.Errorf("unsupported domain header packet type %d", dh.PacketType)
}
2024-03-15 15:17:21 +11:00
}