diff --git a/srsapps/ue/mac/include/srsapps/ue/mac/demux.h b/srsapps/ue/mac/include/srsapps/ue/mac/demux.h index e5a168ce0..3ab286f7c 100644 --- a/srsapps/ue/mac/include/srsapps/ue/mac/demux.h +++ b/srsapps/ue/mac/include/srsapps/ue/mac/demux.h @@ -47,7 +47,7 @@ class demux { public: demux(); - void init(phy* phy_h_, log* log_h_, mac_io* mac_io_h_, timers* timers_db_); + void init(phy* phy_h_, log* log_h_, mac_io* mac_io_h_, timers* timers_db_, bool pcap_=false, FILE *pcap_file_=0); void add_sdu_handler(sdu_handler *handler); @@ -72,6 +72,10 @@ private: bool pending_temp_rnti; bool has_pending_contention_resolution_id; + /* Write MAC PDUs to file in PCACP format? */ + bool pcap; + FILE *pcap_file; + phy *phy_h; log *log_h; mac_io *mac_io_h; diff --git a/srsapps/ue/mac/include/srsapps/ue/mac/mac.h b/srsapps/ue/mac/include/srsapps/ue/mac/mac.h index 55420fce6..4ec7128d4 100644 --- a/srsapps/ue/mac/include/srsapps/ue/mac/mac.h +++ b/srsapps/ue/mac/include/srsapps/ue/mac/mac.h @@ -60,7 +60,8 @@ class mac : public timer_callback { public: mac() : timers_db((uint32_t) NOF_MAC_TIMERS), tr_end_time(1024*10), tr_start_time(1024*10) {started=false;} - bool init(phy *phy_h, tti_sync *ttisync, log *log_h); + ~mac(); + bool init(phy *phy_h, tti_sync *ttisync, log *log_h, bool pcap_=false); void stop(); int get_tti(); void main_radio_loop(); // called after thread creation @@ -149,6 +150,10 @@ private: uint16_t phy_rnti; void setup_timers(); void timeAlignmentTimerExpire(); + + /* Write MAC PDUs to file in PCACP format? */ + bool pcap; + FILE *pcap_file; trace tr_start_time; trace tr_end_time; diff --git a/srsapps/ue/mac/include/srsapps/ue/mac/mux.h b/srsapps/ue/mac/include/srsapps/ue/mac/mux.h index 530c77d15..c56764075 100644 --- a/srsapps/ue/mac/include/srsapps/ue/mac/mux.h +++ b/srsapps/ue/mac/include/srsapps/ue/mac/mux.h @@ -47,7 +47,7 @@ class mux public: mux(); void reset(); - void init(log *log_h, mac_io *mac_io_h, bsr_proc *bsr_procedure); + void init(log *log_h, mac_io *mac_io_h, bsr_proc *bsr_procedure, bool pcap_=false, FILE *pcap_file_=0); bool is_pending_ccch_sdu(); bool is_pending_any_sdu(); @@ -97,6 +97,10 @@ private: qbuff pdu_buff; sch_pdu pdu_msg; bool msg3_has_been_transmitted; + + /* Write MAC PDUs to file in PCACP format? */ + bool pcap; + FILE *pcap_file; }; } diff --git a/srsapps/ue/mac/include/srsapps/ue/mac/pcap.h b/srsapps/ue/mac/include/srsapps/ue/mac/pcap.h new file mode 100644 index 000000000..982cbe64d --- /dev/null +++ b/srsapps/ue/mac/include/srsapps/ue/mac/pcap.h @@ -0,0 +1,218 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 The srsLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef UEPCAP_H +#define UEPCAP_H + +#include +#include +#include +#include + +#define MAC_LTE_DLT 147 + + +/* This structure gets written to the start of the file */ +typedef struct pcap_hdr_s { + unsigned int magic_number; /* magic number */ + unsigned short version_major; /* major version number */ + unsigned short version_minor; /* minor version number */ + unsigned int thiszone; /* GMT to local correction */ + unsigned int sigfigs; /* accuracy of timestamps */ + unsigned int snaplen; /* max length of captured packets, in octets */ + unsigned int network; /* data link type */ +} pcap_hdr_t; + +/* This structure precedes each packet */ +typedef struct pcaprec_hdr_s { + unsigned int ts_sec; /* timestamp seconds */ + unsigned int ts_usec; /* timestamp microseconds */ + unsigned int incl_len; /* number of octets of packet saved in file */ + unsigned int orig_len; /* actual length of packet */ +} pcaprec_hdr_t; + + +/* radioType */ +#define FDD_RADIO 1 +#define TDD_RADIO 2 + +/* Direction */ +#define DIRECTION_UPLINK 0 +#define DIRECTION_DOWNLINK 1 + +/* rntiType */ +#define NO_RNTI 0 /* Used for BCH-BCH */ +#define P_RNTI 1 +#define RA_RNTI 2 +#define C_RNTI 3 +#define SI_RNTI 4 +#define SPS_RNTI 5 +#define M_RNTI 6 + +#define MAC_LTE_START_STRING "mac-lte" + +#define MAC_LTE_RNTI_TAG 0x02 +/* 2 bytes, network order */ + +#define MAC_LTE_UEID_TAG 0x03 +/* 2 bytes, network order */ + +#define MAC_LTE_SUBFRAME_TAG 0x04 +/* 2 bytes, network order */ + +#define MAC_LTE_PREDFINED_DATA_TAG 0x05 +/* 1 byte */ + +#define MAC_LTE_RETX_TAG 0x06 +/* 1 byte */ + +#define MAC_LTE_CRC_STATUS_TAG 0x07 +/* 1 byte */ + +/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU + continues until the end of the frame) */ +#define MAC_LTE_PAYLOAD_TAG 0x01 + + +/* Context information for every MAC PDU that will be logged */ +typedef struct MAC_Context_Info_t { + unsigned short radioType; + unsigned char direction; + unsigned char rntiType; + unsigned short rnti; + unsigned short ueid; + unsigned char isRetx; + unsigned char crcStatusOK; + + unsigned short sysFrameNumber; + unsigned short subFrameNumber; + +} MAC_Context_Info_t; + + + + +/**************************************************************************/ +/* API functions for opening/writing/closing MAC-LTE PCAP files */ + +/* Open the file and write file header */ +inline FILE *MAC_LTE_PCAP_Open(const char *fileName) +{ + pcap_hdr_t file_header = + { + 0xa1b2c3d4, /* magic number */ + 2, 4, /* version number is 2.4 */ + 0, /* timezone */ + 0, /* sigfigs - apparently all tools do this */ + 65535, /* snaplen - this should be long enough */ + MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */ + }; + + FILE *fd = fopen(fileName, "w"); + if (fd == NULL) { + printf("Failed to open file \"%s\" for writing\n", fileName); + return NULL; + } + + /* Write the file header */ + fwrite(&file_header, sizeof(pcap_hdr_t), 1, fd); + + return fd; +} + +/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ +inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) +{ + pcaprec_hdr_t packet_header; + char context_header[256]; + int offset = 0; + unsigned short tmp16; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + + /*****************************************************************/ + /* Context information (same as written by UDP heuristic clients */ + context_header[offset++] = context->radioType; + context_header[offset++] = context->direction; + context_header[offset++] = context->rntiType; + + /* RNTI */ + context_header[offset++] = MAC_LTE_RNTI_TAG; + tmp16 = htons(context->rnti); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + /* UEId */ + context_header[offset++] = MAC_LTE_UEID_TAG; + tmp16 = htons(context->ueid); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + /* Subframe number */ + context_header[offset++] = MAC_LTE_SUBFRAME_TAG; + tmp16 = htons(context->subFrameNumber); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + /* CRC Status */ + context_header[offset++] = MAC_LTE_CRC_STATUS_TAG; + context_header[offset++] = context->crcStatusOK; + + /* Data tag immediately preceding PDU */ + context_header[offset++] = MAC_LTE_PAYLOAD_TAG; + + + /****************************************************************/ + /* PCAP Header */ + struct timeval t; + gettimeofday(&t, NULL); + packet_header.ts_sec = t.tv_sec; + packet_header.ts_usec = t.tv_usec; + packet_header.incl_len = offset + length; + packet_header.orig_len = offset + length; + + /***************************************************************/ + /* Now write everything to the file */ + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(context_header, 1, offset, fd); + fwrite(PDU, 1, length, fd); + + return 1; +} + +/* Close the PCAP file */ +inline void MAC_LTE_PCAP_Close(FILE *fd) +{ + fclose(fd); +} + +#endif /* UEPCAP_H */ diff --git a/srsapps/ue/mac/include/srsapps/ue/mac/pdu.h b/srsapps/ue/mac/include/srsapps/ue/mac/pdu.h index 7ec65e8e2..e27d66603 100644 --- a/srsapps/ue/mac/include/srsapps/ue/mac/pdu.h +++ b/srsapps/ue/mac/include/srsapps/ue/mac/pdu.h @@ -124,7 +124,7 @@ public: } // Section 6.1.2 - void parse_packet(uint8_t *ptr) { + void parse_packet(uint8_t *ptr, FILE *pcap_file=0) { uint8_t *init_ptr = ptr; nof_subheaders = 0; while(subheaders[nof_subheaders].read_subheader(&ptr)) { @@ -139,7 +139,7 @@ public: return pdu_is_ul; } - virtual bool write_packet(uint8_t *ptr) = 0; + virtual bool write_packet(uint8_t *ptr, FILE *pcap_file=0) = 0; protected: std::vector subheaders; @@ -238,8 +238,8 @@ public: sch_pdu(uint32_t max_rars) : pdu(max_rars) {} - void parse_packet(uint8_t *ptr); - bool write_packet(uint8_t *ptr); + void parse_packet(uint8_t *ptr, FILE *pcap_file=0); + bool write_packet(uint8_t *ptr, FILE *pcap_file=0); bool has_space_ce(uint32_t nbytes); bool has_space_sdu(uint32_t nbytes); bool has_space_sdu(uint32_t nbytes, bool is_first); @@ -295,7 +295,7 @@ public: bool has_backoff(); uint8_t get_backoff(); - bool write_packet(uint8_t* ptr); + bool write_packet(uint8_t* ptr, FILE *pcap_file=0); void fprint(FILE *stream); private: diff --git a/srsapps/ue/mac/src/demux.cc b/srsapps/ue/mac/src/demux.cc index 36bce0301..d1fd7cdf5 100644 --- a/srsapps/ue/mac/src/demux.cc +++ b/srsapps/ue/mac/src/demux.cc @@ -40,12 +40,14 @@ demux::demux() : mac_msg(20),pending_mac_msg(20) sdu_handler_ = NULL; } -void demux::init(phy* phy_h_, log* log_h_, mac_io* mac_io_h_, timers* timers_db_) +void demux::init(phy* phy_h_, log* log_h_, mac_io* mac_io_h_, timers* timers_db_, bool pcap_, FILE *pcap_file_) { phy_h = phy_h_; log_h = log_h_; mac_io_h = mac_io_h_; timers_db = timers_db_; + pcap = pcap_; + pcap_file = pcap_file_; } void demux::add_sdu_handler(sdu_handler* handler) @@ -91,7 +93,7 @@ void demux::push_pdu_temp_crnti(uint8_t *mac_pdu, uint32_t nof_bits) if (!pending_temp_rnti) { // Unpack DLSCH MAC PDU pending_mac_msg.init(nof_bits/8); - pending_mac_msg.parse_packet(mac_pdu); + pending_mac_msg.parse_packet(mac_pdu, pcap_file); //pending_mac_msg.fprint(stdout); // Look for Contention Resolution UE ID @@ -115,7 +117,7 @@ void demux::push_pdu(uint8_t *mac_pdu, uint32_t nof_bits) { // Unpack DLSCH MAC PDU mac_msg.init(nof_bits/8); - mac_msg.parse_packet(mac_pdu); + mac_msg.parse_packet(mac_pdu, pcap_file); //mac_msg.fprint(stdout); process_pdu(&mac_msg); Debug("Normal MAC PDU processed\n"); diff --git a/srsapps/ue/mac/src/mac.cc b/srsapps/ue/mac/src/mac.cc index 331995caa..e9b8b0ae0 100644 --- a/srsapps/ue/mac/src/mac.cc +++ b/srsapps/ue/mac/src/mac.cc @@ -35,24 +35,41 @@ #include "srsapps/common/log.h" #include "srsapps/ue/mac/mac.h" #include "srsapps/ue/mac/mac_params.h" +#include "srsapps/ue/mac/pcap.h" namespace srslte { namespace ue { + +mac::~mac() +{ + if(pcap && pcap_file) { + MAC_LTE_PCAP_Close(pcap_file); + } +} -bool mac::init(phy *phy_h_, tti_sync* ttisync_, log* log_h_) +bool mac::init(phy *phy_h_, tti_sync* ttisync_, log* log_h_, bool pcap_) { started = false; ttisync = ttisync_; phy_h = phy_h_; log_h = log_h_; + pcap = pcap_; tti = 0; is_synchronized = false; last_temporal_crnti = 0; phy_rnti = 0; + + if(pcap) { + pcap_file = MAC_LTE_PCAP_Open("/tmp/ue_mac.pcap"); + if(!pcap_file) { + Info("Failed to open pcap for writing\n"); + pcap = false; + } + } bsr_procedure.init(log_h, &timers_db, ¶ms_db, &mac_io_lch); - mux_unit.init(log_h, &mac_io_lch, &bsr_procedure); - demux_unit.init(phy_h, log_h, &mac_io_lch, &timers_db); + mux_unit.init(log_h, &mac_io_lch, &bsr_procedure, pcap, pcap_file); + demux_unit.init(phy_h, log_h, &mac_io_lch, &timers_db, pcap, pcap_file); ra_procedure.init(¶ms_db, phy_h, log_h, &timers_db, &mux_unit, &demux_unit); sr_procedure.init(log_h, ¶ms_db, phy_h); reset(); diff --git a/srsapps/ue/mac/src/mux.cc b/srsapps/ue/mac/src/mux.cc index fde3eb2aa..618160922 100644 --- a/srsapps/ue/mac/src/mux.cc +++ b/srsapps/ue/mac/src/mux.cc @@ -52,11 +52,13 @@ mux::mux() : pdu_msg(20) } } -void mux::init(log *log_h_, mac_io *mac_io_h_, bsr_proc *bsr_procedure_) +void mux::init(log *log_h_, mac_io *mac_io_h_, bsr_proc *bsr_procedure_, bool pcap_, FILE *pcap_file_) { log_h = log_h_; mac_io_h = mac_io_h_; bsr_procedure = bsr_procedure_; + pcap = pcap_; + pcap_file = pcap_file_; } void mux::reset() @@ -285,7 +287,7 @@ bool mux::assemble_pdu(uint32_t pdu_sz_nbits) { //pdu_msg.fprint(stdout); /* Generate MAC PDU and save to buffer */ - if (pdu_msg.write_packet(buff)) { + if (pdu_msg.write_packet(buff, pcap_file)) { pdu_buff.push(pdu_sz_nbits); } else { Error("Writing PDU message to packet\n"); diff --git a/srsapps/ue/mac/src/pdu.cc b/srsapps/ue/mac/src/pdu.cc index 95f606389..d4ef9adc0 100644 --- a/srsapps/ue/mac/src/pdu.cc +++ b/srsapps/ue/mac/src/pdu.cc @@ -30,6 +30,7 @@ #include #include "srsapps/ue/mac/pdu.h" +#include "srsapps/ue/mac/pcap.h" #include "srslte/srslte.h" namespace srslte { @@ -85,8 +86,24 @@ void sch_subh::fprint(FILE* stream) } } -void sch_pdu::parse_packet(uint8_t *ptr) +void sch_pdu::parse_packet(uint8_t *ptr, FILE *pcap_file) { + if(pcap_file) { + MAC_Context_Info_t context = + { + FDD_RADIO, DIRECTION_DOWNLINK, C_RNTI, + 50, /* RNTI */ + 102, /* UEId */ + 0, /* Retx */ + 1, /* CRC Stsatus (i.e. OK) */ + 1, /* Sysframe number */ + 4 /* Subframe number */ + }; + + MAC_LTE_PCAP_WritePDU(pcap_file, &context, ptr, pdu_len); + fprintf(stdout, "Wrote DL MAC PDU, len=%d\n", pdu_len); + } + pdu::parse_packet(ptr); // Correct size for last SDU @@ -104,7 +121,7 @@ void sch_pdu::parse_packet(uint8_t *ptr) } // Section 6.1.2 -bool sch_pdu::write_packet(uint8_t* ptr) +bool sch_pdu::write_packet(uint8_t* ptr, FILE *pcap_file) { uint8_t *init_ptr = ptr; bool last_is_padding = false; @@ -173,6 +190,21 @@ bool sch_pdu::write_packet(uint8_t* ptr) // Set paddint to zeros (if any) bzero(ptr, rem_len*sizeof(uint8_t)*8); + if(pcap_file) { + MAC_Context_Info_t context = + { + FDD_RADIO, DIRECTION_UPLINK, C_RNTI, + 50, /* RNTI */ + 102, /* UEId */ + 0, /* Retx */ + 1, /* CRC Stsatus (i.e. OK) */ + 1, /* Sysframe number */ + 4 /* Subframe number */ + }; + + MAC_LTE_PCAP_WritePDU(pcap_file, &context, init_ptr, pdu_len); + fprintf(stdout, "Wrote UL MAC PDU, len=%d\n", pdu_len); + } } uint32_t sch_pdu::rem_size() { @@ -554,7 +586,7 @@ void rar_pdu::set_backoff(uint8_t bi) } // Section 6.1.5 -bool rar_pdu::write_packet(uint8_t* ptr) +bool rar_pdu::write_packet(uint8_t* ptr, FILE *pcap_file) { // Write Backoff Indicator, if any if (has_backoff_indicator) { diff --git a/srsapps/ue/mac/test/mac_test.cc b/srsapps/ue/mac/test/mac_test.cc index 3ee4ed96d..f614d7c25 100644 --- a/srsapps/ue/mac/test/mac_test.cc +++ b/srsapps/ue/mac/test/mac_test.cc @@ -282,10 +282,10 @@ void process_connsetup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *msg, srslte::ue::mac } } } - for (int i=0;irr_cnfg.drb_to_add_mod_list_size;i++) { - printf("Setting up DRB%d\n", msg->rr_cnfg.drb_to_add_mod_list[i].drb_id); - // todo - } +// for (int i=0;irr_cnfg.drb_to_add_mod_list_size;i++) { +// printf("Setting up DRB%d\n", msg->rr_cnfg.drb_to_add_mod_list[i].drb_id); +// // todo +// } }