1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
package sctp // nolint:dupl
import (
"errors"
"fmt"
)
/*
chunkInitAck represents an SCTP Chunk of type INIT ACK
See chunkInitCommon for the fixed headers
Variable Parameters Status Type Value
-------------------------------------------------------------
State Cookie Mandatory 7
IPv4 IP (Note 1) Optional 5
IPv6 IP (Note 1) Optional 6
Unrecognized Parameter Optional 8
Reserved for ECN Capable (Note 2) Optional 32768 (0x8000)
Host Name IP (Note 3) Optional 11<Paste>
*/
type chunkInitAck struct {
chunkHeader
chunkInitCommon
}
// Init ack chunk errors
var (
ErrChunkTypeNotInitAck = errors.New("ChunkType is not of type INIT ACK")
ErrChunkNotLongEnoughForParams = errors.New("chunk Value isn't long enough for mandatory parameters exp")
ErrChunkTypeInitAckFlagZero = errors.New("ChunkType of type INIT ACK flags must be all 0")
ErrInitAckUnmarshalFailed = errors.New("failed to unmarshal INIT body")
ErrInitCommonDataMarshalFailed = errors.New("failed marshaling INIT common data")
ErrChunkTypeInitAckInitateTagZero = errors.New("ChunkType of type INIT ACK InitiateTag must not be 0")
ErrInitAckInboundStreamRequestZero = errors.New("INIT ACK inbound stream request must be > 0")
ErrInitAckOutboundStreamRequestZero = errors.New("INIT ACK outbound stream request must be > 0")
ErrInitAckAdvertisedReceiver1500 = errors.New("INIT ACK Advertised Receiver Window Credit (a_rwnd) must be >= 1500")
)
func (i *chunkInitAck) unmarshal(raw []byte) error {
if err := i.chunkHeader.unmarshal(raw); err != nil {
return err
}
if i.typ != ctInitAck {
return fmt.Errorf("%w: actually is %s", ErrChunkTypeNotInitAck, i.typ.String())
} else if len(i.raw) < initChunkMinLength {
return fmt.Errorf("%w: %d actual: %d", ErrChunkNotLongEnoughForParams, initChunkMinLength, len(i.raw))
}
// The Chunk Flags field in INIT is reserved, and all bits in it should
// be set to 0 by the sender and ignored by the receiver. The sequence
// of parameters within an INIT can be processed in any order.
if i.flags != 0 {
return ErrChunkTypeInitAckFlagZero
}
if err := i.chunkInitCommon.unmarshal(i.raw); err != nil {
return fmt.Errorf("%w: %v", ErrInitAckUnmarshalFailed, err)
}
return nil
}
func (i *chunkInitAck) marshal() ([]byte, error) {
initShared, err := i.chunkInitCommon.marshal()
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrInitCommonDataMarshalFailed, err)
}
i.chunkHeader.typ = ctInitAck
i.chunkHeader.raw = initShared
return i.chunkHeader.marshal()
}
func (i *chunkInitAck) check() (abort bool, err error) {
// The receiver of the INIT ACK records the value of the Initiate Tag
// parameter. This value MUST be placed into the Verification Tag
// field of every SCTP packet that the INIT ACK receiver transmits
// within this association.
//
// The Initiate Tag MUST NOT take the value 0. See Section 5.3.1 for
// more on the selection of the Initiate Tag value.
//
// If the value of the Initiate Tag in a received INIT ACK chunk is
// found to be 0, the receiver MUST destroy the association
// discarding its TCB. The receiver MAY send an ABORT for debugging
// purpose.
if i.initiateTag == 0 {
abort = true
return abort, ErrChunkTypeInitAckInitateTagZero
}
// Defines the maximum number of streams the sender of this INIT ACK
// chunk allows the peer end to create in this association. The
// value 0 MUST NOT be used.
//
// Note: There is no negotiation of the actual number of streams but
// instead the two endpoints will use the min(requested, offered).
// See Section 5.1.1 for details.
//
// Note: A receiver of an INIT ACK with the MIS value set to 0 SHOULD
// destroy the association discarding its TCB.
if i.numInboundStreams == 0 {
abort = true
return abort, ErrInitAckInboundStreamRequestZero
}
// Defines the number of outbound streams the sender of this INIT ACK
// chunk wishes to create in this association. The value of 0 MUST
// NOT be used, and the value MUST NOT be greater than the MIS value
// sent in the INIT chunk.
//
// Note: A receiver of an INIT ACK with the OS value set to 0 SHOULD
// destroy the association discarding its TCB.
if i.numOutboundStreams == 0 {
abort = true
return abort, ErrInitAckOutboundStreamRequestZero
}
// An SCTP receiver MUST be able to receive a minimum of 1500 bytes in
// one SCTP packet. This means that an SCTP endpoint MUST NOT indicate
// less than 1500 bytes in its initial a_rwnd sent in the INIT or INIT
// ACK.
if i.advertisedReceiverWindowCredit < 1500 {
abort = true
return abort, ErrInitAckAdvertisedReceiver1500
}
return false, nil
}
// String makes chunkInitAck printable
func (i *chunkInitAck) String() string {
return fmt.Sprintf("%s\n%s", i.chunkHeader, i.chunkInitCommon)
}
|