diff --git a/aurp/atalk.go b/aurp/atalk.go new file mode 100644 index 0000000..0b836f1 --- /dev/null +++ b/aurp/atalk.go @@ -0,0 +1,17 @@ +package aurp + +import "io" + +// AppleTalkPacket is for encapsulated AppleTalk traffic. +type AppleTalkPacket struct { + DomainHeader // where PacketTypeAppleTalk + + Data []byte +} + +func (p *AppleTalkPacket) WriteTo(w io.Writer) (int64, error) { + a := acc(w) + a.writeTo(&p.DomainHeader) + a.write(p.Data) + return a.ret() +} diff --git a/aurp/aurp.go b/aurp/aurp.go index c6b5078..2f6ae98 100644 --- a/aurp/aurp.go +++ b/aurp/aurp.go @@ -8,34 +8,6 @@ import ( "io" ) -// TrHeader represent an AURP-Tr packet header. It includes the domain header. -type TrHeader struct { - DomainHeader - - ConnectionID uint16 - Sequence uint16 // Note: 65535 is succeeded by 1, not 0 -} - -// WriteTo writes the encoded form of the header to w, including the domain -// header. -func (h *TrHeader) WriteTo(w io.Writer) (int64, error) { - a := acc(w) - a.writeTo(&h.DomainHeader) - a.write16(h.ConnectionID) - a.write16(h.Sequence) - return a.ret() -} - -func parseTrHeader(p []byte) (TrHeader, []byte, error) { - if len(p) < 4 { - return TrHeader{}, p, fmt.Errorf("insufficient input length %d for tr header", len(p)) - } - return TrHeader{ - ConnectionID: binary.BigEndian.Uint16(p[:2]), - Sequence: binary.BigEndian.Uint16(p[2:4]), - }, p[4:], nil -} - // Header represents an AURP packet header. It includes the AURP-Tr header, // which includes the domain header. type Header struct { @@ -86,16 +58,19 @@ const ( type RoutingFlag uint16 const ( - // Open-Req and RI-Req + // Open-Req and RI-Req (SUI flags) RoutingFlagSUINA RoutingFlag = 0x4000 RoutingFlagSUINDOrNRC RoutingFlag = 0x2000 RoutingFlagSUINDC RoutingFlag = 0x1000 RoutingFlagSUIZC RoutingFlag = 0x0800 + // The combination of the above four flags (the SUI flags). + RoutingFlagAllSUI RoutingFlag = 0x7800 + // RI-Rsp and GDZL-Rsp RoutingFlagLast RoutingFlag = 0x8000 - // Open-Rsp + // Open-Rsp (environment flags) RoutingFlagRemappingActive RoutingFlag = 0x4000 RoutingFlagHopCountReduction RoutingFlag = 0x2000 RoutingFlagReservedEnv RoutingFlag = 0x1800 @@ -110,20 +85,6 @@ type Packet interface { io.WriterTo } -// AppleTalkPacket is for encapsulated AppleTalk traffic. -type AppleTalkPacket struct { - DomainHeader // where PacketTypeAppleTalk - - Data []byte -} - -func (p *AppleTalkPacket) WriteTo(w io.Writer) (int64, error) { - a := acc(w) - a.writeTo(&p.DomainHeader) - a.write(p.Data) - return a.ret() -} - // 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. diff --git a/aurp/domain.go b/aurp/domain.go index 2853ab3..67d918a 100644 --- a/aurp/domain.go +++ b/aurp/domain.go @@ -12,8 +12,8 @@ import ( type DomainHeader struct { DestinationDI DomainIdentifier SourceDI DomainIdentifier - Version uint16 // Should always be 0x0001 - Reserved uint16 + Version uint16 // Should always be 0x0001 + Reserved uint16 // Should always be 0x0000 PacketType PacketType // 2 = AppleTalk data packet, 3 = AURP packet } diff --git a/aurp/open.go b/aurp/open.go index 1e1b052..20e0c3f 100644 --- a/aurp/open.go +++ b/aurp/open.go @@ -15,9 +15,6 @@ type OpenReqPacket struct { } func (p *OpenReqPacket) WriteTo(w io.Writer) (int64, error) { - p.Sequence = 0 - p.CommandCode = CmdCodeOpenReq - a := acc(w) a.writeTo(&p.Header) a.write16(p.Version) @@ -48,9 +45,6 @@ type OpenRspPacket struct { } func (p *OpenRspPacket) WriteTo(w io.Writer) (int64, error) { - p.Sequence = 0 - p.CommandCode = CmdCodeOpenRsp - a := acc(w) a.writeTo(&p.Header) a.write16(uint16(p.RateOrErrCode)) diff --git a/aurp/router_down.go b/aurp/router_down.go index a98b82a..71e4d2e 100644 --- a/aurp/router_down.go +++ b/aurp/router_down.go @@ -13,8 +13,6 @@ type RDPacket struct { } func (p *RDPacket) WriteTo(w io.Writer) (int64, error) { - p.CommandCode = CmdCodeRD - a := acc(w) a.writeTo(&p.Header) a.write16(uint16(p.ErrorCode)) diff --git a/aurp/routing_info.go b/aurp/routing_info.go index 5b71a64..0c9793e 100644 --- a/aurp/routing_info.go +++ b/aurp/routing_info.go @@ -10,12 +10,6 @@ type RIReqPacket struct { Header } -func (p *RIReqPacket) WriteTo(w io.Writer) (int64, error) { - p.Sequence = 0 - p.CommandCode = CmdCodeRIReq - return p.Header.WriteTo(w) -} - type RIRspPacket struct { Header @@ -23,8 +17,6 @@ type RIRspPacket struct { } func (p *RIRspPacket) WriteTo(w io.Writer) (int64, error) { - p.CommandCode = CmdCodeRIRsp - a := acc(w) a.writeTo(&p.Header) a.writeTo(p.Networks) @@ -45,11 +37,6 @@ type RIAckPacket struct { Header } -func (p *RIAckPacket) WriteTo(w io.Writer) (int64, error) { - p.CommandCode = CmdCodeRIAck - return p.Header.WriteTo(w) -} - type RIUpdPacket struct { Header @@ -57,8 +44,6 @@ type RIUpdPacket struct { } func (p *RIUpdPacket) WriteTo(w io.Writer) (int64, error) { - p.CommandCode = CmdCodeRIUpd - a := acc(w) a.writeTo(&p.Header) a.writeTo(p.Events) diff --git a/aurp/tickle.go b/aurp/tickle.go index ef3b88b..f8fff6d 100644 --- a/aurp/tickle.go +++ b/aurp/tickle.go @@ -1,25 +1,9 @@ package aurp -import "io" - type TicklePacket struct { Header } -func (p *TicklePacket) WriteTo(w io.Writer) (int64, error) { - p.Sequence = 0 - p.CommandCode = CmdCodeTickle - p.Flags = 0 - return p.Header.WriteTo(w) -} - type TickleAckPacket struct { Header } - -func (p *TickleAckPacket) WriteTo(w io.Writer) (int64, error) { - p.Sequence = 0 - p.CommandCode = CmdCodeTickleAck - p.Flags = 0 - return p.Header.WriteTo(w) -} diff --git a/aurp/transport.go b/aurp/transport.go new file mode 100644 index 0000000..da4e43b --- /dev/null +++ b/aurp/transport.go @@ -0,0 +1,99 @@ +package aurp + +import ( + "encoding/binary" + "fmt" + "io" +) + +// TrHeader represent an AURP-Tr packet header. It includes the domain header. +type TrHeader struct { + DomainHeader + + ConnectionID uint16 + Sequence uint16 +} + +// WriteTo writes the encoded form of the header to w, including the domain +// header. +func (h *TrHeader) WriteTo(w io.Writer) (int64, error) { + a := acc(w) + a.writeTo(&h.DomainHeader) + a.write16(h.ConnectionID) + a.write16(h.Sequence) + return a.ret() +} + +func parseTrHeader(p []byte) (TrHeader, []byte, error) { + if len(p) < 4 { + return TrHeader{}, p, fmt.Errorf("insufficient input length %d for tr header", len(p)) + } + return TrHeader{ + ConnectionID: binary.BigEndian.Uint16(p[:2]), + Sequence: binary.BigEndian.Uint16(p[2:4]), + }, p[4:], nil +} + +// incSequence increments the sequence number. +// Note that 0 is special and 65535+1 = 1, according to AURP. +func (tr *TrHeader) incSequence() { + tr.Sequence++ + if tr.Sequence == 0 { + tr.Sequence = 1 + } +} + +// transaction returns a new TrHeader based on this one, usable for transaction +// requests or responses. +func (tr *TrHeader) transaction() TrHeader { + return TrHeader{ + DomainHeader: DomainHeader{ + DestinationDI: tr.DestinationDI, + SourceDI: tr.SourceDI, + Version: 1, + Reserved: 0, + PacketType: PacketTypeRouting, + }, + ConnectionID: tr.ConnectionID, + Sequence: 0, // Transaction packets all use sequence number 0. + } +} + +// DataSender is used to track sender state in a one-way AURP connection. +// Note that both data senders and data recievers can send packets. +type DataSender struct { + TrHeader +} + +// NewOpenRspPacket returns a new Open-Rsp packet structure. +func (ds *DataSender) NewOpenRspPacket(envFlags RoutingFlag, rateOrErr int16, opts Options) *OpenRspPacket { + return &OpenRspPacket{ + Header: Header{ + TrHeader: ds.transaction(), + CommandCode: CmdCodeOpenRsp, + Flags: envFlags, + }, + RateOrErrCode: rateOrErr, + Options: opts, + } +} + +// DataReceiver is used to track reciever state in a one-way AURP connection. +// Note that both data senders and data recievers can send packets. +type DataReceiver struct { + TrHeader +} + +// NewOpenReqPacket returns a new Open-Req packet structure. By default it sets +// all SUI flags and uses version 1. +func (dr *DataReceiver) NewOpenReqPacket(opts Options) *OpenReqPacket { + return &OpenReqPacket{ + Header: Header{ + TrHeader: dr.transaction(), + CommandCode: CmdCodeOpenReq, + Flags: RoutingFlagAllSUI, + }, + Version: 1, + Options: opts, + } +} diff --git a/aurp/zone_info.go b/aurp/zone_info.go index ea98a8e..b3ef423 100644 --- a/aurp/zone_info.go +++ b/aurp/zone_info.go @@ -32,11 +32,6 @@ type ZIReqPacket struct { } func (p *ZIReqPacket) WriteTo(w io.Writer) (int64, error) { - p.Sequence = 0 - p.CommandCode = CmdCodeZoneReq - p.Flags = 0 - p.Subcode = SubcodeZoneInfoReq - a := acc(w) a.writeTo(&p.Header) a.write16(uint16(p.Subcode)) @@ -79,11 +74,6 @@ type ZIRspPacket struct { } func (p *ZIRspPacket) WriteTo(w io.Writer) (int64, error) { - p.Sequence = 0 - p.CommandCode = CmdCodeZoneRsp - p.Flags = 0 - // Subcode can vary for this packet type: it's either 1 or 2 - a := acc(w) a.writeTo(&p.Header) a.write16(uint16(p.Subcode)) @@ -109,11 +99,6 @@ type GDZLReqPacket struct { } func (p *GDZLReqPacket) WriteTo(w io.Writer) (int64, error) { - p.Sequence = 0 - p.CommandCode = CmdCodeZoneReq - p.Flags = 0 - p.Subcode = SubcodeGetDomainZoneList - a := acc(w) a.writeTo(&p.Header) a.write16(uint16(p.Subcode)) @@ -145,11 +130,6 @@ func (p *GDZLRspPacket) WriteTo(w io.Writer) (int64, error) { } } - p.Sequence = 0 - p.CommandCode = CmdCodeZoneRsp - // Flags is used to distinguish the final response packet, so leave alone - p.Subcode = SubcodeGetDomainZoneList - a := acc(w) a.writeTo(&p.Header) a.write16(uint16(p.Subcode)) @@ -207,11 +187,6 @@ func (p *GZNReqPacket) WriteTo(w io.Writer) (int64, error) { return 0, fmt.Errorf("zone name %q too long", p.ZoneName) } - p.Sequence = 0 - p.CommandCode = CmdCodeZoneReq - p.Flags = 0 - p.Subcode = SubcodeGetZonesNet - a := acc(w) a.writeTo(&p.Header) a.write16(uint16(p.Subcode))