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
|
package dhcpv6
import (
"fmt"
)
type DHCPv6 interface {
Type() MessageType
ToBytes() []byte
Options() []Option
String() string
Summary() string
Length() int
IsRelay() bool
GetOption(code OptionCode) []Option
GetOneOption(code OptionCode) Option
}
func FromBytes(data []byte) (DHCPv6, error) {
var (
isRelay = false
headerSize int
messageType = MessageType(data[0])
)
if messageType == RELAY_FORW || messageType == RELAY_REPL {
isRelay = true
}
if isRelay {
headerSize = RelayHeaderSize
} else {
headerSize = MessageHeaderSize
}
if len(data) < headerSize {
return nil, fmt.Errorf("Invalid header size: shorter than %v bytes", headerSize)
}
if isRelay {
var (
linkAddr, peerAddr []byte
)
d := DHCPv6Relay{
messageType: messageType,
hopCount: uint8(data[1]),
}
linkAddr = append(linkAddr, data[2:18]...)
d.linkAddr = linkAddr
peerAddr = append(peerAddr, data[18:34]...)
d.peerAddr = peerAddr
options, err := OptionsFromBytes(data[34:])
if err != nil {
return nil, err
}
// TODO fail if no OptRelayMessage is present
d.options = options
return &d, nil
} else {
tid, err := BytesToTransactionID(data[1:4])
if err != nil {
return nil, err
}
d := DHCPv6Message{
messageType: messageType,
transactionID: *tid,
}
options, err := OptionsFromBytes(data[4:])
if err != nil {
return nil, err
}
d.options = options
return &d, nil
}
}
func NewMessage() (*DHCPv6Message, error) {
tid, err := GenerateTransactionID()
if err != nil {
return nil, err
}
d := DHCPv6Message{
messageType: SOLICIT,
transactionID: *tid,
}
return &d, nil
}
func getOptions(options []Option, code OptionCode, onlyFirst bool) []Option {
var ret []Option
for _, opt := range options {
if opt.Code() == code {
ret = append(ret, opt)
if onlyFirst {
break
}
}
}
return ret
}
func getOption(options []Option, code OptionCode) Option {
opts := getOptions(options, code, true)
if opts == nil {
return nil
}
return opts[0]
}
|