blob: 1986041c0e3f2b0074609782e2f78d0c53c523a1 [file] [log] [blame]
Harald Weltedbb0f5a2016-10-18 23:51:54 +02001#include <stdio.h>
Harald Welte74d1e342016-10-19 00:06:22 +02002#include <time.h>
Harald Weltef4032322016-10-19 00:23:10 +02003#include <unistd.h>
Harald Weltec1b9cab2016-10-23 19:36:14 +02004#include <string.h>
Harald Welte74d1e342016-10-19 00:06:22 +02005
Harald Weltedbb0f5a2016-10-18 23:51:54 +02006#include <sys/time.h>
Harald Welte41a53002016-11-14 23:22:49 +01007#include <sys/types.h>
Harald Weltedbb0f5a2016-10-18 23:51:54 +02008
Harald Welte1df5cf42016-11-14 21:29:01 +01009#include <osmocom/core/bits.h>
Harald Weltedbb0f5a2016-10-18 23:51:54 +020010#include <osmocom/core/signal.h>
11#include <osmocom/core/logging.h>
Harald Welte41a53002016-11-14 23:22:49 +010012#include <osmocom/core/msgb.h>
Harald Weltedbb0f5a2016-10-18 23:51:54 +020013#include <osmocom/core/application.h>
Harald Welte525af182016-10-19 00:38:46 +020014#include <osmocom/abis/subchan_demux.h>
Harald Welte41a53002016-11-14 23:22:49 +010015#include <osmocom/abis/lapd_pcap.h>
Harald Weltedbb0f5a2016-10-18 23:51:54 +020016
17#include "storage.h"
18#include "recorder.h"
Harald Welte1df5cf42016-11-14 21:29:01 +010019#include "flip_bits.h"
20#include "hdlc.h"
Harald Weltedbb0f5a2016-10-18 23:51:54 +020021
22struct e1_recorder g_recorder;
23
Harald Weltef4032322016-10-19 00:23:10 +020024enum mode {
25 MODE_PRINT,
26 MODE_BIN,
Harald Weltec1b9cab2016-10-23 19:36:14 +020027 MODE_SC,
Harald Weltef4032322016-10-19 00:23:10 +020028};
29
Harald Weltec1b9cab2016-10-23 19:36:14 +020030#define MAX_TS 32
31#define CHUNK_BYTES 160
32
33/* Ericsson super-channel */
34struct sc_state {
35 uint8_t ts_data[MAX_TS][CHUNK_BYTES];
36 uint8_t num_ts;
Harald Welte1df5cf42016-11-14 21:29:01 +010037 uint32_t ts_mask;
38 struct hdlc_proc hdlc;
Harald Weltec1b9cab2016-10-23 19:36:14 +020039};
40
41static struct sc_state g_sc_state[2];
42
Harald Weltef4032322016-10-19 00:23:10 +020043static enum mode g_mode = MODE_PRINT;
44static int g_filter_line = -1;
45static int g_filter_slot = -1;
Harald Welte525af182016-10-19 00:38:46 +020046static int g_filter_subslot = -1;
47static struct osmo_e1cap_pkthdr *g_last_pkthdr;
Harald Welte41a53002016-11-14 23:22:49 +010048static int g_pcap_fd = -1;
49struct msgb *g_pcap_msg = NULL;
Harald Weltef4032322016-10-19 00:23:10 +020050
Harald Welte74d1e342016-10-19 00:06:22 +020051static char *timeval2str(struct timeval *tv)
52{
53 time_t nowtime;
54 struct tm *nowtm;
55 char tmbuf[64];
56 static char buf[64];
57
58 nowtime = tv->tv_sec;
59 nowtm = localtime(&nowtime);
60 strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm);
61 snprintf(buf, sizeof buf, "%s.%06ld", tmbuf, tv->tv_usec);
62 return buf;
63}
64
Harald Weltec1b9cab2016-10-23 19:36:14 +020065static int all_bytes_are(unsigned char ch, const uint8_t *data, int len)
66{
67 int i;
68
69 for (i = 0; i < len; i++) {
70 if (data[i] != ch)
71 return 0;
72 }
73 return 1;
74}
75
Harald Welte41a53002016-11-14 23:22:49 +010076static void handle_hdlc_frame_content(const uint8_t *data, unsigned int len,
77 void *priv)
78{
79 if (g_pcap_fd && len >= 4) {
80 uint8_t *cur = msgb_put(g_pcap_msg, len-2);
81 memcpy(cur, data, len-2);
82 printf("==> %s\n", msgb_hexdump(g_pcap_msg));
83 OSMO_ASSERT(g_pcap_msg->len >= 2);
84 /* FIXME: timestamp! */
85 osmo_pcap_lapd_write(g_pcap_fd, OSMO_LAPD_PCAP_OUTPUT, g_pcap_msg);
86 msgb_reset(g_pcap_msg);
87 }
88}
89
Harald Weltec1b9cab2016-10-23 19:36:14 +020090static void handle_sc_out(struct sc_state *scs)
91{
Harald Welte1df5cf42016-11-14 21:29:01 +010092 unsigned int num_bytes = scs->num_ts * CHUNK_BYTES;
93 unsigned int num_bits = num_bytes * 8;
94 uint8_t out[32*CHUNK_BYTES];
95 ubit_t out_bits[32*CHUNK_BYTES*8];
Harald Weltec1b9cab2016-10-23 19:36:14 +020096 int i, j, k = 0;
97
98 /* re-shuffle the data from columns to lines */
99 for (i = 0; i < CHUNK_BYTES; i++) {
Harald Welte1df5cf42016-11-14 21:29:01 +0100100 for (j = 0; j < scs->num_ts; j++)
Harald Weltec1b9cab2016-10-23 19:36:14 +0200101 out[k++] = scs->ts_data[j][i];
102 }
Harald Welte1df5cf42016-11-14 21:29:01 +0100103 //printf("num_bytes=%u %s\n", num_bytes, osmo_hexdump_nospc(out, num_bytes));
104 osmo_pbit2ubit_ext(out_bits, 0, out, 0, num_bits, 1);
105 //for (i = 0; i < num_bits; i++) fputc(out_bits[i] ? '1' : '.', stdout); fputc('\n', stdout);
106 process_raw_hdlc(&scs->hdlc, out_bits, num_bits);
Harald Weltec1b9cab2016-10-23 19:36:14 +0200107}
108
109static void handle_sc_in(struct osmo_e1cap_pkthdr *pkt, const uint8_t *data, unsigned int len)
110{
111 struct sc_state *scs;
112
113 if (pkt->line_nr >= ARRAY_SIZE(g_sc_state)) {
114 fprintf(stderr, "Line number out of range\n");
115 exit(1);
116 }
117
118 scs = &g_sc_state[pkt->line_nr];
119 if (pkt->ts_nr >= ARRAY_SIZE(scs->ts_data)) {
120 fprintf(stderr, "Timeslot number out of range\n");
121 exit(1);
122 }
123
124 if (len != sizeof(scs->ts_data[pkt->ts_nr])) {
125 fprintf(stderr, "Insufficient data\n");
126 exit(1);
127 }
128
Harald Welte1df5cf42016-11-14 21:29:01 +0100129 if (pkt->ts_nr == 1) {
130 scs->ts_mask = 0;
131 memset(scs->ts_data, 0, sizeof(scs->ts_data));
132 }
133
134 /* copy over the data */
135 memcpy(scs->ts_data[pkt->ts_nr-1], data, len);
136 /* note that we have valid data for the given timeslot */
137 scs->ts_mask |= (1 << (pkt->ts_nr-1));
138
139 /* make sure we know what's the maximum timeslot number */
140 if (pkt->ts_nr > scs->num_ts)
141 scs->num_ts = pkt->ts_nr;
142
143 /* check if we have data for all needed timeslots */
144 uint32_t ts_mask = (1 << scs->num_ts) -1;
145 //printf("num_ts=%u, ts_mask=0x%x, scs_ts_mask=0x%x\n", scs->num_ts, ts_mask, scs->ts_mask);
146 if (scs->ts_mask == ts_mask) {
Harald Weltec1b9cab2016-10-23 19:36:14 +0200147 handle_sc_out(scs);
Harald Welte1df5cf42016-11-14 21:29:01 +0100148 }
Harald Weltec1b9cab2016-10-23 19:36:14 +0200149}
150
151
Harald Welte1df5cf42016-11-14 21:29:01 +0100152static void handle_data(struct osmo_e1cap_pkthdr *pkt, uint8_t *data, int len)
Harald Welte525af182016-10-19 00:38:46 +0200153{
Harald Welte1df5cf42016-11-14 21:29:01 +0100154 flip_buf_bits(data, len);
155#if 0
156 /* filter out all-ff/all-fe/all-7f */
157 if (all_bytes_are(0xff, data, len) ||
158 all_bytes_are(0x7f, data, len) ||
159 all_bytes_are(0x7e, data, len) ||
160 all_bytes_are(0xe7, data, len) ||
161 all_bytes_are(0x3f, data, len) ||
162 all_bytes_are(0xf3, data, len) ||
163 all_bytes_are(0x9f, data, len) ||
164 all_bytes_are(0xf9, data, len) ||
165 all_bytes_are(0xcf, data, len) ||
166 all_bytes_are(0xfc, data, len) ||
167 all_bytes_are(0xfe, data, len))
168 return;
169#endif
170
Harald Welte525af182016-10-19 00:38:46 +0200171 switch (g_mode) {
172 case MODE_PRINT:
173 printf("%s %02u/%02u %u (%u): %s\n",
174 timeval2str(&pkt->ts),
175 pkt->line_nr, pkt->ts_nr, pkt->capture_mode,
176 pkt->len,
177 osmo_hexdump_nospc(data, len));
178 break;
179 case MODE_BIN:
180 write(1, data, len);
181 break;
Harald Weltec1b9cab2016-10-23 19:36:14 +0200182 case MODE_SC:
183 handle_sc_in(pkt, data, len);
184 break;
Harald Welte525af182016-10-19 00:38:46 +0200185 }
186}
187
188static int subch_demux_out_cb(struct subch_demux *dmx, int ch, uint8_t *data,
189 int len, void *c)
190{
191 OSMO_ASSERT(ch == g_filter_subslot);
Harald Welte1df5cf42016-11-14 21:29:01 +0100192
Harald Welte525af182016-10-19 00:38:46 +0200193 handle_data(g_last_pkthdr, data, len);
194
195 return 0;
196}
197
Harald Weltef4032322016-10-19 00:23:10 +0200198static int handle_options(int argc, char **argv)
199{
200 int opt;
201
Harald Welte41a53002016-11-14 23:22:49 +0100202 while ((opt = getopt(argc, argv, "l:s:bSu:p:")) != -1) {
Harald Weltef4032322016-10-19 00:23:10 +0200203 switch (opt) {
Harald Welte525af182016-10-19 00:38:46 +0200204 case 'l': /* Filter on E1 Line Number */
Harald Weltef4032322016-10-19 00:23:10 +0200205 g_filter_line = atoi(optarg);
206 break;
Harald Welte525af182016-10-19 00:38:46 +0200207 case 's': /* Filter on E1 Slot Number */
Harald Weltef4032322016-10-19 00:23:10 +0200208 g_filter_slot = atoi(optarg);
209 break;
Harald Welte525af182016-10-19 00:38:46 +0200210 case 'b': /* Raw binary output mode (for piping) */
Harald Weltef4032322016-10-19 00:23:10 +0200211 g_mode = MODE_BIN;
212 break;
Harald Weltec1b9cab2016-10-23 19:36:14 +0200213 case 'S': /* Super Channel Mode */
214 g_mode = MODE_SC;
215 break;
Harald Welte525af182016-10-19 00:38:46 +0200216 case 'u': /* 16k Sub-channel demux + filter */
217 g_filter_subslot = atoi(optarg);
218 if (g_filter_subslot < 0 || g_filter_subslot > 3)
219 exit(2);
220 break;
Harald Welte41a53002016-11-14 23:22:49 +0100221 case 'p': /* PCAP writing */
222 g_pcap_fd = osmo_pcap_lapd_open(optarg, 0640);
223 if (g_pcap_fd < 0) {
224 perror("opening pcap file");
225 exit(1);
226 }
227 g_pcap_msg = msgb_alloc(1024, "pcap");
228 break;
Harald Weltef4032322016-10-19 00:23:10 +0200229 default:
230 fprintf(stderr, "Unknown option '%c'\n", opt);
231 exit(EXIT_FAILURE);
232 break;
233 }
234 }
235
236 return 0;
237}
238
Harald Welte41a53002016-11-14 23:22:49 +0100239static struct log_info_cat log_categories[] = {
240};
241
242static struct log_info log_info = {
243 .cat = log_categories,
244 .num_cat = ARRAY_SIZE(log_categories),
245};
246
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200247int main(int argc, char **argv)
248{
249 struct osmo_e1cap_file *f;
250 struct osmo_e1cap_pkthdr *pkt;
Harald Weltef4032322016-10-19 00:23:10 +0200251 unsigned long num_pkt = 0;
Harald Welte525af182016-10-19 00:38:46 +0200252 struct subch_demux smux;
Harald Welte41a53002016-11-14 23:22:49 +0100253 int i;
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200254
255 printf("sizeof(timeval) = %zu\n", sizeof(struct timeval));
256 printf("sizeof(osmo_e1cap_pkthdr) = %zu\n", sizeof(*pkt));
257
Harald Welte1df5cf42016-11-14 21:29:01 +0100258 memset(g_sc_state, 0, sizeof(g_sc_state));
Harald Welte41a53002016-11-14 23:22:49 +0100259 for (i = 0; i < ARRAY_SIZE(g_sc_state); i++)
260 g_sc_state[i].hdlc.out_cb = handle_hdlc_frame_content;
Harald Welte1df5cf42016-11-14 21:29:01 +0100261 init_flip_bits();
262
Harald Welte41a53002016-11-14 23:22:49 +0100263 osmo_init_logging(&log_info);
264
Harald Weltef4032322016-10-19 00:23:10 +0200265 handle_options(argc, argv);
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200266
Harald Weltef4032322016-10-19 00:23:10 +0200267 if (optind >= argc) {
268 fprintf(stderr, "Missing input file name\n");
269 exit(2);
270 }
271
272 f = osmo_e1cap_open(NULL, argv[optind++]);
273 if (!f) {
274 fprintf(stderr, "Unable to open input file\n");
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200275 exit(1);
Harald Weltef4032322016-10-19 00:23:10 +0200276 }
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200277
Harald Welte525af182016-10-19 00:38:46 +0200278 if (g_filter_subslot >= 0) {
279 smux.out_cb = subch_demux_out_cb;
280 subch_demux_init(&smux);
281 subch_demux_activate(&smux, g_filter_subslot);
282 }
283
Harald Welte1df5cf42016-11-14 21:29:01 +0100284// printf("hdlc=%s\n", osmo_hexdump(&g_sc_state[0].hdlc, sizeof(g_sc_state[0].hdlc)));
285
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200286 while ((pkt = osmo_e1cap_read_next(f))) {
Harald Weltef4032322016-10-19 00:23:10 +0200287 num_pkt++;
Harald Welte525af182016-10-19 00:38:46 +0200288 g_last_pkthdr = pkt;
Harald Weltef4032322016-10-19 00:23:10 +0200289
290 if (g_filter_line >= 0 && pkt->line_nr != g_filter_line)
291 continue;
292 if (g_filter_slot >= 0 && pkt->ts_nr != g_filter_slot)
293 continue;
294
Harald Welte525af182016-10-19 00:38:46 +0200295 if (g_filter_subslot >= 0) {
296 subch_demux_in(&smux, pkt->data, pkt->len);
297 continue;
Harald Weltef4032322016-10-19 00:23:10 +0200298 }
Harald Welte525af182016-10-19 00:38:46 +0200299
300 handle_data(pkt, pkt->data, pkt->len);
301
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200302 talloc_free(pkt);
303 }
Harald Weltef4032322016-10-19 00:23:10 +0200304
305 fprintf(stderr, "Processed a total of %lu packets\n", num_pkt);
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200306}