blob: 33667c306f7633d32df0ffa4a9aedc92f676afd1 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file gsmtap_util.c
2 * GSMTAP support code in libosmocore. */
Harald Weltee779c362010-06-29 20:51:13 +02003/*
Harald Welte93713a52017-07-12 23:43:40 +02004 * (C) 2010-2017 by Harald Welte <laforge@gnumonks.org>
Harald Weltee779c362010-06-29 20:51:13 +02005 *
6 * All Rights Reserved
7 *
Harald Weltee08da972017-11-13 01:00:26 +09008 * SPDX-License-Identifier: GPL-2.0+
9 *
Harald Weltee779c362010-06-29 20:51:13 +020010 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
Harald Weltee779c362010-06-29 20:51:13 +020020 */
21
Pau Espin Pedrol88955fb2023-01-18 18:54:00 +010022#include "config.h"
Harald Weltee779c362010-06-29 20:51:13 +020023
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010024#include <osmocom/core/gsmtap_util.h>
25#include <osmocom/core/logging.h>
26#include <osmocom/core/gsmtap.h>
27#include <osmocom/core/msgb.h>
Harald Welte33cb71a2011-05-21 18:54:32 +020028#include <osmocom/core/talloc.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010029#include <osmocom/core/select.h>
Harald Welte33cb71a2011-05-21 18:54:32 +020030#include <osmocom/core/socket.h>
Harald Welte95871da2017-05-15 12:11:36 +020031#include <osmocom/core/byteswap.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010032#include <osmocom/gsm/protocol/gsm_04_08.h>
33#include <osmocom/gsm/rsl.h>
Harald Weltee779c362010-06-29 20:51:13 +020034
Harald Welte33cb71a2011-05-21 18:54:32 +020035#include <sys/types.h>
Harald Weltee4764422011-05-22 12:25:57 +020036
Harald Weltee779c362010-06-29 20:51:13 +020037#include <stdio.h>
38#include <unistd.h>
39#include <stdint.h>
40#include <string.h>
41#include <errno.h>
42
Harald Welte47379ca2011-08-17 16:35:24 +020043/*! \addtogroup gsmtap
44 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020045 * GSMTAP utility routines. Encapsulates GSM messages over UDP.
46 *
47 * \file gsmtap_util.c */
Harald Welte47379ca2011-08-17 16:35:24 +020048
49
Neels Hofmeyr87e45502017-06-20 00:17:59 +020050/*! convert RSL channel number to GSMTAP channel type
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +010051 * \param[in] rsl_chantype RSL channel type
Harald Welte47379ca2011-08-17 16:35:24 +020052 * \param[in] link_id RSL link identifier
Harald Welte67733042020-03-08 17:21:29 +010053 * \param[in] user_plane Is this voice/csd user plane (1) or signaling (0)
Harald Welte47379ca2011-08-17 16:35:24 +020054 * \returns GSMTAP channel type
55 */
Harald Welte67733042020-03-08 17:21:29 +010056uint8_t chantype_rsl2gsmtap2(uint8_t rsl_chantype, uint8_t link_id, bool user_plane)
Harald Weltee779c362010-06-29 20:51:13 +020057{
58 uint8_t ret = GSMTAP_CHANNEL_UNKNOWN;
59
60 switch (rsl_chantype) {
61 case RSL_CHAN_Bm_ACCHs:
Vadim Yanitskiyfc02ff42021-05-26 18:19:03 +020062 case RSL_CHAN_OSMO_VAMOS_Bm_ACCHs:
Harald Welte67733042020-03-08 17:21:29 +010063 if (user_plane)
64 ret = GSMTAP_CHANNEL_VOICE_F;
65 else
66 ret = GSMTAP_CHANNEL_FACCH_F;
Harald Weltee779c362010-06-29 20:51:13 +020067 break;
68 case RSL_CHAN_Lm_ACCHs:
Vadim Yanitskiyfc02ff42021-05-26 18:19:03 +020069 case RSL_CHAN_OSMO_VAMOS_Lm_ACCHs:
Harald Welte67733042020-03-08 17:21:29 +010070 if (user_plane)
71 ret = GSMTAP_CHANNEL_VOICE_H;
72 else
73 ret = GSMTAP_CHANNEL_FACCH_H;
Harald Weltee779c362010-06-29 20:51:13 +020074 break;
75 case RSL_CHAN_SDCCH4_ACCH:
76 ret = GSMTAP_CHANNEL_SDCCH4;
77 break;
78 case RSL_CHAN_SDCCH8_ACCH:
79 ret = GSMTAP_CHANNEL_SDCCH8;
80 break;
81 case RSL_CHAN_BCCH:
82 ret = GSMTAP_CHANNEL_BCCH;
83 break;
84 case RSL_CHAN_RACH:
85 ret = GSMTAP_CHANNEL_RACH;
86 break;
87 case RSL_CHAN_PCH_AGCH:
88 /* it could also be AGCH... */
89 ret = GSMTAP_CHANNEL_PCH;
90 break;
Harald Welte3b7cd0b2017-07-27 14:12:15 +020091 case RSL_CHAN_OSMO_PDCH:
92 ret = GSMTAP_CHANNEL_PDCH;
93 break;
Harald Welteac7fabe2020-02-26 17:24:02 +010094 case RSL_CHAN_OSMO_CBCH4:
95 ret = GSMTAP_CHANNEL_CBCH51;
96 break;
97 case RSL_CHAN_OSMO_CBCH8:
98 ret = GSMTAP_CHANNEL_CBCH52;
99 break;
Harald Weltee779c362010-06-29 20:51:13 +0200100 }
101
102 if (link_id & 0x40)
103 ret |= GSMTAP_CHANNEL_ACCH;
104
105 return ret;
106}
107
Harald Welte67733042020-03-08 17:21:29 +0100108/*! convert RSL channel number to GSMTAP channel type
109 * \param[in] rsl_chantype RSL channel type
110 * \param[in] link_id RSL link identifier
111 * \returns GSMTAP channel type
112 */
113uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
114{
115 return chantype_rsl2gsmtap2(rsl_chantype, link_id, false);
116}
117
Harald Welte93713a52017-07-12 23:43:40 +0200118/*! convert GSMTAP channel type to RSL channel number + Link ID
119 * \param[in] gsmtap_chantype GSMTAP channel type
120 * \param[out] rsl_chantype RSL channel mumber
121 * \param[out] link_id RSL link identifier
122 */
123void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype,
124 uint8_t *link_id)
125{
126 switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) {
Harald Welte67733042020-03-08 17:21:29 +0100127 case GSMTAP_CHANNEL_FACCH_F:
128 case GSMTAP_CHANNEL_VOICE_F: // TCH/F
Harald Welte93713a52017-07-12 23:43:40 +0200129 *rsl_chantype = RSL_CHAN_Bm_ACCHs;
130 break;
Harald Welte67733042020-03-08 17:21:29 +0100131 case GSMTAP_CHANNEL_FACCH_H:
132 case GSMTAP_CHANNEL_VOICE_H: // TCH/H
Harald Welte93713a52017-07-12 23:43:40 +0200133 *rsl_chantype = RSL_CHAN_Lm_ACCHs;
134 break;
135 case GSMTAP_CHANNEL_SDCCH4: // SDCCH/4
136 *rsl_chantype = RSL_CHAN_SDCCH4_ACCH;
137 break;
138 case GSMTAP_CHANNEL_SDCCH8: // SDCCH/8
139 *rsl_chantype = RSL_CHAN_SDCCH8_ACCH;
140 break;
141 case GSMTAP_CHANNEL_BCCH: // BCCH
142 *rsl_chantype = RSL_CHAN_BCCH;
143 break;
144 case GSMTAP_CHANNEL_RACH: // RACH
145 *rsl_chantype = RSL_CHAN_RACH;
146 break;
147 case GSMTAP_CHANNEL_PCH: // PCH
148 case GSMTAP_CHANNEL_AGCH: // AGCH
149 *rsl_chantype = RSL_CHAN_PCH_AGCH;
150 break;
151 case GSMTAP_CHANNEL_PDCH:
Harald Welte3b7cd0b2017-07-27 14:12:15 +0200152 *rsl_chantype = RSL_CHAN_OSMO_PDCH;
Harald Welte93713a52017-07-12 23:43:40 +0200153 break;
154 }
155
156 *link_id = gsmtap_chantype & GSMTAP_CHANNEL_ACCH ? 0x40 : 0x00;
157}
158
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200159/*! create an arbitrary type GSMTAP message
Sylvain Munautabf66e72011-09-26 13:23:19 +0200160 * \param[in] type The GSMTAP_TYPE_xxx constant of the message to create
Harald Welte47379ca2011-08-17 16:35:24 +0200161 * \param[in] arfcn GSM ARFCN (Channel Number)
162 * \param[in] ts GSM time slot
163 * \param[in] chan_type Channel Type
164 * \param[in] ss Sub-slot
165 * \param[in] fn GSM Frame Number
166 * \param[in] signal_dbm Signal Strength (dBm)
167 * \param[in] snr Signal/Noise Ratio (SNR)
168 * \param[in] data Pointer to data buffer
169 * \param[in] len Length of \ref data
Pau Espin Pedrol9a5d90a2020-06-30 18:16:33 +0200170 * \return dynamically allocated message buffer containing data
Harald Welte47379ca2011-08-17 16:35:24 +0200171 *
172 * This function will allocate a new msgb and fill it with a GSMTAP
173 * header containing the information
174 */
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200175struct msgb *gsmtap_makemsg_ex(uint8_t type, uint16_t arfcn, uint8_t ts, uint8_t chan_type,
Harald Weltee34a9402010-06-29 22:31:21 +0200176 uint8_t ss, uint32_t fn, int8_t signal_dbm,
Vadim Yanitskiy833e8fa2021-01-04 17:40:05 +0100177 int8_t snr, const uint8_t *data, unsigned int len)
Harald Weltee779c362010-06-29 20:51:13 +0200178{
179 struct msgb *msg;
180 struct gsmtap_hdr *gh;
181 uint8_t *dst;
182
Harald Weltee779c362010-06-29 20:51:13 +0200183 msg = msgb_alloc(sizeof(*gh) + len, "gsmtap_tx");
184 if (!msg)
Harald Weltee34a9402010-06-29 22:31:21 +0200185 return NULL;
Harald Weltee779c362010-06-29 20:51:13 +0200186
187 gh = (struct gsmtap_hdr *) msgb_put(msg, sizeof(*gh));
188
189 gh->version = GSMTAP_VERSION;
190 gh->hdr_len = sizeof(*gh)/4;
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200191 gh->type = type;
Harald Weltee779c362010-06-29 20:51:13 +0200192 gh->timeslot = ts;
193 gh->sub_slot = ss;
Harald Welte95871da2017-05-15 12:11:36 +0200194 gh->arfcn = osmo_htons(arfcn);
Harald Weltee779c362010-06-29 20:51:13 +0200195 gh->snr_db = snr;
196 gh->signal_dbm = signal_dbm;
Harald Welte95871da2017-05-15 12:11:36 +0200197 gh->frame_number = osmo_htonl(fn);
Harald Weltee779c362010-06-29 20:51:13 +0200198 gh->sub_type = chan_type;
199 gh->antenna_nr = 0;
200
201 dst = msgb_put(msg, len);
202 memcpy(dst, data, len);
203
Harald Weltee34a9402010-06-29 22:31:21 +0200204 return msg;
205}
206
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200207/*! create L1/L2 data and put it into GSMTAP
Sylvain Munautabf66e72011-09-26 13:23:19 +0200208 * \param[in] arfcn GSM ARFCN (Channel Number)
209 * \param[in] ts GSM time slot
210 * \param[in] chan_type Channel Type
211 * \param[in] ss Sub-slot
212 * \param[in] fn GSM Frame Number
213 * \param[in] signal_dbm Signal Strength (dBm)
214 * \param[in] snr Signal/Noise Ratio (SNR)
215 * \param[in] data Pointer to data buffer
216 * \param[in] len Length of \ref data
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200217 * \return message buffer or NULL in case of error
Sylvain Munautabf66e72011-09-26 13:23:19 +0200218 *
219 * This function will allocate a new msgb and fill it with a GSMTAP
220 * header containing the information
221 */
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200222struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type,
223 uint8_t ss, uint32_t fn, int8_t signal_dbm,
Vadim Yanitskiy833e8fa2021-01-04 17:40:05 +0100224 int8_t snr, const uint8_t *data, unsigned int len)
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200225{
226 return gsmtap_makemsg_ex(GSMTAP_TYPE_UM, arfcn, ts, chan_type,
227 ss, fn, signal_dbm, snr, data, len);
228}
229
Harald Weltee4764422011-05-22 12:25:57 +0200230#ifdef HAVE_SYS_SOCKET_H
231
232#include <sys/socket.h>
233#include <netinet/in.h>
234
Philipp Maierce4a8652023-02-20 10:29:49 +0100235/*! Create a new (sending) GSMTAP source socket
Harald Welte47379ca2011-08-17 16:35:24 +0200236 * \param[in] host host name or IP address in string format
237 * \param[in] port UDP port number in host byte order
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200238 * \return file descriptor of the new socket
Harald Welte47379ca2011-08-17 16:35:24 +0200239 *
Maxef5d3bc2023-02-18 23:48:27 +0300240 * Opens a GSMTAP source (sending) socket, connect it to host/port and
Harald Welte47379ca2011-08-17 16:35:24 +0200241 * return resulting fd. If \a host is NULL, the destination address
242 * will be localhost. If \a port is 0, the default \ref
243 * GSMTAP_UDP_PORT will be used.
244 * */
Harald Welte33cb71a2011-05-21 18:54:32 +0200245int gsmtap_source_init_fd(const char *host, uint16_t port)
246{
247 if (port == 0)
248 port = GSMTAP_UDP_PORT;
249 if (host == NULL)
250 host = "localhost";
251
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200252 return osmo_sock_init(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, host, port,
253 OSMO_SOCK_F_CONNECT);
Harald Welte33cb71a2011-05-21 18:54:32 +0200254}
255
Maxa747d362023-02-18 23:45:42 +0300256/*! Create a new (sending) GSMTAP source socket
257 * \param[in] local_host local host name or IP address in string format
258 * \param[in] local_port local UDP port number in host byte order
259 * \param[in] rem_host remote host name or IP address in string format
260 * \param[in] rem_port remote UDP port number in host byte order
261 * \return file descriptor of the new socket
262 *
263 * Opens a GSMTAP source (sending) socket, connect it to remote host/port,
264 * bind to local host/port and return resulting fd.
265 * If \a local_host is NULL, the default address is used.
266 * If \a local_port is 0, than random unused port will be selected by OS.
267 * If \a rem_host is NULL, the destination address will be localhost.
268 * If \a rem_port is 0, the default \ref GSMTAP_UDP_PORT will be used.
269 */
270int gsmtap_source_init_fd2(const char *local_host, uint16_t local_port, const char *rem_host, uint16_t rem_port)
271{
272 if (!local_host)
273 return gsmtap_source_init_fd(rem_host, rem_port);
274
275 return osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, local_host, local_port,
276 rem_host ? rem_host : "localhost", rem_port ? rem_port : GSMTAP_UDP_PORT,
277 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
278}
279
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200280/*! Add a local sink to an existing GSMTAP source and return fd
Harald Weltede6e4982012-12-06 21:25:27 +0100281 * \param[in] gsmtap_fd file descriptor of the gsmtap socket
282 * \returns file descriptor of locally bound receive socket
283 *
284 * In case the GSMTAP socket is connected to a local destination
285 * IP/port, this function creates a corresponding receiving socket
286 * bound to that destination IP + port.
287 *
288 * In case the gsmtap socket is not connected to a local IP/port, or
289 * creation of the receiving socket fails, a negative error code is
290 * returned.
291 */
Harald Welte33cb71a2011-05-21 18:54:32 +0200292int gsmtap_source_add_sink_fd(int gsmtap_fd)
293{
294 struct sockaddr_storage ss;
295 socklen_t ss_len = sizeof(ss);
296 int rc;
297
298 rc = getpeername(gsmtap_fd, (struct sockaddr *)&ss, &ss_len);
299 if (rc < 0)
300 return rc;
301
302 if (osmo_sockaddr_is_local((struct sockaddr *)&ss, ss_len) == 1) {
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200303 rc = osmo_sock_init_sa((struct sockaddr *)&ss, SOCK_DGRAM,
Philipp Maierb8a91622018-08-23 20:18:55 +0200304 IPPROTO_UDP,
305 OSMO_SOCK_F_BIND |
306 OSMO_SOCK_F_UDP_REUSEADDR);
Harald Welte33cb71a2011-05-21 18:54:32 +0200307 if (rc >= 0)
308 return rc;
309 }
310
311 return -ENODEV;
312}
313
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200314/*! Send a \ref msgb through a GSMTAP source
Harald Welte47379ca2011-08-17 16:35:24 +0200315 * \param[in] gti GSMTAP instance
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100316 * \param[in] msg message buffer
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200317 * \return 0 in case of success; negative in case of error
Neels Hofmeyrc9a4ce62018-02-16 01:23:29 +0100318 * NOTE: in case of nonzero return value, the *caller* must free the msg!
319 * (This enables the caller to attempt re-sending the message.)
320 * If 0 is returned, the msgb was freed by this function.
Harald Welte47379ca2011-08-17 16:35:24 +0200321 */
Harald Welte33cb71a2011-05-21 18:54:32 +0200322int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg)
323{
Harald Welte13692a62011-05-22 20:06:11 +0200324 if (!gti)
325 return -ENODEV;
326
Harald Welte33cb71a2011-05-21 18:54:32 +0200327 if (gti->ofd_wq_mode)
328 return osmo_wqueue_enqueue(&gti->wq, msg);
329 else {
330 /* try immediate send and return error if any */
331 int rc;
332
333 rc = write(gsmtap_inst_fd(gti), msg->data, msg->len);
Neels Hofmeyr90539ac2018-02-16 01:24:03 +0100334 if (rc < 0) {
Harald Welte33cb71a2011-05-21 18:54:32 +0200335 return rc;
336 } else if (rc >= msg->len) {
337 msgb_free(msg);
338 return 0;
339 } else {
340 /* short write */
341 return -EIO;
342 }
343 }
344}
345
Harald Welte9e34f082021-11-25 15:35:50 +0100346/*! Send a \ref msgb through a GSMTAP source; free the message even if tx queue full.
347 * \param[in] gti GSMTAP instance
348 * \param[in] msg message buffer; always freed, caller must not reference it later.
349 * \return 0 in case of success; negative in case of error
350 */
351int gsmtap_sendmsg_free(struct gsmtap_inst *gti, struct msgb *msg)
352{
353 int rc;
354 rc = gsmtap_sendmsg(gti, msg);
355 if (rc < 0)
356 msgb_free(msg);
357 return rc;
358}
359
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200360/*! send an arbitrary type through GSMTAP.
Sylvain Munautabf66e72011-09-26 13:23:19 +0200361 * See \ref gsmtap_makemsg_ex for arguments
362 */
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200363int gsmtap_send_ex(struct gsmtap_inst *gti, uint8_t type, uint16_t arfcn, uint8_t ts,
Harald Welte33cb71a2011-05-21 18:54:32 +0200364 uint8_t chan_type, uint8_t ss, uint32_t fn,
Vadim Yanitskiy833e8fa2021-01-04 17:40:05 +0100365 int8_t signal_dbm, int8_t snr, const uint8_t *data,
Harald Welte33cb71a2011-05-21 18:54:32 +0200366 unsigned int len)
Harald Weltee34a9402010-06-29 22:31:21 +0200367{
368 struct msgb *msg;
Neels Hofmeyra4952aa2018-02-16 01:26:00 +0100369 int rc;
Harald Weltee34a9402010-06-29 22:31:21 +0200370
Harald Welte13692a62011-05-22 20:06:11 +0200371 if (!gti)
372 return -ENODEV;
373
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200374 msg = gsmtap_makemsg_ex(type, arfcn, ts, chan_type, ss, fn, signal_dbm,
Harald Weltee34a9402010-06-29 22:31:21 +0200375 snr, data, len);
376 if (!msg)
377 return -ENOMEM;
378
Neels Hofmeyra4952aa2018-02-16 01:26:00 +0100379 rc = gsmtap_sendmsg(gti, msg);
380 if (rc)
381 msgb_free(msg);
382 return rc;
Harald Weltee779c362010-06-29 20:51:13 +0200383}
384
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200385/*! send a message from L1/L2 through GSMTAP.
Sylvain Munautabf66e72011-09-26 13:23:19 +0200386 * See \ref gsmtap_makemsg for arguments
387 */
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200388int gsmtap_send(struct gsmtap_inst *gti, uint16_t arfcn, uint8_t ts,
389 uint8_t chan_type, uint8_t ss, uint32_t fn,
Vadim Yanitskiy833e8fa2021-01-04 17:40:05 +0100390 int8_t signal_dbm, int8_t snr, const uint8_t *data,
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200391 unsigned int len)
392{
393 return gsmtap_send_ex(gti, GSMTAP_TYPE_UM, arfcn, ts, chan_type, ss, fn,
394 signal_dbm, snr, data, len);
395}
396
Harald Weltee779c362010-06-29 20:51:13 +0200397/* Callback from select layer if we can write to the socket */
Harald Welte33cb71a2011-05-21 18:54:32 +0200398static int gsmtap_wq_w_cb(struct osmo_fd *ofd, struct msgb *msg)
Harald Weltee779c362010-06-29 20:51:13 +0200399{
Harald Weltee779c362010-06-29 20:51:13 +0200400 int rc;
401
Harald Welte33cb71a2011-05-21 18:54:32 +0200402 rc = write(ofd->fd, msg->data, msg->len);
Harald Weltee779c362010-06-29 20:51:13 +0200403 if (rc < 0) {
Harald Weltee779c362010-06-29 20:51:13 +0200404 return rc;
405 }
406 if (rc != msg->len) {
Harald Weltee779c362010-06-29 20:51:13 +0200407 return -EIO;
408 }
409
Harald Weltee779c362010-06-29 20:51:13 +0200410 return 0;
411}
412
Harald Welted58ba462011-04-27 10:57:49 +0200413/* Callback from select layer if we can read from the sink socket */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200414static int gsmtap_sink_fd_cb(struct osmo_fd *fd, unsigned int flags)
Harald Welted58ba462011-04-27 10:57:49 +0200415{
416 int rc;
417 uint8_t buf[4096];
418
Harald Welte16886992019-03-20 10:26:39 +0100419 if (!(flags & OSMO_FD_READ))
Harald Welted58ba462011-04-27 10:57:49 +0200420 return 0;
421
422 rc = read(fd->fd, buf, sizeof(buf));
423 if (rc < 0) {
Harald Welted58ba462011-04-27 10:57:49 +0200424 return rc;
425 }
426 /* simply discard any data arriving on the socket */
427
428 return 0;
429}
430
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200431/*! Add a local sink to an existing GSMTAP source and return fd
Vadim Yanitskiy2f65bb12019-03-25 15:57:09 +0700432 * \param[in] gti existing GSMTAP source
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200433 * \returns file descriptor of locally bound receive socket
434 *
435 * In case the GSMTAP socket is connected to a local destination
436 * IP/port, this function creates a corresponding receiving socket
437 * bound to that destination IP + port.
438 *
439 * In case the gsmtap socket is not connected to a local IP/port, or
440 * creation of the receiving socket fails, a negative error code is
441 * returned.
442 *
443 * The file descriptor of the receiving socket is automatically added
444 * to the libosmocore select() handling.
445 */
Harald Welte33cb71a2011-05-21 18:54:32 +0200446int gsmtap_source_add_sink(struct gsmtap_inst *gti)
Harald Welted58ba462011-04-27 10:57:49 +0200447{
Harald Welte9d862c82016-11-26 00:10:07 +0100448 int fd, rc;
Harald Welted58ba462011-04-27 10:57:49 +0200449
Harald Welte33cb71a2011-05-21 18:54:32 +0200450 fd = gsmtap_source_add_sink_fd(gsmtap_inst_fd(gti));
451 if (fd < 0)
452 return fd;
Harald Welted58ba462011-04-27 10:57:49 +0200453
Harald Welte33cb71a2011-05-21 18:54:32 +0200454 if (gti->ofd_wq_mode) {
455 struct osmo_fd *sink_ofd;
456
457 sink_ofd = &gti->sink_ofd;
458 sink_ofd->fd = fd;
Harald Welte16886992019-03-20 10:26:39 +0100459 sink_ofd->when = OSMO_FD_READ;
Harald Welte33cb71a2011-05-21 18:54:32 +0200460 sink_ofd->cb = gsmtap_sink_fd_cb;
461
Harald Welte9d862c82016-11-26 00:10:07 +0100462 rc = osmo_fd_register(sink_ofd);
463 if (rc < 0) {
464 close(fd);
465 return rc;
466 }
Harald Welted58ba462011-04-27 10:57:49 +0200467 }
468
Harald Welte33cb71a2011-05-21 18:54:32 +0200469 return fd;
470}
Harald Welted58ba462011-04-27 10:57:49 +0200471
Harald Welte47379ca2011-08-17 16:35:24 +0200472
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200473/*! Open GSMTAP source socket, connect and register osmo_fd
Harald Welte47379ca2011-08-17 16:35:24 +0200474 * \param[in] host host name or IP address in string format
475 * \param[in] port UDP port number in host byte order
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100476 * \param[in] ofd_wq_mode Register \ref osmo_wqueue (1) or not (0)
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200477 * \return callee-allocated \ref gsmtap_inst
Harald Welte47379ca2011-08-17 16:35:24 +0200478 *
Maxa747d362023-02-18 23:45:42 +0300479 * Open GSMTAP source (sending) socket, connect it to remote host/port,
480 * bind it local host/port,
Harald Welte47379ca2011-08-17 16:35:24 +0200481 * allocate 'struct gsmtap_inst' and optionally osmo_fd/osmo_wqueue
Vadim Yanitskiy2f65bb12019-03-25 15:57:09 +0700482 * registration.
483 */
Maxa747d362023-02-18 23:45:42 +0300484struct gsmtap_inst *gsmtap_source_init2(const char *local_host, uint16_t local_port,
485 const char *rem_host, uint16_t rem_port, int ofd_wq_mode)
Harald Welte33cb71a2011-05-21 18:54:32 +0200486{
487 struct gsmtap_inst *gti;
Harald Welte9d862c82016-11-26 00:10:07 +0100488 int fd, rc;
Harald Welted58ba462011-04-27 10:57:49 +0200489
Maxa747d362023-02-18 23:45:42 +0300490 fd = gsmtap_source_init_fd2(local_host, local_port, rem_host, rem_port);
Harald Welte33cb71a2011-05-21 18:54:32 +0200491 if (fd < 0)
492 return NULL;
493
494 gti = talloc_zero(NULL, struct gsmtap_inst);
495 gti->ofd_wq_mode = ofd_wq_mode;
496 gti->wq.bfd.fd = fd;
497 gti->sink_ofd.fd = -1;
498
499 if (ofd_wq_mode) {
500 osmo_wqueue_init(&gti->wq, 64);
501 gti->wq.write_cb = &gsmtap_wq_w_cb;
502
Harald Welte9d862c82016-11-26 00:10:07 +0100503 rc = osmo_fd_register(&gti->wq.bfd);
504 if (rc < 0) {
Vadim Yanitskiyb9baf022019-03-24 00:01:27 +0700505 talloc_free(gti);
Harald Welte9d862c82016-11-26 00:10:07 +0100506 close(fd);
507 return NULL;
508 }
Harald Welte33cb71a2011-05-21 18:54:32 +0200509 }
510
511 return gti;
Harald Welted58ba462011-04-27 10:57:49 +0200512}
513
Maxa747d362023-02-18 23:45:42 +0300514/*! Open GSMTAP source socket, connect and register osmo_fd
515 * \param[in] host host name or IP address in string format
516 * \param[in] port UDP port number in host byte order
517 * \param[in] ofd_wq_mode Register \ref osmo_wqueue (1) or not (0)
518 * \return callee-allocated \ref gsmtap_inst
519 *
520 * Open GSMTAP source (sending) socket, connect it to host/port,
521 * allocate 'struct gsmtap_inst' and optionally osmo_fd/osmo_wqueue
522 * registration.
523 */
524struct gsmtap_inst *gsmtap_source_init(const char *host, uint16_t port,
525 int ofd_wq_mode)
526{
527 return gsmtap_source_init2(NULL, 0, host, port, ofd_wq_mode);
528}
529
Vadim Yanitskiy2f4186a2021-12-29 21:58:19 +0600530void gsmtap_source_free(struct gsmtap_inst *gti)
531{
532 if (gti->ofd_wq_mode) {
533 osmo_fd_unregister(&gti->wq.bfd);
534 osmo_wqueue_clear(&gti->wq);
535
536 if (gti->sink_ofd.fd != -1) {
537 osmo_fd_unregister(&gti->sink_ofd);
538 close(gti->sink_ofd.fd);
539 }
540 }
541
542 close(gti->wq.bfd.fd);
543 talloc_free(gti);
544}
545
Harald Weltee4764422011-05-22 12:25:57 +0200546#endif /* HAVE_SYS_SOCKET_H */
Harald Weltede6e4982012-12-06 21:25:27 +0100547
Harald Welteaa3ba462017-07-13 00:01:02 +0200548const struct value_string gsmtap_gsm_channel_names[] = {
549 { GSMTAP_CHANNEL_UNKNOWN, "UNKNOWN" },
550 { GSMTAP_CHANNEL_BCCH, "BCCH" },
551 { GSMTAP_CHANNEL_CCCH, "CCCH" },
552 { GSMTAP_CHANNEL_RACH, "RACH" },
553 { GSMTAP_CHANNEL_AGCH, "AGCH" },
554 { GSMTAP_CHANNEL_PCH, "PCH" },
555 { GSMTAP_CHANNEL_SDCCH, "SDCCH" },
556 { GSMTAP_CHANNEL_SDCCH4, "SDCCH/4" },
557 { GSMTAP_CHANNEL_SDCCH8, "SDCCH/8" },
Harald Welte67733042020-03-08 17:21:29 +0100558 { GSMTAP_CHANNEL_FACCH_F, "FACCH/F" },
559 { GSMTAP_CHANNEL_FACCH_H, "FACCH/H" },
Harald Welteaa3ba462017-07-13 00:01:02 +0200560 { GSMTAP_CHANNEL_PACCH, "PACCH" },
561 { GSMTAP_CHANNEL_CBCH52, "CBCH" },
562 { GSMTAP_CHANNEL_PDCH, "PDCH" } ,
563 { GSMTAP_CHANNEL_PTCCH, "PTTCH" },
564 { GSMTAP_CHANNEL_CBCH51, "CBCH" },
565 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH, "LSACCH" },
566 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH4, "SACCH/4" },
567 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH8, "SACCH/8" },
Harald Welte67733042020-03-08 17:21:29 +0100568 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_FACCH_F, "SACCH/F" },
569 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_FACCH_H, "SACCH/H" },
570 { GSMTAP_CHANNEL_VOICE_F, "TCH/F" },
571 { GSMTAP_CHANNEL_VOICE_H, "TCH/H" },
Harald Welteaa3ba462017-07-13 00:01:02 +0200572 { 0, NULL }
573};
574
575/* for debugging */
576const struct value_string gsmtap_type_names[] = {
577 { GSMTAP_TYPE_UM, "GSM Um (MS<->BTS)" },
578 { GSMTAP_TYPE_ABIS, "GSM Abis (BTS<->BSC)" },
579 { GSMTAP_TYPE_UM_BURST, "GSM Um burst (MS<->BTS)" },
580 { GSMTAP_TYPE_SIM, "SIM Card" },
581 { GSMTAP_TYPE_TETRA_I1, "TETRA V+D" },
582 { GSMTAP_TYPE_TETRA_I1_BURST, "TETRA bursts" },
583 { GSMTAP_TYPE_WMX_BURST, "WiMAX burst" },
584 { GSMTAP_TYPE_GMR1_UM, "GMR-1 air interfeace (MES-MS<->GTS)"},
585 { GSMTAP_TYPE_UMTS_RLC_MAC, "UMTS RLC/MAC" },
586 { GSMTAP_TYPE_UMTS_RRC, "UMTS RRC" },
587 { GSMTAP_TYPE_LTE_RRC, "LTE RRC" },
588 { GSMTAP_TYPE_LTE_MAC, "LTE MAC" },
589 { GSMTAP_TYPE_LTE_MAC_FRAMED, "LTE MAC with context hdr" },
590 { GSMTAP_TYPE_OSMOCORE_LOG, "libosmocore logging" },
591 { GSMTAP_TYPE_QC_DIAG, "Qualcomm DIAG" },
592 { 0, NULL }
593};
594
Harald Weltede6e4982012-12-06 21:25:27 +0100595/*! @} */