add simple RLC PCAP writer

This commit is contained in:
Andre Puschmann 2018-03-23 16:46:28 +01:00
parent 7993385742
commit e7c74fa0f7
3 changed files with 305 additions and 0 deletions

View File

@ -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 */

View File

@ -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 <stdint.h>
#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

View File

@ -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 <stdint.h>
#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);
}
}