diff options
Diffstat (limited to 'dhcpv6/option_vendor_opts.go')
-rw-r--r-- | dhcpv6/option_vendor_opts.go | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/dhcpv6/option_vendor_opts.go b/dhcpv6/option_vendor_opts.go new file mode 100644 index 0000000..a2281e3 --- /dev/null +++ b/dhcpv6/option_vendor_opts.go @@ -0,0 +1,117 @@ +package dhcpv6 + +/* + This module defines the OptVendorOpts structure. + https://tools.ietf.org/html/rfc3315#section-22.17 + + Option 17 + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_VENDOR_OPTS | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | enterprise-number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . option-data (sub-options) . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Sub-Option + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | opt-code | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . option-data . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +import ( + "encoding/binary" + "errors" + "fmt" +) + +// OptVendorOpts represents a DHCPv6 Status Code option +type OptVendorOpts struct { + EnterpriseNumber uint32 + VendorOpts []Option +} + +// Code returns the option code +func (op *OptVendorOpts) Code() OptionCode { + return OptionVendorOpts +} + +// ToBytes serializes the option and returns it as a sequence of bytes +func (op *OptVendorOpts) ToBytes() []byte { + buf := make([]byte, 8) + binary.BigEndian.PutUint16(buf[0:2], uint16(OptionVendorOpts)) + binary.BigEndian.PutUint16(buf[2:4], uint16(op.Length())) + binary.BigEndian.PutUint32(buf[4:8], uint32(op.EnterpriseNumber)) + for _, opt := range op.VendorOpts { + buf = append(buf, opt.ToBytes()...) + } + return buf +} + +// Length returns the option length +func (op *OptVendorOpts) Length() int { + l := 4 // 4 bytes for Enterprise Number + for _, opt := range op.VendorOpts { + l += 4 + opt.Length() // 4 bytes for Code and Length from Vendor + } + return l +} + +// String returns a string representation of the VendorOpts data +func (op *OptVendorOpts) String() string { + return fmt.Sprintf("OptVendorOpts{enterprisenum=%v, vendorOpts=%v}", + op.EnterpriseNumber, op.VendorOpts, + ) +} + +// ParseOptVendorOpts builds an OptVendorOpts structure from a sequence of bytes. +// The input data does not include option code and length bytes. +func ParseOptVendorOpts(data []byte) (*OptVendorOpts, error) { + opt := OptVendorOpts{} + if len(data) < 4 { + return nil, fmt.Errorf("Invalid vendor opts data length. Expected at least 4 bytes, got %v", len(data)) + } + opt.EnterpriseNumber = binary.BigEndian.Uint32(data[:4]) + + var err error + opt.VendorOpts, err = OptionsFromBytesWithParser(data[4:], vendParseOption) + if err != nil { + return nil, err + } + return &opt, nil +} + +// vendParseOption builds a GenericOption from a slice of bytes +// We cannot use the exisitng ParseOption function in options.go because the +// sub-options include codes specific to each vendor. There are overlaps in these +// codes with RFC standard codes. +func vendParseOption(dataStart []byte) (Option, error) { + // Parse a sequence of bytes as a single DHCPv6 option. + // Returns the option structure, or an error if any. + + if len(dataStart) < 4 { + return nil, fmt.Errorf("Invalid DHCPv6 vendor option: less than 4 bytes") + } + code := OptionCode(binary.BigEndian.Uint16(dataStart[:2])) + length := int(binary.BigEndian.Uint16(dataStart[2:4])) + if len(dataStart) < length+4 { + return nil, fmt.Errorf("Invalid option length for vendor option %v. Declared %v, actual %v", + code, length, len(dataStart)-4, + ) + } + + optData := dataStart[4 : 4+length] + if len(optData) < 1 { + return nil, errors.New("vendParseOption: at least one vendor options data is required") + } + + return &OptionGeneric{OptionCode: code, OptionData: optData}, nil +} |