From e6d5057d5d9c6cb8e092d507b14e136fd85ef772 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 15 Jul 2010 21:30:25 +0200 Subject: [PATCH] gsm: Update and enhance the GSM Tap functionality * switch to the new format * add uplink frame dump as well * fill more fields than before (not fully complete yet tough) Signed-off-by: Sylvain Munaut --- public-trunk/GSM/GSML1FEC.cpp | 12 +++- public-trunk/GSM/GSMTAPDump.cpp | 100 +++++++++++++++++++++++++++++--- public-trunk/GSM/GSMTAPDump.h | 5 +- public-trunk/GSM/gsmtap.h | 80 +++++++++++++------------ 4 files changed, 151 insertions(+), 46 deletions(-) diff --git a/public-trunk/GSM/GSML1FEC.cpp b/public-trunk/GSM/GSML1FEC.cpp index 4e56c0e..d4e394e 100644 --- a/public-trunk/GSM/GSML1FEC.cpp +++ b/public-trunk/GSM/GSML1FEC.cpp @@ -659,6 +659,10 @@ void XCCHL1Decoder::handleGoodFrame() OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder d[]=" << mD; if (mUpstream) { + // Send all bits to GSMTAP + gWriteGSMTAP(ARFCN(),TN(),mReadTime.FN(), + typeAndOffset(),mMapping.repeatLength()>51,true, + mD); // Build an L2 frame and pass it up. const BitVector L2Part(mD.tail(headerOffset())); OBJLOG(DEEPDEBUG) <<"XCCHL1Decoder L2=" << L2Part; @@ -810,14 +814,18 @@ void XCCHL1Encoder::sendFrame(const L2Frame& frame) // GSM 05.03 4.1.1. //assert(mD.size()==headerOffset()+frame.size()); frame.copyToSegment(mU,headerOffset()); + + // Send to GSMTAP (must send mU = real bits !) + gWriteGSMTAP(ARFCN(),TN(),mNextWriteTime.FN(), + typeAndOffset(),mMapping.repeatLength()>51,false,mU); + + // Encode data into bursts OBJLOG(DEEPDEBUG) << "XCCHL1Encoder d[]=" << mD; mD.LSB8MSB(); OBJLOG(DEEPDEBUG) << "XCCHL1Encoder d[]=" << mD; encode(); // Encode u[] to c[], GSM 05.03 4.1.2 and 4.1.3. interleave(); // Interleave c[] to i[][], GSM 05.03 4.1.4. transmit(); // Send the bursts to the radio, GSM 05.03 4.1.5. - // FIXME: is this FN OK, or do we need to back it up by 4? - gWriteGSMTAP(ARFCN(),mTN,mPrevWriteTime.FN(),frame); } diff --git a/public-trunk/GSM/GSMTAPDump.cpp b/public-trunk/GSM/GSMTAPDump.cpp index 0037e7d..2f6f04e 100644 --- a/public-trunk/GSM/GSMTAPDump.cpp +++ b/public-trunk/GSM/GSMTAPDump.cpp @@ -30,21 +30,107 @@ UDPSocket GSMTAPSocket; -void gWriteGSMTAP(unsigned ARFCN, unsigned TS, unsigned FN, const GSM::L2Frame& frame) +void gWriteGSMTAP(unsigned ARFCN, unsigned TS, unsigned FN, + GSM::TypeAndOffset to, bool is_saach, bool ul_dln, + const BitVector& frame) { + char buffer[MAX_UDP_LENGTH]; + int ofs = 0; + + // Check if GSMTap is enabled if (!gConfig.defines("GSMTAP.TargetIP")) return; + // Port configuration unsigned port = GSMTAP_UDP_PORT; // default port for GSM-TAP if (gConfig.defines("GSMTAP.TargetPort")) port = gConfig.getNum("GSMTAP.TargetPort"); - // Write a GSMTAP packet to the configured destination. + // Set socket destination GSMTAPSocket.destination(port,gConfig.getStr("GSMTAP.TargetIP")); - char buffer[MAX_UDP_LENGTH]; - gsmtap_hdr header(ARFCN,TS,FN); - memcpy(buffer,&header,sizeof(header)); - frame.pack((unsigned char*)buffer+sizeof(header)); - GSMTAPSocket.write(buffer, sizeof(header) + frame.size()/8); + + // Decode TypeAndOffset + uint8_t stype, scn; + + switch (to) { + case GSM::TDMA_BEACON_BCCH: + stype = GSMTAP_CHANNEL_BCCH; + scn = 0; + break; + + case GSM::TDMA_BEACON_CCCH: + stype = GSMTAP_CHANNEL_CCCH; + scn = 0; + break; + + case GSM::SDCCH_4_0: + case GSM::SDCCH_4_1: + case GSM::SDCCH_4_2: + case GSM::SDCCH_4_3: + stype = GSMTAP_CHANNEL_SDCCH4; + scn = to - GSM::SDCCH_4_0; + break; + + case GSM::SDCCH_8_0: + case GSM::SDCCH_8_1: + case GSM::SDCCH_8_2: + case GSM::SDCCH_8_3: + case GSM::SDCCH_8_4: + case GSM::SDCCH_8_5: + case GSM::SDCCH_8_6: + case GSM::SDCCH_8_7: + stype = GSMTAP_CHANNEL_SDCCH8; + scn = to - GSM::SDCCH_8_0; + break; + + case GSM::TCHF_0: + stype = GSMTAP_CHANNEL_TCH_F; + scn = 0; + break; + + case GSM::TCHH_0: + case GSM::TCHH_1: + stype = GSMTAP_CHANNEL_TCH_H; + scn = to - GSM::TCHH_0; + break; + + default: + stype = GSMTAP_CHANNEL_UNKNOWN; + scn = 0; + } + + if (is_saach) + stype |= GSMTAP_CHANNEL_ACCH; + + // Flags in ARFCN + if (gConfig.getNum("GSM.Band") == 1900) + ARFCN |= GSMTAP_ARFCN_F_PCS; + + if (ul_dln) + ARFCN |= GSMTAP_ARFCN_F_UPLINK; + + // Build header + struct gsmtap_hdr *header = (struct gsmtap_hdr *)buffer; + header->version = GSMTAP_VERSION; + header->hdr_len = sizeof(struct gsmtap_hdr) >> 2; + header->type = GSMTAP_TYPE_UM; + header->timeslot = TS; + header->arfcn = htons(ARFCN); + header->signal_dbm = 0; /* FIXME */ + header->snr_db = 0; /* FIXME */ + header->frame_number = htonl(FN); + header->sub_type = stype; + header->antenna_nr = 0; + header->sub_slot = scn; + header->res = 0; + + ofs += sizeof(*header); + + // Add frame data + frame.pack((unsigned char*)&buffer[ofs]); + ofs += (frame.size() + 7) >> 3; + + // Write the GSMTAP packet + GSMTAPSocket.write(buffer, ofs); } diff --git a/public-trunk/GSM/GSMTAPDump.h b/public-trunk/GSM/GSMTAPDump.h index 9c8e470..4955fcd 100644 --- a/public-trunk/GSM/GSMTAPDump.h +++ b/public-trunk/GSM/GSMTAPDump.h @@ -28,10 +28,13 @@ #define GSMTAPDUMP_H #include "gsmtap.h" +#include "GSMCommon.h" #include "GSMTransfer.h" -void gWriteGSMTAP(unsigned ARFCN, unsigned TS, unsigned FN, const GSM::L2Frame& frame); +void gWriteGSMTAP(unsigned ARFCN, unsigned TS, unsigned FN, + GSM::TypeAndOffset to, bool is_sacch, bool ul_dln, + const BitVector& frame); #endif diff --git a/public-trunk/GSM/gsmtap.h b/public-trunk/GSM/gsmtap.h index fcba386..75fa3f3 100644 --- a/public-trunk/GSM/gsmtap.h +++ b/public-trunk/GSM/gsmtap.h @@ -1,14 +1,20 @@ #ifndef _GSMTAP_H #define _GSMTAP_H -/* gsmtap header, pseudo-header in front of the actua GSM payload*/ +/* gsmtap header, pseudo-header in front of the actua GSM payload */ -#include -#ifdef __linux__ -# include -#endif +/* GSMTAP is a generic header format for GSM protocol captures, + * it uses the IANA-assigned UDP port number 4729 and carries + * payload in various formats of GSM interfaces such as Um MAC + * blocks or Um bursts. + * + * Example programs generating GSMTAP data are airprobe + * (http://airprobe.org/) or OsmocomBB (http://bb.osmocom.org/) + */ -#define GSMTAP_VERSION 0x01 +#include + +#define GSMTAP_VERSION 0x02 #define GSMTAP_TYPE_UM 0x01 /* A Layer 2 MAC block (23 bytes) */ #define GSMTAP_TYPE_ABIS 0x02 @@ -25,38 +31,41 @@ #define GSMTAP_BURST_ACCESS 0x08 #define GSMTAP_BURST_NONE 0x09 +#define GSMTAP_CHANNEL_UNKNOWN 0x00 +#define GSMTAP_CHANNEL_BCCH 0x01 +#define GSMTAP_CHANNEL_CCCH 0x02 +#define GSMTAP_CHANNEL_RACH 0x03 +#define GSMTAP_CHANNEL_AGCH 0x04 +#define GSMTAP_CHANNEL_PCH 0x05 +#define GSMTAP_CHANNEL_SDCCH 0x06 +#define GSMTAP_CHANNEL_SDCCH4 0x07 +#define GSMTAP_CHANNEL_SDCCH8 0x08 +#define GSMTAP_CHANNEL_TCH_F 0x09 +#define GSMTAP_CHANNEL_TCH_H 0x0a +#define GSMTAP_CHANNEL_ACCH 0x80 + +#define GSMTAP_ARFCN_F_PCS 0x8000 +#define GSMTAP_ARFCN_F_UPLINK 0x4000 +#define GSMTAP_ARFCN_MASK 0x3fff + #define GSMTAP_UDP_PORT 4729 /* officially registered with IANA */ struct gsmtap_hdr { - u_int8_t version; /* version, set to 0x01 currently */ - u_int8_t hdr_len; /* length in number of 32bit words */ - u_int8_t type; /* see GSMTAP_TYPE_* */ - u_int8_t timeslot; /* timeslot (0..7 on Um) */ + uint8_t version; /* version, set to GSMTAP_VERSION */ + uint8_t hdr_len; /* length in number of 32bit words */ + uint8_t type; /* see GSMTAP_TYPE_* */ + uint8_t timeslot; /* timeslot (0..7 on Um) */ - u_int16_t arfcn; /* ARFCN (frequency). - * highest bit 1 == uplink */ - u_int8_t noise_db; /* noise figure in dB */ - u_int8_t signal_db; /* signal level in dB */ + uint16_t arfcn; /* ARFCN (frequency) */ + int8_t signal_dbm; /* signal level in dBm */ + int8_t snr_db; /* signal/noise ratio in dB */ - u_int32_t frame_number; /* GSM Frame Number (FN) */ + uint32_t frame_number; /* GSM Frame Number (FN) */ - u_int8_t burst_type; /* Type of burst, see above */ - u_int8_t antenna_nr; /* Antenna Number */ - u_int16_t res; /* reserved for future use (RFU) */ - - gsmtap_hdr(unsigned ARFCN, unsigned TS, unsigned FN) - { - version = GSMTAP_VERSION; - type = GSMTAP_TYPE_UM; - burst_type = GSMTAP_BURST_NONE; - antenna_nr = 0; - noise_db = 0; - signal_db = 0; - - timeslot = TS; - arfcn = htons(ARFCN); - frame_number = htonl(FN); - } + uint8_t sub_type; /* Type of burst/channel, see above */ + uint8_t antenna_nr; /* Antenna Number */ + uint8_t sub_slot; /* sub-slot within timeslot */ + uint8_t res; /* reserved for future use (RFU) */ } __attribute__((packed)); @@ -70,12 +79,11 @@ struct pcap_timeval { int32_t tv_sec; int32_t tv_usec; }; - + struct pcap_sf_pkthdr { struct pcap_timeval ts; /* time stamp */ - u_int32_t caplen; /* lenght of portion present */ - u_int32_t len; /* length of this packet */ + uint32_t caplen; /* lenght of portion present */ + uint32_t len; /* length of this packet */ }; - #endif /* _GSMTAP_H */