コード例 #1
1
ファイル: pppoe.cpp プロジェクト: rklabs/libtins
PPPoE::PPPoE(const uint8_t* buffer, uint32_t total_sz)
    : tags_size_() {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    stream.size(std::min(stream.size(), (size_t)payload_length()));
    // If this is a session data packet
    if (code() == 0) {
        if (stream) {
            inner_pdu(
                new RawPDU(stream.pointer(), stream.size())
            );
        }
    }
    else {
        while (stream) {
            TagTypes opt_type = static_cast<TagTypes>(stream.read<uint16_t>());
            uint16_t opt_len = stream.read_be<uint16_t>();
            if (!stream.can_read(opt_len)) {
                throw malformed_packet();
            }
            add_tag(tag(opt_type, opt_len, stream.pointer()));
            stream.skip(opt_len);
        }
    }
}
コード例 #2
0
ファイル: ethernetII.cpp プロジェクト: Temptationx/libtins
uint32_t EthernetII::trailer_size() const {
    int32_t padding = 60 - sizeof(ethhdr); // EthernetII min size is 60, padding is sometimes needed
    if (inner_pdu()) {
        padding -= inner_pdu()->size();
        padding = std::max(0, padding);
    }
    return padding;
}
コード例 #3
0
ファイル: ipsec.cpp プロジェクト: asjadsyed/libtins
void IPSecAH::write_serialization(uint8_t* buffer, uint32_t total_sz) {
    if (inner_pdu()) {
        next_header(Internals::pdu_flag_to_ip_type(inner_pdu()->pdu_type()));
    }
    length(header_size() / sizeof(uint32_t) - 2);
    OutputMemoryStream output(buffer, total_sz);
    output.write(header_);
    output.write(icv_.begin(), icv_.end());
}
コード例 #4
0
ファイル: dot1q.cpp プロジェクト: Iaroslav464/libtins
uint32_t Dot1Q::trailer_size() const {
    if(_append_padding) {
        uint32_t total_size = sizeof(_header);
        if(inner_pdu())
            total_size += inner_pdu()->size();
        return (total_size > 50) ? 0 : (50 - total_size);
    }
    else
        return 0;
}
コード例 #5
0
ファイル: radiotap.cpp プロジェクト: heavyair/testjni
bool RadioTap::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
    if(sizeof(_radio) < total_sz)
        return false;
    const radiotap_hdr *radio_ptr = (const radiotap_hdr*)ptr;
    if(radio_ptr->it_len <= total_sz) {
        ptr += radio_ptr->it_len;
        total_sz -= radio_ptr->it_len;
        return inner_pdu() ? inner_pdu()->matches_response(ptr, total_sz) : true;
    }
    return false;
}
コード例 #6
0
ファイル: dot1q.cpp プロジェクト: Iaroslav464/libtins
bool Dot1Q::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
    if(total_sz < sizeof(_header))
        return false;
    const dot1q_hdr *dot1q_ptr = (const dot1q_hdr*)ptr;
    if(get_id(dot1q_ptr) == get_id(&_header)) {
        ptr += sizeof(_header);
        total_sz -= sizeof(_header);
        return inner_pdu() ? inner_pdu()->matches_response(ptr, total_sz) : true;
    }
    return false;
    
}
コード例 #7
0
ファイル: ethernetII.cpp プロジェクト: Temptationx/libtins
bool EthernetII::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
    if(total_sz < sizeof(ethhdr))
        return false;
    const size_t addr_sz = address_type::address_size;
    const ethhdr *eth_ptr = (const ethhdr*)ptr;
    if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac)) {
        if(std::equal(_eth.src_mac, _eth.src_mac + addr_sz, eth_ptr->dst_mac) || !dst_addr().is_unicast())
        {
            return (inner_pdu()) ? inner_pdu()->matches_response(ptr + sizeof(_eth), total_sz - sizeof(_eth)) : true;
        }
    }
    return false;
}
コード例 #8
0
ファイル: snap.cpp プロジェクト: DaTrollMon/libtins
void Tins::SNAP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
    #ifdef TINS_DEBUG
    assert(total_sz >= sizeof(_snap));
    #endif
    if (inner_pdu()) {
        Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
            inner_pdu()->pdu_type()
        );
        _snap.eth_type = Endian::host_to_be(
            static_cast<uint16_t>(flag)
        );
    }
    std::memcpy(buffer, &_snap, sizeof(_snap));
}
コード例 #9
0
ファイル: dot11_data.cpp プロジェクト: jedahan/libtins
Dot11Data::Dot11Data(const uint8_t *buffer, uint32_t total_sz) 
: Dot11(buffer, total_sz)
{
    const uint32_t offset = init(buffer, total_sz);
    buffer += offset;
    total_sz -= offset;
    if(total_sz) {
        // If the wep bit is on, then just use a RawPDU
        if(wep())
            inner_pdu(new Tins::RawPDU(buffer, total_sz));
        else
            inner_pdu(new Tins::SNAP(buffer, total_sz));
    }
}
コード例 #10
0
ファイル: ipsec.cpp プロジェクト: asjadsyed/libtins
IPSecESP::IPSecESP(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    if (stream) {
        inner_pdu(new RawPDU(stream.pointer(), stream.size()));
    }
}
コード例 #11
0
ファイル: radiotap.cpp プロジェクト: heavyair/testjni
void RadioTap::send(PacketSender &sender, const NetworkInterface &iface) {
    if(!iface)
        throw invalid_interface();

#if !defined(BSD) && !defined(__FreeBSD_kernel__)
    struct sockaddr_ll addr;

    memset(&addr, 0, sizeof(struct sockaddr_ll));

    addr.sll_family = Endian::host_to_be<uint16_t>(PF_PACKET);
    addr.sll_protocol = Endian::host_to_be<uint16_t>(ETH_P_ALL);
    addr.sll_halen = 6;
    addr.sll_ifindex = iface.id();

    const Tins::Dot11 *wlan = tins_cast<Tins::Dot11*>(inner_pdu());
    if(wlan) {
        Tins::Dot11::address_type dot11_addr(wlan->addr1());
        std::copy(dot11_addr.begin(), dot11_addr.end(), addr.sll_addr);
    }

    sender.send_l2(*this, (struct sockaddr*)&addr, (uint32_t)sizeof(addr));
#else
    sender.send_l2(*this, 0, 0, iface);
#endif
}
コード例 #12
0
ファイル: ppi.cpp プロジェクト: gtdsj/libtins
PPI::PPI(const uint8_t *buffer, uint32_t total_sz) {
    if(total_sz < sizeof(_header))
        throw malformed_packet();
    std::memcpy(&_header, buffer, sizeof(_header));
    if(length() > total_sz || length() < sizeof(_header))
        throw malformed_packet();
    buffer += sizeof(_header);
    total_sz -= sizeof(_header);
    // There are some options
    const size_t options_length = length() - sizeof(_header);
    if(options_length > 0) {
        _data.assign(buffer, buffer + options_length);
        buffer += options_length;
        total_sz -= static_cast<uint32_t>(options_length);
    }
    if(total_sz > 0) {
        switch(dlt()) {
            case DLT_IEEE802_11:
                #ifdef HAVE_DOT11
                    parse_80211(buffer, total_sz);
                #else
                    throw protocol_disabled();
                #endif
                break;
            case DLT_EN10MB:
                if(Internals::is_dot3(buffer, total_sz))
                    inner_pdu(new Dot3(buffer, total_sz));
                else
                    inner_pdu(new EthernetII(buffer, total_sz));
                break;
            case DLT_IEEE802_11_RADIO:
                #ifdef HAVE_DOT11
                    inner_pdu(new RadioTap(buffer, total_sz));
                #else
                    throw protocol_disabled();
                #endif
                break;
            case DLT_NULL:
                inner_pdu(new Loopback(buffer, total_sz));
                break;
            case DLT_LINUX_SLL:
                inner_pdu(new Tins::SLL(buffer, total_sz));
                break;
        }
    }
}
コード例 #13
0
ファイル: dot1q.cpp プロジェクト: Iaroslav464/libtins
void Dot1Q::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
    uint32_t trailer = trailer_size();
    #ifdef TINS_DEBUG
    assert(total_sz >= sizeof(_header) + trailer);
    #endif
    if ((payload_type() == 0) && inner_pdu()) {
        Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
            inner_pdu()->pdu_type()
        );
        payload_type(static_cast<uint16_t>(flag));
    }
    std::memcpy(buffer, &_header, sizeof(_header));
    
    buffer += sizeof(_header);
    if(inner_pdu())
        buffer += inner_pdu()->size();
    std::fill(buffer, buffer + trailer, 0);
}
コード例 #14
0
ファイル: arp.cpp プロジェクト: Iaroslav464/libtins
ARP::ARP(const uint8_t *buffer, uint32_t total_sz) 
{
    if(total_sz < sizeof(arphdr))
        throw malformed_packet();
    memcpy(&_arp, buffer, sizeof(arphdr));
    total_sz -= sizeof(arphdr);
    //TODO: Check whether this should be removed or not.
    if(total_sz)
        inner_pdu(new RawPDU(buffer + sizeof(arphdr), total_sz));
}
コード例 #15
0
ファイル: dot11_data.cpp プロジェクト: jedahan/libtins
Dot11QoSData::Dot11QoSData(const uint8_t *buffer, uint32_t total_sz) 
// Am I breaking something? :S
: Dot11Data(buffer, total_sz, no_inner_pdu()) {
    uint32_t sz = data_frame_size();
    buffer += sz;
    total_sz -= sz;
    if(total_sz < sizeof(_qos_control))
        throw malformed_packet();
    _qos_control = *(uint16_t*)buffer;
    total_sz -= sizeof(uint16_t);
    buffer += sizeof(uint16_t);
    if(total_sz) {
        // If the wep bit is on, then just use a RawPDU
        if(wep())
            inner_pdu(new Tins::RawPDU(buffer, total_sz));
        else
            inner_pdu(new Tins::SNAP(buffer, total_sz));
    }
}
コード例 #16
0
ファイル: eapol.cpp プロジェクト: CityOfSolitude/libtins
RSNEAPOL::RSNEAPOL(const uint8_t* buffer, uint32_t total_sz) 
: EAPOL(buffer, total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.skip(sizeof(eapol_header));
    stream.read(header_);
    if (stream.size() >= wpa_length()) {
        stream.read(key_, wpa_length());
        if (stream) {
            inner_pdu(new RawPDU(stream.pointer(), stream.size()));
        }
    }
}
コード例 #17
0
ファイル: ethernetII.cpp プロジェクト: Temptationx/libtins
void EthernetII::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
    #ifdef TINS_DEBUG
    assert(total_sz >= header_size() + trailer_size());
    #endif

    /* Inner type defaults to IP */
    if (inner_pdu()) {
        Constants::Ethernet::e flag = Internals::pdu_flag_to_ether_type(
            inner_pdu()->pdu_type()
        );
        payload_type(static_cast<uint16_t>(flag));
    }
    memcpy(buffer, &_eth, sizeof(ethhdr));
    uint32_t trailer = trailer_size();
    if (trailer) {
        uint32_t trailer_offset = header_size();
        if (inner_pdu())
            trailer_offset += inner_pdu()->size();
        memset(buffer + trailer_offset, 0, trailer);
    }

}
コード例 #18
0
ファイル: ppi.cpp プロジェクト: gtdsj/libtins
void PPI::parse_80211(const uint8_t* buffer, uint32_t total_sz) {
    #ifdef HAVE_DOT11
    if (_data.size() >= 13) {
        // Is FCS-at-end on?
        if ((_data[12] & 1) == 1) {
            // We need to reduce the total size since we're skipping the FCS
            if (total_sz < sizeof(uint32_t)) {
                throw malformed_packet();
            }
            total_sz -= sizeof(uint32_t);
        }
    }
    inner_pdu(Dot11::from_bytes(buffer, total_sz));
    #endif // HAVE_DOT11
}
コード例 #19
0
ファイル: snap.cpp プロジェクト: DaTrollMon/libtins
Tins::SNAP::SNAP(const uint8_t *buffer, uint32_t total_sz) 
{
    if(total_sz < sizeof(_snap))
        throw malformed_packet();
    std::memcpy(&_snap, buffer, sizeof(_snap));
    buffer += sizeof(_snap);
    total_sz -= sizeof(_snap);
    if(total_sz) {
        inner_pdu(
            Internals::pdu_from_flag(
                (Constants::Ethernet::e)eth_type(), 
                buffer, 
                total_sz
            )
        );
    }
}
コード例 #20
0
ファイル: pktap.cpp プロジェクト: CityOfSolitude/libtins
PKTAP::PKTAP(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    uint32_t header_length = header_.length;
    if (header_length > total_sz || header_length < sizeof(header_)) {
        throw malformed_packet();
    }
    stream.skip(header_length - sizeof(header_));
    if (header_.next && stream) {
        inner_pdu(
            Internals::pdu_from_dlt_flag(
                header_.dlt, 
                stream.pointer(), 
                stream.size()
            )
        );
    }
}
コード例 #21
0
ファイル: ethernetII.cpp プロジェクト: Temptationx/libtins
EthernetII::EthernetII(const uint8_t *buffer, uint32_t total_sz) 
{
    if(total_sz < sizeof(ethhdr))
        throw malformed_packet();
    memcpy(&_eth, buffer, sizeof(ethhdr));
    buffer += sizeof(ethhdr);
    total_sz -= sizeof(ethhdr);
    if(total_sz) {
        inner_pdu(
            Internals::pdu_from_flag(
                (Constants::Ethernet::e)payload_type(), 
                buffer, 
                total_sz
            )
        );
    }

}
コード例 #22
0
ファイル: pktap.cpp プロジェクト: gtdsj/libtins
PKTAP::PKTAP(const uint8_t* buffer, uint32_t total_sz) {
    if (total_sz < sizeof(pktap_header)) {
        throw malformed_packet();
    }
    memcpy(&header_, buffer, sizeof(header_));
    uint32_t header_length = header_.length;
    if (header_length > total_sz) {
        throw malformed_packet();
    }
    buffer += header_length;
    total_sz -= header_length;
    if (header_.next && total_sz > 0) {
        inner_pdu(
            Internals::pdu_from_dlt_flag(
                header_.dlt, 
                buffer, 
                total_sz
            )
        );
    }
}
コード例 #23
0
ファイル: ipsec.cpp プロジェクト: asjadsyed/libtins
IPSecAH::IPSecAH(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    const uint32_t ah_len = 4 * (static_cast<uint16_t>(length()) + 2);
    if (ah_len < sizeof(header_)) {
        throw malformed_packet();
    }
    const uint32_t icv_length = ah_len - sizeof(header_);
    if (!stream.can_read(icv_length)) {
        throw malformed_packet();
    }
    stream.read(icv_, icv_length);
    if (stream) {
        inner_pdu(
            Internals::pdu_from_flag(
                static_cast<Constants::IP::e>(next_header()),
                stream.pointer(), 
                stream.size(), 
                true
            )
        );
    }
}
コード例 #24
0
ファイル: icmpv6.cpp プロジェクト: JeanJoskin/libtins
ICMPv6::ICMPv6(const uint8_t *buffer, uint32_t total_sz) 
: _options_size(), reach_time(0), retrans_timer(0)
{
    if(total_sz < sizeof(_header))
        throw malformed_packet();
    std::memcpy(&_header, buffer, sizeof(_header));
    buffer += sizeof(_header);
    total_sz -= sizeof(_header);
    if(has_target_addr()) {
        if(total_sz < ipaddress_type::address_size)
            throw malformed_packet();
        target_addr(buffer);
        buffer += ipaddress_type::address_size;
        total_sz -= ipaddress_type::address_size;
    }
    if(has_dest_addr()) {
        if(total_sz < ipaddress_type::address_size)
            throw malformed_packet();
        dest_addr(buffer);
        buffer += ipaddress_type::address_size;
        total_sz -= ipaddress_type::address_size;
    }
    if(type() == ROUTER_ADVERT) {
        if(total_sz < sizeof(uint32_t) * 2)
            throw malformed_packet();
        const uint32_t *ptr_32 = (const uint32_t*)buffer;
        reach_time = *ptr_32++;
        retrans_timer = *ptr_32++;
        
        buffer += sizeof(uint32_t) * 2;
        total_sz -= sizeof(uint32_t) * 2;
    }
    if(has_options())
        parse_options(buffer, total_sz);
    if(total_sz > 0)
        inner_pdu(new RawPDU(buffer, total_sz));
}
コード例 #25
0
ファイル: radiotap.cpp プロジェクト: heavyair/testjni
void RadioTap::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
    uint32_t sz = header_size();
    uint8_t *buffer_start = buffer;
#ifdef TINS_DEBUG
    assert(total_sz >= sz);
#endif
    _radio.it_len = Endian::host_to_le<uint16_t>(sz);
    memcpy(buffer, &_radio, sizeof(_radio));
    buffer += sizeof(_radio);
    if(_radio.flags.tsft) {
        memcpy(buffer, &_tsft, sizeof(_tsft));
        buffer += sizeof(_tsft);
    }
    if(_radio.flags.flags) {
        memcpy(buffer, &_flags, sizeof(_flags));
        buffer += sizeof(_flags);
    }
    if(_radio.flags.rate) {
        memcpy(buffer, &_rate, sizeof(_rate));
        buffer += sizeof(_rate);
    }
    if(_radio.flags.channel) {
        if(((buffer - buffer_start) & 1) == 1)
            *(buffer++) = 0;
        memcpy(buffer, &_channel_freq, sizeof(_channel_freq));
        buffer += sizeof(_channel_freq);
        memcpy(buffer, &_channel_type, sizeof(_channel_type));
        buffer += sizeof(_channel_type);
    }
    if(_radio.flags.dbm_signal) {
        memcpy(buffer, &_dbm_signal, sizeof(_dbm_signal));
        buffer += sizeof(_dbm_signal);
    }
    if(_radio.flags.dbm_noise) {
        memcpy(buffer, &_dbm_noise, sizeof(_dbm_noise));
        buffer += sizeof(_dbm_noise);
    }
    if(_radio.flags.lock_quality) {
        if(((buffer - buffer_start) & 1) == 1)
            *(buffer++) = 0;
        memcpy(buffer, &_signal_quality, sizeof(_signal_quality));
        buffer += sizeof(_signal_quality);
    }
    if(_radio.flags.antenna) {
        memcpy(buffer, &_antenna, sizeof(_antenna));
        buffer += sizeof(_antenna);
    }
    if(_radio.flags.db_signal) {
        memcpy(buffer, &_db_signal, sizeof(_db_signal));
        buffer += sizeof(_db_signal);
    }
    if(_radio.flags.rx_flags) {
        if(((buffer - buffer_start) & 1) == 1)
            *(buffer++) = 0;
        memcpy(buffer, &_rx_flags, sizeof(_rx_flags));
        buffer += sizeof(_rx_flags);
    }
    if(_radio.flags.channel_plus) {
        uint32_t offset = ((buffer - buffer_start) % 4);
        if(offset) {
            offset = 4 - offset;
            while(offset--) {
                *buffer++ = 0;
            }
        }
        uint32_t dummy = _channel_type;
        // nasty Big Endian fix
        dummy = Endian::le_to_host<uint32_t>(Endian::host_to_le<uint16_t>(dummy));
        memcpy(buffer, &dummy, sizeof(dummy));
        buffer += sizeof(dummy);
        memcpy(buffer, &_channel_freq, sizeof(_channel_freq));
        buffer += sizeof(_channel_freq);
        memcpy(buffer, &_channel, sizeof(_channel));
        buffer += sizeof(_channel);
        memcpy(buffer, &_max_power, sizeof(_max_power));
        buffer += sizeof(_max_power);
    }
    if((_flags & 0x10) != 0 && inner_pdu()) {
        uint32_t crc32 = Endian::host_to_le(
                             Utils::crc32(buffer, inner_pdu()->size())
                         );
        memcpy(buffer + inner_pdu()->size(), &crc32, sizeof(uint32_t));
    }
}
コード例 #26
0
ファイル: pdu.cpp プロジェクト: Imva/libtins
void PDU::copy_inner_pdu(const PDU &pdu) {
    if(pdu.inner_pdu())
        inner_pdu(pdu.inner_pdu()->clone());
}
コード例 #27
0
ファイル: pdu.cpp プロジェクト: Imva/libtins
void PDU::inner_pdu(const PDU &next_pdu) {
    inner_pdu(next_pdu.clone());
}
コード例 #28
0
ファイル: radiotap.cpp プロジェクト: bt/libtins
RadioTap::RadioTap(const uint8_t *buffer, uint32_t total_sz)
{
    check_size(total_sz, sizeof(_radio));
    const uint8_t *buffer_start = buffer;
    std::memcpy(&_radio, buffer, sizeof(_radio));
    uint32_t radiotap_hdr_size = length();
    check_size(total_sz, radiotap_hdr_size);
    buffer += sizeof(_radio);
    radiotap_hdr_size -= sizeof(_radio);

    if(_radio.flags.tsft)
        read_field(buffer, radiotap_hdr_size, _tsft);

    if(_radio.flags.flags)
        read_field(buffer, radiotap_hdr_size, _flags);

    if(_radio.flags.rate)
        read_field(buffer, radiotap_hdr_size, _rate);

    if(_radio.flags.channel) {
        if(((buffer - buffer_start) & 1) == 1) {
            buffer++;
            radiotap_hdr_size--;
        }
        read_field(buffer, radiotap_hdr_size, _channel_freq);
        read_field(buffer, radiotap_hdr_size, _channel_type);
    }

    if(_radio.flags.dbm_signal)
        read_field(buffer, radiotap_hdr_size, _dbm_signal);

    if(_radio.flags.dbm_noise)
        read_field(buffer, radiotap_hdr_size, _dbm_noise);

    if(_radio.flags.lock_quality)
        read_field(buffer, radiotap_hdr_size, _signal_quality);

    if(_radio.flags.antenna)
        read_field(buffer, radiotap_hdr_size, _antenna);

    if(_radio.flags.db_signal)
        read_field(buffer, radiotap_hdr_size, _db_signal);

    if(_radio.flags.rx_flags) {
        if(((buffer - buffer_start) & 1) == 1) {
            buffer++;
            radiotap_hdr_size--;
        }
        read_field(buffer, radiotap_hdr_size, _rx_flags);
    }
    if(_radio.flags.channel_plus) {
        uint32_t offset = ((buffer - buffer_start) % 4);
        if(offset) {
            offset = 4 - offset;
            buffer += offset;
            radiotap_hdr_size -= offset;
        }
        uint32_t dummy;
        read_field(buffer, radiotap_hdr_size, dummy);
        // nasty Big Endian fix
        _channel_type = Endian::le_to_host<uint16_t>(Endian::host_to_le<uint32_t>(dummy));
        read_field(buffer, radiotap_hdr_size, _channel_freq);
        read_field(buffer, radiotap_hdr_size, _channel);
        read_field(buffer, radiotap_hdr_size, _max_power);
    }

    total_sz -= length();
    buffer += radiotap_hdr_size;

    if(_radio.flags.flags && (flags() & FCS) != 0) {
        check_size(total_sz, sizeof(uint32_t));
        total_sz -= sizeof(uint32_t);
        if((flags() & FAILED_FCS) !=0)
            throw malformed_packet();
    }

    if(total_sz)
        inner_pdu(Dot11::from_bytes(buffer, total_sz));
}
コード例 #29
0
ファイル: radiotap.cpp プロジェクト: heavyair/testjni
RadioTap::RadioTap(const uint8_t *buffer, uint32_t total_sz)
{
    check_size(total_sz, sizeof(_radio));
    const uint8_t *buffer_start = buffer;
    std::memcpy(&_radio, buffer, sizeof(_radio));
    uint32_t radiotap_hdr_size = length();
    check_size(total_sz, radiotap_hdr_size);
    // We start on the first flags field, skipping version, pad and length.
    const flags_type* current_flags = (const flags_type*)(buffer + sizeof(uint32_t));
    const uint32_t extra_flags_size = find_extra_flag_fields_size(
                                          buffer + sizeof(uint32_t), total_sz);
    // Find and skip the extra flag fields.
    buffer += extra_flags_size;
    radiotap_hdr_size -= extra_flags_size;
    // Also skip the header
    buffer += sizeof(_radio);
    radiotap_hdr_size -= sizeof(_radio);

    while(true) {
        _radio.flags_32 |= *(const uint32_t*)current_flags;
        if(current_flags->tsft)
            read_field(buffer, radiotap_hdr_size, _tsft);

        if(current_flags->flags)
            read_field(buffer, radiotap_hdr_size, _flags);

        if(current_flags->rate)
            read_field(buffer, radiotap_hdr_size, _rate);

        if(current_flags->channel) {
            if(((buffer - buffer_start) & 1) == 1) {
                buffer++;
                radiotap_hdr_size--;
            }
            read_field(buffer, radiotap_hdr_size, _channel_freq);
            read_field(buffer, radiotap_hdr_size, _channel_type);
        }

        if(current_flags->dbm_signal)
            read_field(buffer, radiotap_hdr_size, _dbm_signal);

        if(current_flags->dbm_noise)
            read_field(buffer, radiotap_hdr_size, _dbm_noise);

        if(current_flags->lock_quality)
            read_field(buffer, radiotap_hdr_size, _signal_quality);

        if(current_flags->antenna)
            read_field(buffer, radiotap_hdr_size, _antenna);

        if(current_flags->db_signal)
            read_field(buffer, radiotap_hdr_size, _db_signal);

        if(current_flags->rx_flags) {
            if(((buffer - buffer_start) & 1) == 1) {
                buffer++;
                radiotap_hdr_size--;
            }
            read_field(buffer, radiotap_hdr_size, _rx_flags);
        }
        if(current_flags->channel_plus) {
            uint32_t offset = ((buffer - buffer_start) % 4);
            if(offset) {
                offset = 4 - offset;
                buffer += offset;
                radiotap_hdr_size -= offset;
            }
            uint32_t dummy;
            read_field(buffer, radiotap_hdr_size, dummy);
            // nasty Big Endian fix
            _channel_type = Endian::le_to_host<uint16_t>(Endian::host_to_le<uint32_t>(dummy));
            read_field(buffer, radiotap_hdr_size, _channel_freq);
            read_field(buffer, radiotap_hdr_size, _channel);
            read_field(buffer, radiotap_hdr_size, _max_power);
        }
        // We can do this safely because we checked the size on find_extra_flags...
        if(current_flags->ext == 1) {
            current_flags++;
        }
        else {
            break;
        }
    }

    total_sz -= length();
    buffer += radiotap_hdr_size;

    if(_radio.flags.flags && (flags() & FCS) != 0) {
        check_size(total_sz, sizeof(uint32_t));
        total_sz -= sizeof(uint32_t);
        if((flags() & FAILED_FCS) !=0)
            throw malformed_packet();
    }

    if(total_sz)
        inner_pdu(Dot11::from_bytes(buffer, total_sz));
}