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