/** * * \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 SRSLTE_PCAP_H #define SRSLTE_PCAP_H #include #include #include #include #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 */ 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_PAYLOAD_TAG 0x01 #define MAC_LTE_RNTI_TAG 0x02 #define MAC_LTE_UEID_TAG 0x03 #define MAC_LTE_FRAME_SUBFRAME_TAG 0x04 #define MAC_LTE_PREDFINED_DATA_TAG 0x05 #define MAC_LTE_RETX_TAG 0x06 #define MAC_LTE_CRC_STATUS_TAG 0x07 /* 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; /* Context information for every NAS PDU that will be logged */ typedef struct NAS_Context_Info_s { // No Context yet } 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 * **************************************************************************/ /* Open the file and write file header */ inline FILE *LTE_PCAP_Open(uint32_t DLT, 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 */ 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; } /* Close the PCAP file */ inline void LTE_PCAP_Close(FILE *fd) { if(fd) fclose(fd); } /************************************************************************** * API functions for writing MAC-LTE PCAP files * **************************************************************************/ /* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ inline int LTE_PCAP_MAC_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; 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; } /*****************************************************************/ /* 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 and System Frame Number */ /* SFN is stored in 12 MSB and SF in 4 LSB */ context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG; tmp16 = (context->sysFrameNumber << 4) | context->subFrameNumber; tmp16 = htons(tmp16); 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; } /************************************************************************** * API functions for writing NAS-EPS PCAP files * **************************************************************************/ /* Write an individual PDU (PCAP packet header + nas-context + nas-pdu) */ inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context, const unsigned char *PDU, unsigned int length) { pcaprec_hdr_t packet_header; /* Can't write if file wasn't successfully opened */ if (fd == NULL) { printf("Error: Can't write to empty file handle\n"); return 0; } /****************************************************************/ /* 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 = length; packet_header.orig_len = length; /***************************************************************/ /* Now write everything to the file */ fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); fwrite(PDU, 1, length, fd); 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 // SRSLTE_PCAP_H