1package dtls
2
3import "encoding/binary"
4
5type recordLayerHeader struct {
6	contentType     contentType
7	contentLen      uint16
8	protocolVersion protocolVersion
9	epoch           uint16
10	sequenceNumber  uint64 // uint48 in spec
11
12}
13
14const (
15	recordLayerHeaderSize = 13
16	maxSequenceNumber     = 0x0000FFFFFFFFFFFF
17
18	dtls1_2Major = 0xfe
19	dtls1_2Minor = 0xfd
20)
21
22var protocolVersion1_2 = protocolVersion{dtls1_2Major, dtls1_2Minor}
23
24// https://tools.ietf.org/html/rfc4346#section-6.2.1
25type protocolVersion struct {
26	major, minor uint8
27}
28
29func (r *recordLayerHeader) Marshal() ([]byte, error) {
30	if r.sequenceNumber > maxSequenceNumber {
31		return nil, errSequenceNumberOverflow
32	}
33
34	out := make([]byte, recordLayerHeaderSize)
35	out[0] = byte(r.contentType)
36	out[1] = r.protocolVersion.major
37	out[2] = r.protocolVersion.minor
38	binary.BigEndian.PutUint16(out[3:], r.epoch)
39	putBigEndianUint48(out[5:], r.sequenceNumber)
40	binary.BigEndian.PutUint16(out[recordLayerHeaderSize-2:], r.contentLen)
41	return out, nil
42}
43
44func (r *recordLayerHeader) Unmarshal(data []byte) error {
45	if len(data) < recordLayerHeaderSize {
46		return errBufferTooSmall
47	}
48	r.contentType = contentType(data[0])
49	r.protocolVersion.major = data[1]
50	r.protocolVersion.minor = data[2]
51	r.epoch = binary.BigEndian.Uint16(data[3:])
52
53	// SequenceNumber is stored as uint48, make into uint64
54	seqCopy := make([]byte, 8)
55	copy(seqCopy[2:], data[5:11])
56	r.sequenceNumber = binary.BigEndian.Uint64(seqCopy)
57
58	return nil
59}
60