12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- package sctp
- import (
- "encoding/binary"
- "errors"
- "fmt"
- )
- /*
- chunkHeader represents a SCTP Chunk header, defined in https://tools.ietf.org/html/rfc4960#section-3.2
- The figure below illustrates the field format for the chunks to be
- transmitted in the SCTP packet. Each chunk is formatted with a Chunk
- Type field, a chunk-specific Flag field, a Chunk Length field, and a
- Value field.
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Chunk Type | Chunk Flags | Chunk Length |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | |
- | Chunk Value |
- | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- type chunkHeader struct {
- typ chunkType
- flags byte
- raw []byte
- }
- const (
- chunkHeaderSize = 4
- )
- // SCTP chunk header errors
- var (
- ErrChunkHeaderTooSmall = errors.New("raw is too small for a SCTP chunk")
- ErrChunkHeaderNotEnoughSpace = errors.New("not enough data left in SCTP packet to satisfy requested length")
- ErrChunkHeaderPaddingNonZero = errors.New("chunk padding is non-zero at offset")
- )
- func (c *chunkHeader) unmarshal(raw []byte) error {
- if len(raw) < chunkHeaderSize {
- return fmt.Errorf("%w: raw only %d bytes, %d is the minimum length", ErrChunkHeaderTooSmall, len(raw), chunkHeaderSize)
- }
- c.typ = chunkType(raw[0])
- c.flags = raw[1]
- length := binary.BigEndian.Uint16(raw[2:])
- // Length includes Chunk header
- valueLength := int(length - chunkHeaderSize)
- lengthAfterValue := len(raw) - (chunkHeaderSize + valueLength)
- if lengthAfterValue < 0 {
- return fmt.Errorf("%w: remain %d req %d ", ErrChunkHeaderNotEnoughSpace, valueLength, len(raw)-chunkHeaderSize)
- } else if lengthAfterValue < 4 {
- // https://tools.ietf.org/html/rfc4960#section-3.2
- // The Chunk Length field does not count any chunk padding.
- // Chunks (including Type, Length, and Value fields) are padded out
- // by the sender with all zero bytes to be a multiple of 4 bytes
- // long. This padding MUST NOT be more than 3 bytes in total. The
- // Chunk Length value does not include terminating padding of the
- // chunk. However, it does include padding of any variable-length
- // parameter except the last parameter in the chunk. The receiver
- // MUST ignore the padding.
- for i := lengthAfterValue; i > 0; i-- {
- paddingOffset := chunkHeaderSize + valueLength + (i - 1)
- if raw[paddingOffset] != 0 {
- return fmt.Errorf("%w: %d ", ErrChunkHeaderPaddingNonZero, paddingOffset)
- }
- }
- }
- c.raw = raw[chunkHeaderSize : chunkHeaderSize+valueLength]
- return nil
- }
- func (c *chunkHeader) marshal() ([]byte, error) {
- raw := make([]byte, 4+len(c.raw))
- raw[0] = uint8(c.typ)
- raw[1] = c.flags
- binary.BigEndian.PutUint16(raw[2:], uint16(len(c.raw)+chunkHeaderSize))
- copy(raw[4:], c.raw)
- return raw, nil
- }
- func (c *chunkHeader) valueLength() int {
- return len(c.raw)
- }
- // String makes chunkHeader printable
- func (c chunkHeader) String() string {
- return c.typ.String()
- }
|