/* * Copyright (C) 2013 Bastian Bloessl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "utils.h" #if defined(__APPLE__) #include #define htole16(x) OSSwapHostToLittleInt16(x) #else #include #endif #include #include #include using namespace gr::ieee802_11; class ofdm_mac_impl : public ofdm_mac { public: ofdm_mac_impl(std::vector src_mac, std::vector dst_mac, std::vector bss_mac, bool strip_header) : block("ofdm_mac", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), d_seq_nr(0), d_strip_header(strip_header) { message_port_register_out(pmt::mp("phy out")); message_port_register_out(pmt::mp("app out")); message_port_register_in(pmt::mp("app in")); set_msg_handler(pmt::mp("app in"), boost::bind(&ofdm_mac_impl::app_in, this, _1)); message_port_register_in(pmt::mp("phy in")); set_msg_handler(pmt::mp("phy in"), boost::bind(&ofdm_mac_impl::phy_in, this, _1)); if(!check_mac(src_mac)) throw std::invalid_argument("wrong mac address size"); if(!check_mac(dst_mac)) throw std::invalid_argument("wrong mac address size"); if(!check_mac(bss_mac)) throw std::invalid_argument("wrong mac address size"); for(int i = 0; i < 6; i++) { d_src_mac[i] = src_mac[i]; d_dst_mac[i] = dst_mac[i]; d_bss_mac[i] = bss_mac[i]; } } void phy_in (pmt::pmt_t msg) { if (d_strip_header) { // this must be a pair if (!pmt::is_blob(pmt::cdr(msg))) throw std::runtime_error("PMT must be blob"); // strip MAC header and only leave PHY blob pmt::pmt_t blob(pmt::cdr(msg)); const char *mpdu = reinterpret_cast(pmt::blob_data(blob)); pmt::pmt_t msdu = pmt::make_blob(mpdu + 24, pmt::blob_length(blob) - 24); // update original msg, note that the fcs is still there pmt::set_cdr(msg, msdu); } message_port_pub(pmt::mp("app out"), msg); } void app_in (pmt::pmt_t msg) { size_t msg_len; const char *msdu; if(pmt::is_eof_object(msg)) { message_port_pub(pmt::mp("phy out"), pmt::PMT_EOF); detail().get()->set_done(true); return; } else if(pmt::is_symbol(msg)) { std::string str; str = pmt::symbol_to_string(msg); msg_len = str.length(); msdu = str.data(); } else if(pmt::is_pair(msg)) { msg_len = pmt::blob_length(pmt::cdr(msg)); msdu = reinterpret_cast(pmt::blob_data(pmt::cdr(msg))); } else { throw std::invalid_argument("OFDM MAC expects PDUs or strings"); return; } // make MAC frame int psdu_length; char *psdu; generate_mac_data_frame(msdu, msg_len, &psdu, &psdu_length); // dict pmt::pmt_t dict = pmt::make_dict(); dict = pmt::dict_add(dict, pmt::mp("crc_included"), pmt::PMT_T); // blob pmt::pmt_t mac = pmt::make_blob(psdu, psdu_length); // pdu message_port_pub(pmt::mp("phy out"), pmt::cons(dict, mac)); free(psdu); } void generate_mac_data_frame(const char *msdu, int msdu_size, char **psdu, int *psdu_size) { // mac header mac_header header; header.frame_control = 0x0008; header.duration = 0x002e; for(int i = 0; i < 6; i++) { header.addr1[i] = d_dst_mac[i]; header.addr2[i] = d_src_mac[i]; header.addr3[i] = d_bss_mac[i]; } header.seq_nr = 0; for (int i = 0; i < 12; i++) { if(d_seq_nr & (1 << i)) { header.seq_nr |= (1 << (i + 4)); } } header.seq_nr = htole16(header.seq_nr); d_seq_nr++; //header size is 24, plus 4 for FCS means 28 bytes *psdu_size = 28 + msdu_size; *psdu = (char *) calloc(*psdu_size, sizeof(char)); //copy mac header into psdu std::memcpy(*psdu, &header, 24); //copy msdu into psdu memcpy(*psdu + 24, msdu, msdu_size); //compute and store fcs boost::crc_32_type result; result.process_bytes(*psdu, msdu_size + 24); unsigned int fcs = result.checksum(); memcpy(*psdu + msdu_size + 24, &fcs, sizeof(unsigned int)); } bool check_mac(std::vector mac) { if(mac.size() != 6) return false; return true; } private: uint16_t d_seq_nr; uint8_t d_src_mac[6]; uint8_t d_dst_mac[6]; uint8_t d_bss_mac[6]; bool d_strip_header; }; ofdm_mac::sptr ofdm_mac::make(std::vector src_mac, std::vector dst_mac, std::vector bss_mac, bool strip_header) { return gnuradio::get_initial_sptr(new ofdm_mac_impl(src_mac, dst_mac, bss_mac, strip_header)); }