summaryrefslogtreecommitdiffhomepage
path: root/dhcpv6/client.go
diff options
context:
space:
mode:
Diffstat (limited to 'dhcpv6/client.go')
-rw-r--r--dhcpv6/client.go118
1 files changed, 105 insertions, 13 deletions
diff --git a/dhcpv6/client.go b/dhcpv6/client.go
index 2f7a64f..7d53334 100644
--- a/dhcpv6/client.go
+++ b/dhcpv6/client.go
@@ -30,25 +30,26 @@ func (c *Client) Exchange(ifname string, solicit DHCPv6) ([]DHCPv6, error) {
var err error
// Solicit
- if solicit == nil {
- solicit, err = NewSolicitForInterface(ifname)
- if err != nil {
- return conversation, err
- }
- }
- conversation = append(conversation, solicit)
- advertise, err := c.Solicit(ifname, solicit)
+ solicit, advertise, err := c.Solicit(ifname, solicit)
if err != nil {
return conversation, err
}
+ conversation = append(conversation, solicit)
conversation = append(conversation, advertise)
- // TODO request/reply
+ request, reply, err := c.Request(ifname, advertise, nil)
+ if err != nil {
+ return conversation, err
+ }
+ conversation = append(conversation, request)
+ conversation = append(conversation, reply)
return conversation, nil
}
-// send a SOLICIT, return a response, or nil
-func (c *Client) Solicit(ifname string, solicit DHCPv6) (DHCPv6, error) {
+func (c *Client) sendReceive(ifname string, packet DHCPv6) (DHCPv6, error) {
+ if packet == nil {
+ return nil, fmt.Errorf("Packet to send cannot be nil")
+ }
// if no LocalAddr is specified, get the interface's link-local address
var laddr net.UDPAddr
if c.LocalAddr == nil {
@@ -93,8 +94,8 @@ func (c *Client) Solicit(ifname string, solicit DHCPv6) (DHCPv6, error) {
}
conn.SetWriteDeadline(time.Now().Add(wtimeout))
- // send the SOLICIT packet out
- _, err = conn.WriteTo(solicit.ToBytes(), &raddr)
+ // send the packet out
+ _, err = conn.WriteTo(packet.ToBytes(), &raddr)
if err != nil {
return nil, err
}
@@ -121,3 +122,94 @@ func (c *Client) Solicit(ifname string, solicit DHCPv6) (DHCPv6, error) {
}
return adv, nil
}
+
+// send a SOLICIT, return the solicit, an ADVERTISE (if not nil), and an error if
+// any
+func (c *Client) Solicit(ifname string, solicit DHCPv6) (DHCPv6, DHCPv6, error) {
+ var err error
+ if solicit == nil {
+ solicit, err = NewSolicitForInterface(ifname)
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+ advertise, err := c.sendReceive(ifname, solicit)
+ return solicit, advertise, err
+}
+
+// send a REQUEST built from an ADVERTISE if no REQUEST is specified, return a
+// the request, a reply if not nil, and an error if any
+func (c *Client) Request(ifname string, advertise, request DHCPv6) (DHCPv6, DHCPv6, error) {
+ if request == nil {
+ if advertise == nil {
+ return nil, nil, fmt.Errorf("ADVERTISE and REQUEST cannot be both nil")
+ }
+ if advertise.Type() != ADVERTISE {
+ return nil, nil, fmt.Errorf("The passed ADVERTISE must have ADVERTISE type set")
+ }
+ adv, ok := advertise.(*DHCPv6Message)
+ if !ok {
+ return nil, nil, fmt.Errorf("The passed ADVERTISE must be of DHCPv6Message type")
+ }
+ // build REQUEST from ADVERTISE
+ req := DHCPv6Message{}
+ req.SetMessage(REQUEST)
+ req.SetTransactionID(adv.TransactionID())
+ // add Client ID
+ cid := adv.GetOneOption(OPTION_CLIENTID)
+ if cid == nil {
+ return nil, nil, fmt.Errorf("Client ID cannot be nil in ADVERTISE when building REQUEST")
+ }
+ req.AddOption(cid)
+ // add Server ID
+ sid := adv.GetOneOption(OPTION_SERVERID)
+ if sid == nil {
+ return nil, nil, fmt.Errorf("Server ID cannot be nil in ADVERTISE when building REQUEST")
+ }
+ req.AddOption(sid)
+ // add Elapsed Time
+ req.AddOption(&OptElapsedTime{})
+ // add IA_NA
+ iaNa := adv.GetOneOption(OPTION_IA_NA)
+ if iaNa == nil {
+ return nil, nil, fmt.Errorf("IA_NA cannot be nil in ADVERTISE when building REQUEST")
+ }
+ req.AddOption(iaNa)
+ // add OptRequestedOption
+ oro := OptRequestedOption{}
+ oro.SetRequestedOptions([]OptionCode{
+ OPT_BOOTFILE_URL,
+ OPT_BOOTFILE_PARAM,
+ })
+ req.AddOption(&oro)
+ // add OPTION_NII
+ // TODO implement OptionNetworkInterfaceIdentifier
+ nii := OptionGeneric{
+ OptionCode: OPTION_NII,
+ OptionData: []byte{
+ 1, // UNDI - Universal Network Device Interface
+ 3, 2, // UNDI rev. 3.2 - second generation EFI runtime driver support, see rfc4578
+ },
+ }
+ req.AddOption(&nii)
+ // add OPTION_CLIENT_ARCH_TYPE
+ // TODO implement OptionClientArchType
+ cat := OptionGeneric{
+ OptionCode: OPTION_CLIENT_ARCH_TYPE,
+ OptionData: []byte{
+ 0, // Intel - see rfc4578
+ 7, // EFI BC
+ },
+ }
+ req.AddOption(&cat)
+ // add OPTION_VENDOR_CLASS, only if present in the original request
+ // TODO implement OptionVendorClass
+ vClass := adv.GetOneOption(OPTION_VENDOR_CLASS)
+ if vClass != nil {
+ req.AddOption(vClass)
+ }
+ request = &req
+ }
+ reply, err := c.sendReceive(ifname, request)
+ return request, reply, err
+}