mirror of
https://github.com/soypat/lneto.git
synced 2026-08-07 08:23:42 +00:00
63f7870fe5
* add handler.encapsulateNode * implement round robin handler approach * simplify round robin implementation * leave TODO * internet.node touch up * fix conflict resolve f-up * replace certain ErrShortBuffer with ErrTruncatedFrame error
129 lines
4.3 KiB
Go
129 lines
4.3 KiB
Go
package ipv6
|
|
|
|
import (
|
|
"encoding/binary"
|
|
|
|
"github.com/soypat/lneto"
|
|
)
|
|
|
|
// NewFrame returns a new [Frame] with data set to buf.
|
|
// An error is returned if the buffer size is smaller than 40.
|
|
// Users should still call [Frame.ValidateSize] before working
|
|
// with payload/options of frames to avoid panics.
|
|
func NewFrame(buf []byte) (Frame, error) {
|
|
if len(buf) < sizeHeader {
|
|
return Frame{buf: nil}, lneto.ErrTruncatedFrame
|
|
}
|
|
return Frame{buf: buf}, nil
|
|
}
|
|
|
|
// Frame encapsulates the raw data of an IPv6 packet
|
|
// and provides methods for manipulating, validating and
|
|
// retrieving fields and payload data. See [RFC8200].
|
|
//
|
|
// [RFC8200]: https://tools.ietf.org/html/rfc8200
|
|
type Frame struct {
|
|
buf []byte
|
|
}
|
|
|
|
// RawData returns the underlying slice with which the frame was created.
|
|
func (i6frm Frame) RawData() []byte { return i6frm.buf }
|
|
|
|
// Payload returns the contents of the IPv6 packet, which may be zero sized.
|
|
// Be sure to call [Frame.ValidateSize] beforehand to avoid panic.
|
|
func (i6frm Frame) Payload() []byte {
|
|
pl := i6frm.PayloadLength()
|
|
return i6frm.buf[sizeHeader : sizeHeader+pl]
|
|
}
|
|
|
|
// VersionTrafficAndFlow returns the version, Traffic and Flow label fields of the IPv6 header.
|
|
// See [ToS] Traffic Class. Version should be 6 for IPv6.
|
|
func (i6frm Frame) VersionTrafficAndFlow() (version uint8, tos ToS, flow uint32) {
|
|
v := binary.BigEndian.Uint32(i6frm.buf[0:4])
|
|
version = uint8(v >> (32 - 4))
|
|
tos = ToS(v >> (32 - 12))
|
|
flow = v & 0x000f_ffff
|
|
return version, tos, flow
|
|
}
|
|
|
|
// SetVersionTrafficAndFlow sets the version, ToS and Flow label in the IPv6 header. Version must be equal to 6.
|
|
// See [Frame.VersionTrafficAndFlow].
|
|
func (i6frm Frame) SetVersionTrafficAndFlow(version uint8, tos ToS, flow uint32) {
|
|
v := flow | uint32(tos)<<(32-12) | uint32(version)<<(32-4)
|
|
binary.BigEndian.PutUint32(i6frm.buf[0:4], v)
|
|
}
|
|
|
|
// PayloadLength returns the size of payload in octets(bytes) including any extension headers.
|
|
// The length is set to zero when a Hop-by-Hop extension header carries a Jumbo Payload option.
|
|
func (i6frm Frame) PayloadLength() uint16 {
|
|
return binary.BigEndian.Uint16(i6frm.buf[4:6])
|
|
}
|
|
|
|
// SetPayloadLength sets the payload length field of the IPv6 header. See [Frame.PayloadLength].
|
|
func (i6frm Frame) SetPayloadLength(pl uint16) {
|
|
binary.BigEndian.PutUint16(i6frm.buf[4:6], pl)
|
|
}
|
|
|
|
// NextHeader returns the Next Header field of the IPv6 header which usually specifies the transport layer
|
|
// protocol used by packet's payload.
|
|
func (i6frm Frame) NextHeader() lneto.IPProto {
|
|
return lneto.IPProto(i6frm.buf[6])
|
|
}
|
|
|
|
// SetNextHeader sets the Next Header (protocol) field of the IPv6 header. See [Frame.NextHeader].
|
|
func (i6frm Frame) SetNextHeader(proto lneto.IPProto) {
|
|
i6frm.buf[6] = uint8(proto)
|
|
}
|
|
|
|
// HopLimit returns the Hop Limit of the IPv6 header.
|
|
// This value is decremented by one at each forwarding node and the packet is discarded if it becomes 0.
|
|
// However, the destination node should process the packet normally even if received with a hop limit of 0.
|
|
func (i6frm Frame) HopLimit() uint8 {
|
|
return i6frm.buf[7]
|
|
}
|
|
|
|
// SetHopLimit sets the Hop Limit field of the IPv6 header. See [Frame.HopLimiy].
|
|
func (i6frm Frame) SetHopLimit(hop uint8) {
|
|
i6frm.buf[7] = hop
|
|
}
|
|
|
|
func (i6frm Frame) sourceAndDestinationAddr() []byte {
|
|
return i6frm.buf[8:40]
|
|
}
|
|
|
|
// SourceAddr returns pointer to the sending node unicast IPv6 address in the IP header.
|
|
func (i6frm Frame) SourceAddr() *[16]byte {
|
|
return (*[16]byte)(i6frm.buf[8:24])
|
|
}
|
|
|
|
// DestinationAddr returns pointer to the destination node unicast or multicast IPv6 address in the IP header.
|
|
func (i6frm Frame) DestinationAddr() *[16]byte {
|
|
return (*[16]byte)(i6frm.buf[24:40])
|
|
}
|
|
|
|
func (i6frm Frame) CRCWritePseudo(crc *lneto.CRC791) {
|
|
crc.WriteEven(i6frm.sourceAndDestinationAddr())
|
|
crc.AddUint32(uint32(i6frm.PayloadLength()))
|
|
crc.AddUint32(uint32(i6frm.NextHeader()))
|
|
}
|
|
|
|
// ClearHeader zeros out the header contents.
|
|
func (i6frm Frame) ClearHeader() {
|
|
for i := range i6frm.buf[:sizeHeader] {
|
|
i6frm.buf[i] = 0
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate API.
|
|
//
|
|
|
|
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
|
// the frame. It returns a non-nil error on finding an inconsistency.
|
|
func (i6frm Frame) ValidateSize(v *lneto.Validator) {
|
|
tl := i6frm.PayloadLength()
|
|
if int(tl)+sizeHeader > len(i6frm.RawData()) {
|
|
v.AddError(lneto.ErrInvalidLengthField)
|
|
}
|
|
}
|