From e7c74fa0f7858702b328dd91ab4b5edaa974b652 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 23 Mar 2018 16:46:28 +0100 Subject: [PATCH] add simple RLC PCAP writer --- lib/include/srslte/common/pcap.h | 150 +++++++++++++++++++++++++++ lib/include/srslte/common/rlc_pcap.h | 65 ++++++++++++ lib/src/common/rlc_pcap.cc | 90 ++++++++++++++++ 3 files changed, 305 insertions(+) create mode 100644 lib/include/srslte/common/rlc_pcap.h create mode 100644 lib/src/common/rlc_pcap.cc diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h index ce4fcf541..823da662a 100644 --- a/lib/include/srslte/common/pcap.h +++ b/lib/include/srslte/common/pcap.h @@ -34,6 +34,7 @@ #define MAC_LTE_DLT 147 #define NAS_LTE_DLT 148 +#define RLC_LTE_DLT 149 // UDP needs to be selected as protocol /* This structure gets written to the start of the file */ @@ -104,6 +105,67 @@ typedef struct NAS_Context_Info_s { } NAS_Context_Info_t; +/* RLC-LTE disector */ + +/* rlcMode */ +#define RLC_TM_MODE 1 +#define RLC_UM_MODE 2 +#define RLC_AM_MODE 4 +#define RLC_PREDEF 8 + +/* priority ? */ + +/* channelType */ +#define CHANNEL_TYPE_CCCH 1 +#define CHANNEL_TYPE_BCCH_BCH 2 +#define CHANNEL_TYPE_PCCH 3 +#define CHANNEL_TYPE_SRB 4 +#define CHANNEL_TYPE_DRB 5 +#define CHANNEL_TYPE_BCCH_DL_SCH 6 +#define CHANNEL_TYPE_MCCH 7 +#define CHANNEL_TYPE_MTCH 8 + +/* sequenceNumberLength */ +#define UM_SN_LENGTH_5_BITS 5 +#define UM_SN_LENGTH_10_BITS 10 +#define AM_SN_LENGTH_10_BITS 10 +#define AM_SN_LENGTH_16_BITS 16 + +/* Narrow band mode */ +typedef enum { + rlc_no_nb_mode = 0, + rlc_nb_mode = 1 +} rlc_lte_nb_mode; + +/* Context information for every RLC PDU that will be logged */ +typedef struct { + unsigned char rlcMode; + unsigned char direction; + unsigned char priority; + unsigned char sequenceNumberLength; + unsigned short ueid; + unsigned short channelType; + unsigned short channelId; /* for SRB: 1=SRB1, 2=SRB2, 3=SRB1bis; for DRB: DRB ID */ + unsigned short pduLength; + bool extendedLiField; + rlc_lte_nb_mode nbMode; +} RLC_Context_Info_t; + + +// See Wireshark's packet-rlc-lte.h for details +#define RLC_LTE_START_STRING "rlc-lte" +#define RLC_LTE_SN_LENGTH_TAG 0x02 +#define RLC_LTE_DIRECTION_TAG 0x03 +#define RLC_LTE_PRIORITY_TAG 0x04 +#define RLC_LTE_UEID_TAG 0x05 +#define RLC_LTE_CHANNEL_TYPE_TAG 0x06 +#define RLC_LTE_CHANNEL_ID_TAG 0x07 +#define RLC_LTE_EXT_LI_FIELD_TAG 0x08 +#define RLC_LTE_NB_MODE_TAG 0x09 +#define RLC_LTE_PAYLOAD_TAG 0x01 + + + /************************************************************************** * API functions for opening/closing LTE PCAP files * **************************************************************************/ @@ -247,4 +309,92 @@ inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context, return 1; } +/************************************************************************** + * API functions for writing RLC-LTE PCAP files * + **************************************************************************/ + +/* Write an individual RLC PDU (PCAP packet header + UDP header + rlc-context + rlc-pdu) */ +inline int LTE_PCAP_RLC_WritePDU(FILE *fd, RLC_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) +{ + pcaprec_hdr_t packet_header; + char context_header[256]; + int offset = 0; + uint16_t 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; + } + + /*****************************************************************/ + + // Add dummy UDP header, start with src and dest port + context_header[offset++] = 0xde; + context_header[offset++] = 0xad; + context_header[offset++] = 0xbe; + context_header[offset++] = 0xef; + // length + tmp16 = length + 12; + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + // dummy CRC + context_header[offset++] = 0xde; + context_header[offset++] = 0xad; + + // Start magic string + memcpy(&context_header[offset], RLC_LTE_START_STRING, strlen(RLC_LTE_START_STRING)); + offset += strlen(RLC_LTE_START_STRING); + + // Fixed field RLC mode + context_header[offset++] = context->rlcMode; + + // Conditional fields + if (context->rlcMode == RLC_UM_MODE) { + context_header[offset++] = RLC_LTE_SN_LENGTH_TAG; + context_header[offset++] = context->sequenceNumberLength; + } + + // Optional fields + context_header[offset++] = RLC_LTE_DIRECTION_TAG; + context_header[offset++] = context->direction; + + context_header[offset++] = RLC_LTE_PRIORITY_TAG; + context_header[offset++] = context->priority; + + context_header[offset++] = RLC_LTE_UEID_TAG; + tmp16 = htons(context->ueid); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + context_header[offset++] = RLC_LTE_CHANNEL_TYPE_TAG; + tmp16 = htons(context->channelType); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + context_header[offset++] = RLC_LTE_CHANNEL_ID_TAG; + tmp16 = htons(context->channelId); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + // Now the actual PDU + context_header[offset++] = RLC_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; + + // Write everything to file + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(context_header, 1, offset, fd); + fwrite(PDU, 1, length, fd); + + return 1; +} + #endif /* UEPCAP_H */ diff --git a/lib/include/srslte/common/rlc_pcap.h b/lib/include/srslte/common/rlc_pcap.h new file mode 100644 index 000000000..3a506f6ef --- /dev/null +++ b/lib/include/srslte/common/rlc_pcap.h @@ -0,0 +1,65 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 RLCPCAP_H +#define RLCPCAP_H + +#include +#include "srslte/common/pcap.h" + +namespace srslte { + +class rlc_pcap +{ +public: + rlc_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; + void enable(bool en); + void open(const char *filename, uint32_t ue_id = 0); + void close(); + + void set_ue_id(uint16_t ue_id); + + void write_dl_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes); + void write_ul_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes); + +private: + bool enable_write; + FILE *pcap_file; + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint8_t mode, + uint8_t direction, + uint8_t priority, + uint8_t seqnumberlength, + uint16_t ueid, + uint16_t channel_type, + uint16_t channel_id); +}; + +} // namespace srsue + +#endif // RLCPCAP_H diff --git a/lib/src/common/rlc_pcap.cc b/lib/src/common/rlc_pcap.cc new file mode 100644 index 000000000..e6bcbe642 --- /dev/null +++ b/lib/src/common/rlc_pcap.cc @@ -0,0 +1,90 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + + +#include +#include "srslte/srslte.h" +#include "srslte/common/pcap.h" +#include "srslte/common/rlc_pcap.h" + +namespace srslte { + +void rlc_pcap::enable(bool en) +{ + enable_write = true; +} +void rlc_pcap::open(const char* filename, uint32_t ue_id) +{ + fprintf(stdout, "Opening RLC PCAP with DLT=%d\n", RLC_LTE_DLT); + pcap_file = LTE_PCAP_Open(RLC_LTE_DLT, filename); + this->ue_id = ue_id; + enable_write = true; +} +void rlc_pcap::close() +{ + fprintf(stdout, "Saving RLC PCAP file\n"); + LTE_PCAP_Close(pcap_file); +} + +void rlc_pcap::set_ue_id(uint16_t ue_id) { + this->ue_id = ue_id; +} + +void rlc_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint8_t mode, uint8_t direction, uint8_t priority, uint8_t seqnumberlength, uint16_t ueid, uint16_t channel_type, uint16_t channel_id) +{ + if (enable_write) { + RLC_Context_Info_t context; + context.rlcMode = mode; + context.direction = direction; + context.priority = priority; + context.sequenceNumberLength = seqnumberlength; + context.ueid = ueid; + context.channelType = channel_type; + context.channelId = channel_id; + context.pduLength = pdu_len_bytes; + if (pdu) { + LTE_PCAP_RLC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } + } +} + +void rlc_pcap::write_dl_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes) +{ + uint8_t priority = 0; + uint8_t seqnumberlength = 0; // normal length of 10bit + uint8_t channel_id = 0; + pack_and_write(pdu, pdu_len_bytes, RLC_AM_MODE, DIRECTION_DOWNLINK, priority, seqnumberlength, ue_id, CHANNEL_TYPE_CCCH, channel_id); +} + +void rlc_pcap::write_ul_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes) +{ + uint8_t priority = 0; + uint8_t seqnumberlength = 0; // normal length of 10bit + uint8_t channel_id = 0; + pack_and_write(pdu, pdu_len_bytes, RLC_AM_MODE, DIRECTION_UPLINK, priority, seqnumberlength, ue_id, CHANNEL_TYPE_CCCH, channel_id); +} + +}