/* * Copyright (c) 2017, Matias Fontanini * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include using std::vector; using std::pair; using std::string; using std::memcpy; using std::distance; using Tins::Memory::InputMemoryStream; namespace Tins { namespace Internals { namespace Converters { template T convert_to_integral(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian) { if (data_size != sizeof(T)) { throw malformed_option(); } T data = *(T*)ptr; if (endian == PDU::BE) { data = Endian::be_to_host(data); } else { data = Endian::le_to_host(data); } return data; } template vector convert_vector(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian) { if (data_size % sizeof(T) != 0) { throw malformed_option(); } InputMemoryStream input(ptr, data_size); vector output(data_size / sizeof(T)); typename vector::iterator it = output.begin(); while (input) { const T value = input.read(); if (endian == PDU::BE) { *it++ = Endian::be_to_host(value); } else { *it++ = Endian::le_to_host(value); } } return output; } template typename enable_if::value && is_unsigned_integral::value, vector > >::type convert_vector(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian) { if (data_size % (sizeof(T) + sizeof(U)) != 0) { throw malformed_option(); } InputMemoryStream input(ptr, data_size); std::vector > output; while (input) { pair data; data.first = input.read(); data.second = input.read(); if (endian == PDU::BE) { data.first = Endian::be_to_host(data.first); data.second = Endian::be_to_host(data.second); } else { data.first = Endian::le_to_host(data.first); data.second = Endian::le_to_host(data.second); } output.push_back(data); } return output; } template typename enable_if::value && is_unsigned_integral::value, std::pair >::type convert_pair(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian) { if (data_size != sizeof(T) + sizeof(U)) { throw malformed_option(); } InputMemoryStream input(ptr, data_size); pair output; output.first = input.read(); output.second = input.read(); if (endian == PDU::BE) { output.first = Endian::be_to_host(output.first); output.second = Endian::be_to_host(output.second); } else { output.first = Endian::le_to_host(output.first); output.second = Endian::le_to_host(output.second); } return output; } uint8_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type, type_to_type) { if (data_size != 1) { throw malformed_option(); } return *ptr; } int8_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type, type_to_type) { if (data_size != 1) { throw malformed_option(); } return *ptr; } uint16_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type) { return convert_to_integral(ptr, data_size, endian); } uint32_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type) { return convert_to_integral(ptr, data_size, endian); } uint64_t convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type) { return convert_to_integral(ptr, data_size, endian); } HWAddress<6> convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type, type_to_type >) { if (data_size != 6) { throw malformed_option(); } return HWAddress<6>(ptr); } IPv4Address convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type) { if (data_size != sizeof(uint32_t)) { throw malformed_option(); } InputMemoryStream input(ptr, data_size); const uint32_t ip_int = input.read(); if (endian == PDU::BE) { return IPv4Address(ip_int); } else { return IPv4Address(Endian::change_endian(ip_int)); } } IPv6Address convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type, type_to_type) { if (data_size != IPv6Address::address_size) { throw malformed_option(); } return IPv6Address(ptr); } string convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type, type_to_type) { return string(ptr, ptr + data_size); } vector convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type, type_to_type >) { vector output; const uint8_t* end = ptr + data_size; while (ptr != end) { output.push_back(float(*(ptr++) & 0x7f) / 2); } return output; } vector convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type >) { return convert_vector(ptr, data_size, endian); } vector convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type >) { return convert_vector(ptr, data_size, endian); } vector convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type >) { return convert_vector(ptr, data_size, endian); } vector convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type >) { if (data_size % 4 != 0) { throw malformed_option(); } InputMemoryStream input(ptr, data_size); vector output(data_size / sizeof(uint32_t)); vector::iterator it = output.begin(); while (input) { const uint32_t ip_int = input.read(); if (endian == PDU::BE) { *it++ = IPv4Address(ip_int); } else { *it++ = IPv4Address(Endian::change_endian(ip_int)); } } return output; } vector convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type, type_to_type >) { if (data_size % IPv6Address::address_size != 0) { throw malformed_option(); } const uint8_t* end = ptr + data_size; vector output; while (ptr < end) { output.push_back(IPv6Address(ptr)); ptr += IPv6Address::address_size; } return output; } vector > convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type > >) { return convert_vector(ptr, data_size, endian); } pair convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type >) { return convert_pair(ptr, data_size, endian); } pair convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type >) { return convert_pair(ptr, data_size, endian); } pair convert(const uint8_t* ptr, uint32_t data_size, PDU::endian_type endian, type_to_type >) { return convert_pair(ptr, data_size, endian); } } // Converters } // Internals } // Tins