add tlv documentation

This commit is contained in:
Johannes Kimmel 2021-12-14 07:02:01 +01:00
parent 4b5fce5c1f
commit 3f5370882f
1 changed files with 141 additions and 39 deletions

View File

@ -1,6 +1,11 @@
//go:generate stringer -type=Type -trimprefix Type //go:generate stringer -type=Type -trimprefix Type
//go:generate stringer -type=SubType -trimprefix SubType //go:generate stringer -type=SubType -trimprefix SubType
//go:generate stringer -type=AEType -trimprefix AE //go:generate stringer -type=AEType -trimprefix AE
// Package tlv implements a parser for TLV encoded babel messages defined in rfc8966
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4
// https://datatracker.ietf.org/doc/html/draft-ietf-babel-source-specific-07#section-7
package tlv package tlv
import ( import (
@ -11,8 +16,10 @@ import (
"inet.af/netaddr" "inet.af/netaddr"
) )
// Type encodes the type of TLV
type Type uint8 type Type uint8
// Type TLV constants
const ( const (
TypePad1 = Type(0) TypePad1 = Type(0)
TypePadN = Type(1) TypePadN = Type(1)
@ -29,17 +36,21 @@ const (
TypeHMAC = Type(12) TypeHMAC = Type(12)
) )
// TLV holds a single TLV
type TLV interface { type TLV interface {
T() Type T() Type
L() uint8 L() uint8
} }
// SubType encodes the type of Sub-TLV
type SubType uint8 type SubType uint8
// IsMandatory checks if a Sub-TLV is mandatory
func (s SubType) IsMandatory() bool { func (s SubType) IsMandatory() bool {
return s >= 128 return s >= 128
} }
// SubType Sub-TLV constants
const ( const (
SubTypePad1 = SubType(0) SubTypePad1 = SubType(0)
SubTypePadN = SubType(1) SubTypePadN = SubType(1)
@ -48,13 +59,16 @@ const (
SubTypeSourcePrefix = SubType(128) SubTypeSourcePrefix = SubType(128)
) )
// SubTLV holds a single Sub-TLV
type SubTLV interface { type SubTLV interface {
T() SubType T() SubType
L() uint8 L() uint8
} }
// AEType encodes the AE field in TLVs
type AEType uint8 type AEType uint8
// AEType AE constants
const ( const (
AEWildcard = AEType(0) AEWildcard = AEType(0)
AEIPv4 = AEType(1) AEIPv4 = AEType(1)
@ -63,9 +77,12 @@ const (
AEIPv4oIPv6 = AEType(4) AEIPv4oIPv6 = AEType(4)
) )
// AEFromPrefix returns the address encoding of a prefix:
func AEFromPrefix(p netaddr.IPPrefix) AEType { func AEFromPrefix(p netaddr.IPPrefix) AEType {
return AEFromIP(p.IP()) return AEFromIP(p.IP())
} }
// AEFromIP returns the address encoding of an address.
func AEFromIP(p netaddr.IP) AEType { func AEFromIP(p netaddr.IP) AEType {
switch { switch {
case p.IsZero(): case p.IsZero():
@ -80,6 +97,7 @@ func AEFromIP(p netaddr.IP) AEType {
panic("unknown AE") panic("unknown AE")
} }
// Scanner splits bytes into TLV tokens.
type Scanner struct { type Scanner struct {
buf []byte buf []byte
err error err error
@ -87,17 +105,15 @@ type Scanner struct {
l uint8 l uint8
} }
func NewTLVScanner(buf []byte) *Scanner { // Reset resets a scanner state and sets a new byte slice to work on.
return &Scanner{
buf: buf,
}
}
func (ts *Scanner) Reset(buf []byte) { func (ts *Scanner) Reset(buf []byte) {
*ts = Scanner{} *ts = Scanner{}
ts.buf = buf ts.buf = buf
} }
// Scan scans for the next TLV
//
// Returns true if a TLV is found, or false on error or no more TLVs are found.
func (ts *Scanner) Scan() bool { func (ts *Scanner) Scan() bool {
if ts.err != nil { if ts.err != nil {
return false return false
@ -140,14 +156,17 @@ func (ts *Scanner) Scan() bool {
return true return true
} }
// Err returns the first error that occured during scanning.
func (ts *Scanner) Err() error { func (ts *Scanner) Err() error {
return ts.err return ts.err
} }
// Raw returns an unparsed TLV
func (ts *Scanner) Raw() Raw { func (ts *Scanner) Raw() Raw {
return Raw{ts.t, ts.l, ts.buf[:ts.l:ts.l]} return Raw{ts.t, ts.l, ts.buf[:ts.l:ts.l]}
} }
// PacketDecoder splits a packet into TLVs and parses their content
type PacketDecoder struct { type PacketDecoder struct {
tlvscanner Scanner tlvscanner Scanner
@ -163,6 +182,7 @@ type PacketDecoder struct {
err error err error
} }
// Reset clears the parser state and sets a new byte slice to work on.
func (s *PacketDecoder) Reset(b []byte, nexthop netaddr.IP) { func (s *PacketDecoder) Reset(b []byte, nexthop netaddr.IP) {
*s = PacketDecoder{} *s = PacketDecoder{}
s.tlvscanner.Reset(b) s.tlvscanner.Reset(b)
@ -173,6 +193,9 @@ func (s *PacketDecoder) Reset(b []byte, nexthop netaddr.IP) {
s.nexthopv4 = nexthop s.nexthopv4 = nexthop
} }
} }
// Scan parses the next TLV.
// Returns true on success or false on error and when no more TLVs can be found.
func (s *PacketDecoder) Scan() bool { func (s *PacketDecoder) Scan() bool {
if s.err != nil { if s.err != nil {
return false return false
@ -189,20 +212,20 @@ func (s *PacketDecoder) Scan() bool {
switch raw.T() { switch raw.T() {
case TypePad1: case TypePad1:
s.tlv, s.subtlv, s.err = Pad1FromBytes(raw.V()) s.tlv, s.subtlv, s.err = pad1FromBytes(raw.V())
case TypePadN: case TypePadN:
s.tlv, s.subtlv, s.err = PadNFromBytes(raw.V()) s.tlv, s.subtlv, s.err = padNFromBytes(raw.V())
case TypeAckReq: case TypeAckReq:
s.tlv, s.subtlv, s.err = AckReqFromBytes(raw.V()) s.tlv, s.subtlv, s.err = ackReqFromBytes(raw.V())
case TypeAck: case TypeAck:
s.tlv, s.subtlv, s.err = AckFromBytes(raw.V()) s.tlv, s.subtlv, s.err = ackFromBytes(raw.V())
case TypeHello: case TypeHello:
s.tlv, s.subtlv, s.err = HelloFromBytes(raw.V()) s.tlv, s.subtlv, s.err = helloFromBytes(raw.V())
case TypeIHU: case TypeIHU:
s.tlv, s.subtlv, s.err = IHUFromBytes(raw.V()) s.tlv, s.subtlv, s.err = ihuFromBytes(raw.V())
case TypeRouterID: case TypeRouterID:
var rid RouterID var rid RouterID
rid, s.subtlv, s.err = RouterIDFromBytes(raw.V()) rid, s.subtlv, s.err = routerIDFromBytes(raw.V())
if s.err != nil { if s.err != nil {
break break
} }
@ -211,7 +234,7 @@ func (s *PacketDecoder) Scan() bool {
s.routerID = rid s.routerID = rid
case TypeNextHop: case TypeNextHop:
var nh NextHop var nh NextHop
nh, s.subtlv, s.err = NextHopFromBytes(raw.V()) nh, s.subtlv, s.err = nextHopFromBytes(raw.V())
if s.err != nil { if s.err != nil {
break break
} }
@ -225,11 +248,11 @@ func (s *PacketDecoder) Scan() bool {
s.nexthopv6 = nh.Address s.nexthopv6 = nh.Address
} }
case TypeUpdate: case TypeUpdate:
s.tlv, s.subtlv, s.err = s.UpdateFromBytes(raw.V()) s.tlv, s.subtlv, s.err = s.updateFromBytes(raw.V())
case TypeRouteRequest: case TypeRouteRequest:
s.tlv, s.subtlv, s.err = RouteRequestFromBytes(raw.V()) s.tlv, s.subtlv, s.err = routeRequestFromBytes(raw.V())
case TypeSeqnoRequest: case TypeSeqnoRequest:
s.tlv, s.subtlv, s.err = SeqnoRequestFromBytes(raw.V()) s.tlv, s.subtlv, s.err = seqnoRequestFromBytes(raw.V())
case TypeTSPC: case TypeTSPC:
s.tlv = raw s.tlv = raw
s.subtlv = nil s.subtlv = nil
@ -242,49 +265,51 @@ func (s *PacketDecoder) Scan() bool {
return s.err == nil return s.err == nil
} }
// TLV returns the last successfully parsed TLV
func (s *PacketDecoder) TLV() TLV { func (s *PacketDecoder) TLV() TLV {
if s.err != nil { if s.err != nil {
return nil return nil
} }
return s.tlv return s.tlv
} }
// SubTLV returns the last successfully parsed Sub-TLV
func (s *PacketDecoder) SubTLV() []byte { func (s *PacketDecoder) SubTLV() []byte {
if s.err != nil { if s.err != nil {
return nil return nil
} }
return s.subtlv return s.subtlv
} }
// Err returns the first error that occured during parsing.
func (s *PacketDecoder) Err() error { func (s *PacketDecoder) Err() error {
return s.err return s.err
} }
// Raw holds an unparsed TLV
type Raw struct { type Raw struct {
t Type t Type
l uint8 l uint8
v []byte v []byte
} }
// T returns the Type of a Raw TLV
func (t Raw) T() Type { func (t Raw) T() Type {
return t.t return t.t
} }
// L returns the value of the length field in a TLV
func (t Raw) L() uint8 { func (t Raw) L() uint8 {
return t.l return t.l
} }
// V returns the message body of a TLV
func (t Raw) V() []byte { func (t Raw) V() []byte {
return t.v return t.v
} }
type ErrTypeMismatch struct { // ErrTLVLength is used to inform about invalid length fields in TLVs
want Type
got Type
}
func (e ErrTypeMismatch) Error() string {
return fmt.Sprintf("Error parsing TLV: Wrong type %s, wanted %s", e.got, e.want)
}
type ErrTLVLength struct { type ErrTLVLength struct {
l int l int
want int want int
@ -301,6 +326,7 @@ func assertLengthGreater(b []byte, t Type, l int) error {
return nil return nil
} }
// ErrSubTLVLength is used to inform about invalid length fields in Sub-TLVs
type ErrSubTLVLength struct { type ErrSubTLVLength struct {
l int l int
want int want int
@ -317,51 +343,70 @@ func assertSubLengthGreater(b []byte, t SubType, l int) error {
return nil return nil
} }
// Pad1 TLV
//
// 1 byte padding that is silently ignored.
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.1 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.1
type Pad1 struct{} type Pad1 struct{}
// T returns TypePad1.
func (Pad1) T() Type { func (Pad1) T() Type {
return TypePad1 return TypePad1
} }
// L returns 0 message body length.
func (Pad1) L() uint8 { func (Pad1) L() uint8 {
return 8 return 0
} }
func Pad1FromBytes(b []byte) (Pad1, []byte, error) {
func pad1FromBytes(b []byte) (Pad1, []byte, error) {
if err := assertLengthGreater(b, TypePad1, 0); err != nil { if err := assertLengthGreater(b, TypePad1, 0); err != nil {
return Pad1{}, b, err return Pad1{}, b, err
} }
return Pad1{}, b[1:], nil return Pad1{}, b[1:], nil
} }
// PadN TLV
//
// Multi byte padding that is silently ignored.
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.2 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.2
type PadN uint8 type PadN uint8
// T returns TypePadN.
func (PadN) T() Type { func (PadN) T() Type {
return TypePadN return TypePadN
} }
// L returns the length of the padding.
func (p PadN) L() uint8 { func (p PadN) L() uint8 {
return 2 + uint8(p) // TODO: overflow? return uint8(p)
} }
func PadNFromBytes(b []byte) (PadN, []byte, error) {
func padNFromBytes(b []byte) (PadN, []byte, error) {
if err := assertLengthGreater(b, TypePadN, 0); err != nil { if err := assertLengthGreater(b, TypePadN, 0); err != nil {
return PadN(0), b, err return PadN(0), b, err
} }
return PadN(b[1]), b[1:], nil return PadN(b[1]), b[1:], nil
} }
// AckReq - Acknowledgment Request TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.3 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.3
type AckReq struct { type AckReq struct {
Opaque [2]byte Opaque [2]byte
Interval uint16 Interval uint16
} }
// T returns TypePadReq.
func (AckReq) T() Type { func (AckReq) T() Type {
return TypeAckReq return TypeAckReq
} }
// L 8.
func (a AckReq) L() uint8 { func (a AckReq) L() uint8 {
return 8 return 8
} }
func AckReqFromBytes(b []byte) (AckReq, []byte, error) { func ackReqFromBytes(b []byte) (AckReq, []byte, error) {
if err := assertLengthGreater(b, TypeAckReq, 6); err != nil { if err := assertLengthGreater(b, TypeAckReq, 6); err != nil {
return AckReq{}, b, err return AckReq{}, b, err
} }
@ -374,18 +419,23 @@ func AckReqFromBytes(b []byte) (AckReq, []byte, error) {
return ar, b[6:], nil return ar, b[6:], nil
} }
// Ack - Acknowledgment TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.4 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.4
type Ack struct { type Ack struct {
Opaque uint16 Opaque uint16
} }
// T returns TypeAck.
func (Ack) T() Type { func (Ack) T() Type {
return TypeAck return TypeAck
} }
// L is 4.
func (Ack) L() uint8 { func (Ack) L() uint8 {
return 4 return 4
} }
func AckFromBytes(b []byte) (Ack, []byte, error) { func ackFromBytes(b []byte) (Ack, []byte, error) {
if err := assertLengthGreater(b, TypeAck, 2); err != nil { if err := assertLengthGreater(b, TypeAck, 2); err != nil {
return Ack{}, b, err return Ack{}, b, err
} }
@ -393,6 +443,8 @@ func AckFromBytes(b []byte) (Ack, []byte, error) {
return Ack{uint16(b[0])<<8 | uint16(b[1])}, b[4:], nil return Ack{uint16(b[0])<<8 | uint16(b[1])}, b[4:], nil
} }
// Hello TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.5 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.5
type Hello struct { type Hello struct {
Flags uint16 Flags uint16
@ -400,13 +452,16 @@ type Hello struct {
Interval uint16 Interval uint16
} }
// T returns TypeHello.
func (Hello) T() Type { func (Hello) T() Type {
return TypeHello return TypeHello
} }
// L is 8.
func (Hello) L() uint8 { func (Hello) L() uint8 {
return 8 return 8
} }
func HelloFromBytes(b []byte) (Hello, []byte, error) { func helloFromBytes(b []byte) (Hello, []byte, error) {
if err := assertLengthGreater(b, TypeHello, 6); err != nil { if err := assertLengthGreater(b, TypeHello, 6); err != nil {
return Hello{}, b, err return Hello{}, b, err
} }
@ -419,6 +474,8 @@ func HelloFromBytes(b []byte) (Hello, []byte, error) {
return h, b[6:], nil return h, b[6:], nil
} }
// IHU - I Heard You TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.6 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.6
type IHU struct { type IHU struct {
// AE uint8 // AE uint8
@ -428,12 +485,17 @@ type IHU struct {
Address netaddr.IP Address netaddr.IP
} }
// T returns TypeIHU.
func (IHU) T() Type { func (IHU) T() Type {
return TypeIHU return TypeIHU
} }
// AE returns the address encofing
func (i IHU) AE() AEType { func (i IHU) AE() AEType {
return AEFromIP(i.Address) return AEFromIP(i.Address)
} }
// L depends on the address enoding, but is at least 6 bytes.
func (i IHU) L() uint8 { func (i IHU) L() uint8 {
switch i.AE() { switch i.AE() {
case 0: case 0:
@ -447,7 +509,7 @@ func (i IHU) L() uint8 {
} }
panic("invalid AE field") panic("invalid AE field")
} }
func IHUFromBytes(b []byte) (IHU, []byte, error) { func ihuFromBytes(b []byte) (IHU, []byte, error) {
if err := assertLengthGreater(b, TypeIHU, 6); err != nil { if err := assertLengthGreater(b, TypeIHU, 6); err != nil {
return IHU{}, b, err return IHU{}, b, err
} }
@ -463,15 +525,18 @@ func IHUFromBytes(b []byte) (IHU, []byte, error) {
return ihu, b, err return ihu, b, err
} }
// RouterID TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.7 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.7
type RouterID [8]byte type RouterID [8]byte
// Errors specific to RouterID.
var ( var (
ErrRouterIDZeros = errors.New("Invalid RouterID: consists of all zeros") ErrRouterIDZeros = errors.New("Invalid RouterID: consists of all zeros")
ErrRouterIDOnes = errors.New("Invalid RouterID: consists of all ones") ErrRouterIDOnes = errors.New("Invalid RouterID: consists of all ones")
) )
func RouterIDFromBytes(b []byte) (RouterID, []byte, error) { func routerIDFromBytes(b []byte) (RouterID, []byte, error) {
if err := assertLengthGreater(b, TypeRouterID, 10); err != nil { if err := assertLengthGreater(b, TypeRouterID, 10); err != nil {
return RouterID{}, b, err return RouterID{}, b, err
} }
@ -490,12 +555,18 @@ func RouterIDFromBytes(b []byte) (RouterID, []byte, error) {
return rid, b, nil return rid, b, nil
} }
// T returns TypeRouterID.
func (RouterID) T() Type { func (RouterID) T() Type {
return TypeRouterID return TypeRouterID
} }
// L is 8.
func (RouterID) L() uint8 { func (RouterID) L() uint8 {
return 8 return 8
} }
// String formats a Routerid in EUI-64
func (r RouterID) String() string { func (r RouterID) String() string {
var buf bytes.Buffer var buf bytes.Buffer
buf.Grow(8*3 - 1) buf.Grow(8*3 - 1)
@ -508,6 +579,8 @@ func (r RouterID) String() string {
return buf.String() return buf.String()
} }
// NextHop TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.8 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.8
type NextHop struct { type NextHop struct {
// AE uint8 // AE uint8
@ -515,9 +588,12 @@ type NextHop struct {
Address netaddr.IP Address netaddr.IP
} }
// T returns TypeNextHop.
func (NextHop) T() Type { func (NextHop) T() Type {
return TypeNextHop return TypeNextHop
} }
// L depends on the address encoding, at least 2.
func (n NextHop) L() uint8 { func (n NextHop) L() uint8 {
switch AEFromIP(n.Address) { switch AEFromIP(n.Address) {
case 1: case 1:
@ -529,7 +605,7 @@ func (n NextHop) L() uint8 {
} }
panic("invalid AE field") panic("invalid AE field")
} }
func NextHopFromBytes(b []byte) (NextHop, []byte, error) { func nextHopFromBytes(b []byte) (NextHop, []byte, error) {
if err := assertLengthGreater(b, TypeNextHop, 6); err != nil { if err := assertLengthGreater(b, TypeNextHop, 6); err != nil {
return NextHop{}, b, err return NextHop{}, b, err
} }
@ -541,6 +617,8 @@ func NextHopFromBytes(b []byte) (NextHop, []byte, error) {
return nh, b, err return nh, b, err
} }
// Update TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.9 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.9
type Update struct { type Update struct {
// AE uint8 // AE uint8
@ -555,18 +633,23 @@ type Update struct {
NextHop netaddr.IP NextHop netaddr.IP
} }
// T returns TypeUpdate.
func (Update) T() Type { func (Update) T() Type {
return TypeUpdate return TypeUpdate
} }
// L depends on the anounced prefix, at least 10.
func (u Update) L() uint8 { func (u Update) L() uint8 {
return 10 + psizeFromPlen(u.Prefix.Bits()) return 10 + psizeFromPlen(u.Prefix.Bits())
} }
// FormatHeader returns a string of the most important fields except the prefix
func (u Update) FormatHeader() string { func (u Update) FormatHeader() string {
return fmt.Sprintf("Flags 0x%02x Omitted %2d Interval %4d Seqno %5d Metric %5d RouterID %s", return fmt.Sprintf("Flags 0x%02x Omitted %2d Interval %4d Seqno %5d Metric %5d RouterID %s",
u.Flags, u.Omitted, u.Interval, u.Seqno, u.Metric, u.RouterID, u.Flags, u.Omitted, u.Interval, u.Seqno, u.Metric, u.RouterID,
) )
} }
func (s *PacketDecoder) UpdateFromBytes(b []byte) (Update, []byte, error) { func (s *PacketDecoder) updateFromBytes(b []byte) (Update, []byte, error) {
if err := assertLengthGreater(b, TypeUpdate, 10); err != nil { if err := assertLengthGreater(b, TypeUpdate, 10); err != nil {
return Update{}, b, err return Update{}, b, err
} }
@ -619,6 +702,8 @@ func (s *PacketDecoder) UpdateFromBytes(b []byte) (Update, []byte, error) {
return u, b, err return u, b, err
} }
// RouteRequest TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.10 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.10
type RouteRequest struct { type RouteRequest struct {
// AE uint8 // AE uint8
@ -626,16 +711,21 @@ type RouteRequest struct {
Prefix netaddr.IPPrefix Prefix netaddr.IPPrefix
} }
// AE returns the address encoding of the requested prefix
func (r RouteRequest) AE() AEType { func (r RouteRequest) AE() AEType {
return AEFromPrefix(r.Prefix) return AEFromPrefix(r.Prefix)
} }
// T returns TypeRouteRequest.
func (RouteRequest) T() Type { func (RouteRequest) T() Type {
return TypeRouteRequest return TypeRouteRequest
} }
// L depends on the requested prefix, at least 4.
func (r RouteRequest) L() uint8 { func (r RouteRequest) L() uint8 {
return 4 + psizeFromPlen(r.Prefix.Bits()) return 4 + psizeFromPlen(r.Prefix.Bits())
} }
func RouteRequestFromBytes(b []byte) (RouteRequest, []byte, error) { func routeRequestFromBytes(b []byte) (RouteRequest, []byte, error) {
if err := assertLengthGreater(b, TypeRouteRequest, 2); err != nil { if err := assertLengthGreater(b, TypeRouteRequest, 2); err != nil {
return RouteRequest{}, b, err return RouteRequest{}, b, err
} }
@ -647,6 +737,8 @@ func RouteRequestFromBytes(b []byte) (RouteRequest, []byte, error) {
return rr, b, err return rr, b, err
} }
// SeqnoRequest TLV
//
// https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.11 // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.11
type SeqnoRequest struct { type SeqnoRequest struct {
// AE uint8 // AE uint8
@ -657,13 +749,16 @@ type SeqnoRequest struct {
Prefix netaddr.IPPrefix Prefix netaddr.IPPrefix
} }
// T returns TypeSeqnoRequest.
func (SeqnoRequest) T() Type { func (SeqnoRequest) T() Type {
return TypeSeqnoRequest return TypeSeqnoRequest
} }
// L depends on the requested prefix, at least 14.
func (r SeqnoRequest) L() uint8 { func (r SeqnoRequest) L() uint8 {
return 14 + psizeFromPlen(r.Prefix.Bits()) return 14 + psizeFromPlen(r.Prefix.Bits())
} }
func SeqnoRequestFromBytes(b []byte) (SeqnoRequest, []byte, error) { func seqnoRequestFromBytes(b []byte) (SeqnoRequest, []byte, error) {
if err := assertLengthGreater(b, TypeSeqnoRequest, 14); err != nil { if err := assertLengthGreater(b, TypeSeqnoRequest, 14); err != nil {
return SeqnoRequest{}, b, err return SeqnoRequest{}, b, err
} }
@ -681,17 +776,24 @@ func SeqnoRequestFromBytes(b []byte) (SeqnoRequest, []byte, error) {
return sr, b, err return sr, b, err
} }
// SourcePrefix Sub-TLV
//
// https://datatracker.ietf.org/doc/html/draft-ietf-babel-source-specific-07#section-7.1 // https://datatracker.ietf.org/doc/html/draft-ietf-babel-source-specific-07#section-7.1
type SourcePrefix struct { type SourcePrefix struct {
netaddr.IPPrefix netaddr.IPPrefix
} }
// T returns SubTypeSourcePrefix.
func (SourcePrefix) T() SubType { func (SourcePrefix) T() SubType {
return SubTypeSourcePrefix return SubTypeSourcePrefix
} }
// L depends on the encoded prefix
func (s SourcePrefix) L() uint8 { func (s SourcePrefix) L() uint8 {
return psizeFromPlen(s.Bits()) return psizeFromPlen(s.Bits())
} }
// SourcePrefixFromBytes parses a SourcePrefix SubTLV
func SourcePrefixFromBytes(b []byte) (SourcePrefix, []byte, error) { func SourcePrefixFromBytes(b []byte) (SourcePrefix, []byte, error) {
if err := assertSubLengthGreater(b, SubTypeSourcePrefix, 2); err != nil { if err := assertSubLengthGreater(b, SubTypeSourcePrefix, 2); err != nil {
return SourcePrefix{}, b, err return SourcePrefix{}, b, err