void DHCPv6::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { const uint32_t required_size = is_relay_message() ? 2 : 4; buffer = std::copy(header_data, header_data + required_size, buffer); if(is_relay_message()) { buffer = link_addr.copy(buffer); buffer = peer_addr.copy(buffer); } for(options_type::const_iterator it = options_.begin(); it != options_.end(); ++it) buffer = write_option(*it, buffer); }
bool DHCPv6::matches_response(const uint8_t *ptr, uint32_t total_sz) const { if(!is_relay_message()) { if(total_sz < 4 || (ptr[0] == 12 || ptr[0] == 13)) return false; return std::equal(header_data + 1, header_data + 4, ptr + 1); } return false; }
DHCPv6::DHCPv6(const uint8_t *buffer, uint32_t total_sz) : options_size() { if(total_sz == 0) throw malformed_packet(); // Relay Agent/Server Messages bool is_relay_msg = (buffer[0] == 12 || buffer[0] == 13); uint32_t required_size = is_relay_msg ? 2 : 4; if(total_sz < required_size) throw malformed_packet(); std::copy(buffer, buffer + required_size, header_data); buffer += required_size; total_sz -= required_size; if(is_relay_message()) { if(total_sz < ipaddress_type::address_size * 2) throw malformed_packet(); link_addr = buffer; peer_addr = buffer + ipaddress_type::address_size; buffer += ipaddress_type::address_size * 2; total_sz -= ipaddress_type::address_size * 2; } options_size = total_sz; while(total_sz) { if(total_sz < sizeof(uint16_t) * 2) throw malformed_packet(); uint16_t opt; std::memcpy(&opt, buffer, sizeof(uint16_t)); opt = Endian::be_to_host(opt); uint16_t data_size; std::memcpy(&data_size, buffer + sizeof(uint16_t), sizeof(uint16_t)); data_size = Endian::be_to_host(data_size); if(total_sz - sizeof(uint16_t) * 2 < data_size) throw malformed_packet(); buffer += sizeof(uint16_t) * 2; add_option( option(opt, buffer, buffer + data_size) ); buffer += data_size; total_sz -= sizeof(uint16_t) * 2 + data_size; } }
uint32_t DHCPv6::header_size() const { return (is_relay_message() ? (2 + ipaddress_type::address_size * 2) : 4) + options_size; }