blob: dcbd3049116427370adbe361019cef049eea220d [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
arehbein1584b2a2023-10-12 00:20:17 +020049/*! one gsmtap instance */
50struct gsmtap_inst {
51 int ofd_wq_mode; /*!< wait queue mode? This field member may not be changed or moved (backwards compatibility) */
52 struct osmo_wqueue wq; /*!< the wait queue. This field member may not be changed or moved (backwards compatibility) */
53 struct osmo_fd sink_ofd; /*!< file descriptor */
54};
55
56/*! Deprecated, use gsmtap_inst_fd2() instead
57 * \param[in] gti GSMTAP instance
58 * \returns file descriptor of GSMTAP instance */
59int gsmtap_inst_fd(struct gsmtap_inst *gti)
60{
61 return gsmtap_inst_fd2(gti);
62}
63
64/*! obtain the file descriptor associated with a gsmtap instance
65 * \param[in] gti GSMTAP instance
66 * \returns file descriptor of GSMTAP instance */
67int gsmtap_inst_fd2(const struct gsmtap_inst *gti)
68{
69 return gti->wq.bfd.fd;
70}
Harald Welte47379ca2011-08-17 16:35:24 +020071
Neels Hofmeyr87e45502017-06-20 00:17:59 +020072/*! convert RSL channel number to GSMTAP channel type
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +010073 * \param[in] rsl_chantype RSL channel type
Harald Welte47379ca2011-08-17 16:35:24 +020074 * \param[in] link_id RSL link identifier
Harald Welte67733042020-03-08 17:21:29 +010075 * \param[in] user_plane Is this voice/csd user plane (1) or signaling (0)
Harald Welte47379ca2011-08-17 16:35:24 +020076 * \returns GSMTAP channel type
77 */
Harald Welte67733042020-03-08 17:21:29 +010078uint8_t chantype_rsl2gsmtap2(uint8_t rsl_chantype, uint8_t link_id, bool user_plane)
Harald Weltee779c362010-06-29 20:51:13 +020079{
80 uint8_t ret = GSMTAP_CHANNEL_UNKNOWN;
81
82 switch (rsl_chantype) {
83 case RSL_CHAN_Bm_ACCHs:
Vadim Yanitskiyfc02ff42021-05-26 18:19:03 +020084 case RSL_CHAN_OSMO_VAMOS_Bm_ACCHs:
Harald Welte67733042020-03-08 17:21:29 +010085 if (user_plane)
86 ret = GSMTAP_CHANNEL_VOICE_F;
87 else
88 ret = GSMTAP_CHANNEL_FACCH_F;
Harald Weltee779c362010-06-29 20:51:13 +020089 break;
90 case RSL_CHAN_Lm_ACCHs:
Vadim Yanitskiyfc02ff42021-05-26 18:19:03 +020091 case RSL_CHAN_OSMO_VAMOS_Lm_ACCHs:
Harald Welte67733042020-03-08 17:21:29 +010092 if (user_plane)
93 ret = GSMTAP_CHANNEL_VOICE_H;
94 else
95 ret = GSMTAP_CHANNEL_FACCH_H;
Harald Weltee779c362010-06-29 20:51:13 +020096 break;
97 case RSL_CHAN_SDCCH4_ACCH:
98 ret = GSMTAP_CHANNEL_SDCCH4;
99 break;
100 case RSL_CHAN_SDCCH8_ACCH:
101 ret = GSMTAP_CHANNEL_SDCCH8;
102 break;
103 case RSL_CHAN_BCCH:
104 ret = GSMTAP_CHANNEL_BCCH;
105 break;
106 case RSL_CHAN_RACH:
107 ret = GSMTAP_CHANNEL_RACH;
108 break;
109 case RSL_CHAN_PCH_AGCH:
110 /* it could also be AGCH... */
111 ret = GSMTAP_CHANNEL_PCH;
112 break;
Harald Welte3b7cd0b2017-07-27 14:12:15 +0200113 case RSL_CHAN_OSMO_PDCH:
114 ret = GSMTAP_CHANNEL_PDCH;
115 break;
Harald Welteac7fabe2020-02-26 17:24:02 +0100116 case RSL_CHAN_OSMO_CBCH4:
117 ret = GSMTAP_CHANNEL_CBCH51;
118 break;
119 case RSL_CHAN_OSMO_CBCH8:
120 ret = GSMTAP_CHANNEL_CBCH52;
121 break;
Harald Weltee779c362010-06-29 20:51:13 +0200122 }
123
124 if (link_id & 0x40)
125 ret |= GSMTAP_CHANNEL_ACCH;
126
127 return ret;
128}
129
Harald Welte67733042020-03-08 17:21:29 +0100130/*! convert RSL channel number to GSMTAP channel type
131 * \param[in] rsl_chantype RSL channel type
132 * \param[in] link_id RSL link identifier
133 * \returns GSMTAP channel type
134 */
135uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
136{
137 return chantype_rsl2gsmtap2(rsl_chantype, link_id, false);
138}
139
Harald Welte93713a52017-07-12 23:43:40 +0200140/*! convert GSMTAP channel type to RSL channel number + Link ID
141 * \param[in] gsmtap_chantype GSMTAP channel type
142 * \param[out] rsl_chantype RSL channel mumber
143 * \param[out] link_id RSL link identifier
144 */
145void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype,
146 uint8_t *link_id)
147{
148 switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) {
Harald Welte67733042020-03-08 17:21:29 +0100149 case GSMTAP_CHANNEL_FACCH_F:
150 case GSMTAP_CHANNEL_VOICE_F: // TCH/F
Harald Welte93713a52017-07-12 23:43:40 +0200151 *rsl_chantype = RSL_CHAN_Bm_ACCHs;
152 break;
Harald Welte67733042020-03-08 17:21:29 +0100153 case GSMTAP_CHANNEL_FACCH_H:
154 case GSMTAP_CHANNEL_VOICE_H: // TCH/H
Harald Welte93713a52017-07-12 23:43:40 +0200155 *rsl_chantype = RSL_CHAN_Lm_ACCHs;
156 break;
157 case GSMTAP_CHANNEL_SDCCH4: // SDCCH/4
158 *rsl_chantype = RSL_CHAN_SDCCH4_ACCH;
159 break;
160 case GSMTAP_CHANNEL_SDCCH8: // SDCCH/8
161 *rsl_chantype = RSL_CHAN_SDCCH8_ACCH;
162 break;
163 case GSMTAP_CHANNEL_BCCH: // BCCH
164 *rsl_chantype = RSL_CHAN_BCCH;
165 break;
166 case GSMTAP_CHANNEL_RACH: // RACH
167 *rsl_chantype = RSL_CHAN_RACH;
168 break;
169 case GSMTAP_CHANNEL_PCH: // PCH
170 case GSMTAP_CHANNEL_AGCH: // AGCH
171 *rsl_chantype = RSL_CHAN_PCH_AGCH;
172 break;
173 case GSMTAP_CHANNEL_PDCH:
Harald Welte3b7cd0b2017-07-27 14:12:15 +0200174 *rsl_chantype = RSL_CHAN_OSMO_PDCH;
Harald Welte93713a52017-07-12 23:43:40 +0200175 break;
176 }
177
178 *link_id = gsmtap_chantype & GSMTAP_CHANNEL_ACCH ? 0x40 : 0x00;
179}
180
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200181/*! create an arbitrary type GSMTAP message
Sylvain Munautabf66e72011-09-26 13:23:19 +0200182 * \param[in] type The GSMTAP_TYPE_xxx constant of the message to create
Harald Welte47379ca2011-08-17 16:35:24 +0200183 * \param[in] arfcn GSM ARFCN (Channel Number)
184 * \param[in] ts GSM time slot
185 * \param[in] chan_type Channel Type
186 * \param[in] ss Sub-slot
187 * \param[in] fn GSM Frame Number
188 * \param[in] signal_dbm Signal Strength (dBm)
189 * \param[in] snr Signal/Noise Ratio (SNR)
190 * \param[in] data Pointer to data buffer
191 * \param[in] len Length of \ref data
Pau Espin Pedrol9a5d90a2020-06-30 18:16:33 +0200192 * \return dynamically allocated message buffer containing data
Harald Welte47379ca2011-08-17 16:35:24 +0200193 *
194 * This function will allocate a new msgb and fill it with a GSMTAP
195 * header containing the information
196 */
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200197struct msgb *gsmtap_makemsg_ex(uint8_t type, uint16_t arfcn, uint8_t ts, uint8_t chan_type,
Harald Weltee34a9402010-06-29 22:31:21 +0200198 uint8_t ss, uint32_t fn, int8_t signal_dbm,
Vadim Yanitskiy833e8fa2021-01-04 17:40:05 +0100199 int8_t snr, const uint8_t *data, unsigned int len)
Harald Weltee779c362010-06-29 20:51:13 +0200200{
201 struct msgb *msg;
202 struct gsmtap_hdr *gh;
203 uint8_t *dst;
204
Harald Weltee779c362010-06-29 20:51:13 +0200205 msg = msgb_alloc(sizeof(*gh) + len, "gsmtap_tx");
206 if (!msg)
Harald Weltee34a9402010-06-29 22:31:21 +0200207 return NULL;
Harald Weltee779c362010-06-29 20:51:13 +0200208
209 gh = (struct gsmtap_hdr *) msgb_put(msg, sizeof(*gh));
210
211 gh->version = GSMTAP_VERSION;
212 gh->hdr_len = sizeof(*gh)/4;
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200213 gh->type = type;
Harald Weltee779c362010-06-29 20:51:13 +0200214 gh->timeslot = ts;
215 gh->sub_slot = ss;
Harald Welte95871da2017-05-15 12:11:36 +0200216 gh->arfcn = osmo_htons(arfcn);
Harald Weltee779c362010-06-29 20:51:13 +0200217 gh->snr_db = snr;
218 gh->signal_dbm = signal_dbm;
Harald Welte95871da2017-05-15 12:11:36 +0200219 gh->frame_number = osmo_htonl(fn);
Harald Weltee779c362010-06-29 20:51:13 +0200220 gh->sub_type = chan_type;
221 gh->antenna_nr = 0;
222
223 dst = msgb_put(msg, len);
224 memcpy(dst, data, len);
225
Harald Weltee34a9402010-06-29 22:31:21 +0200226 return msg;
227}
228
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200229/*! create L1/L2 data and put it into GSMTAP
Sylvain Munautabf66e72011-09-26 13:23:19 +0200230 * \param[in] arfcn GSM ARFCN (Channel Number)
231 * \param[in] ts GSM time slot
232 * \param[in] chan_type Channel Type
233 * \param[in] ss Sub-slot
234 * \param[in] fn GSM Frame Number
235 * \param[in] signal_dbm Signal Strength (dBm)
236 * \param[in] snr Signal/Noise Ratio (SNR)
237 * \param[in] data Pointer to data buffer
238 * \param[in] len Length of \ref data
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200239 * \return message buffer or NULL in case of error
Sylvain Munautabf66e72011-09-26 13:23:19 +0200240 *
241 * This function will allocate a new msgb and fill it with a GSMTAP
242 * header containing the information
243 */
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200244struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type,
245 uint8_t ss, uint32_t fn, int8_t signal_dbm,
Vadim Yanitskiy833e8fa2021-01-04 17:40:05 +0100246 int8_t snr, const uint8_t *data, unsigned int len)
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200247{
248 return gsmtap_makemsg_ex(GSMTAP_TYPE_UM, arfcn, ts, chan_type,
249 ss, fn, signal_dbm, snr, data, len);
250}
251
Harald Weltee4764422011-05-22 12:25:57 +0200252#ifdef HAVE_SYS_SOCKET_H
253
254#include <sys/socket.h>
255#include <netinet/in.h>
256
Philipp Maierce4a8652023-02-20 10:29:49 +0100257/*! Create a new (sending) GSMTAP source socket
Harald Welte47379ca2011-08-17 16:35:24 +0200258 * \param[in] host host name or IP address in string format
259 * \param[in] port UDP port number in host byte order
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200260 * \return file descriptor of the new socket
Harald Welte47379ca2011-08-17 16:35:24 +0200261 *
Maxef5d3bc2023-02-18 23:48:27 +0300262 * Opens a GSMTAP source (sending) socket, connect it to host/port and
Harald Welte47379ca2011-08-17 16:35:24 +0200263 * return resulting fd. If \a host is NULL, the destination address
264 * will be localhost. If \a port is 0, the default \ref
265 * GSMTAP_UDP_PORT will be used.
266 * */
Harald Welte33cb71a2011-05-21 18:54:32 +0200267int gsmtap_source_init_fd(const char *host, uint16_t port)
268{
269 if (port == 0)
270 port = GSMTAP_UDP_PORT;
271 if (host == NULL)
272 host = "localhost";
273
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200274 return osmo_sock_init(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, host, port,
275 OSMO_SOCK_F_CONNECT);
Harald Welte33cb71a2011-05-21 18:54:32 +0200276}
277
Maxa747d362023-02-18 23:45:42 +0300278/*! Create a new (sending) GSMTAP source socket
279 * \param[in] local_host local host name or IP address in string format
280 * \param[in] local_port local UDP port number in host byte order
281 * \param[in] rem_host remote host name or IP address in string format
282 * \param[in] rem_port remote UDP port number in host byte order
283 * \return file descriptor of the new socket
284 *
285 * Opens a GSMTAP source (sending) socket, connect it to remote host/port,
286 * bind to local host/port and return resulting fd.
287 * If \a local_host is NULL, the default address is used.
288 * If \a local_port is 0, than random unused port will be selected by OS.
289 * If \a rem_host is NULL, the destination address will be localhost.
290 * If \a rem_port is 0, the default \ref GSMTAP_UDP_PORT will be used.
291 */
292int gsmtap_source_init_fd2(const char *local_host, uint16_t local_port, const char *rem_host, uint16_t rem_port)
293{
294 if (!local_host)
295 return gsmtap_source_init_fd(rem_host, rem_port);
296
297 return osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, local_host, local_port,
298 rem_host ? rem_host : "localhost", rem_port ? rem_port : GSMTAP_UDP_PORT,
299 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
300}
301
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200302/*! Add a local sink to an existing GSMTAP source and return fd
Harald Weltede6e4982012-12-06 21:25:27 +0100303 * \param[in] gsmtap_fd file descriptor of the gsmtap socket
304 * \returns file descriptor of locally bound receive socket
305 *
306 * In case the GSMTAP socket is connected to a local destination
307 * IP/port, this function creates a corresponding receiving socket
308 * bound to that destination IP + port.
309 *
310 * In case the gsmtap socket is not connected to a local IP/port, or
311 * creation of the receiving socket fails, a negative error code is
312 * returned.
313 */
Harald Welte33cb71a2011-05-21 18:54:32 +0200314int gsmtap_source_add_sink_fd(int gsmtap_fd)
315{
316 struct sockaddr_storage ss;
317 socklen_t ss_len = sizeof(ss);
318 int rc;
319
320 rc = getpeername(gsmtap_fd, (struct sockaddr *)&ss, &ss_len);
321 if (rc < 0)
322 return rc;
323
324 if (osmo_sockaddr_is_local((struct sockaddr *)&ss, ss_len) == 1) {
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200325 rc = osmo_sock_init_sa((struct sockaddr *)&ss, SOCK_DGRAM,
Philipp Maierb8a91622018-08-23 20:18:55 +0200326 IPPROTO_UDP,
327 OSMO_SOCK_F_BIND |
328 OSMO_SOCK_F_UDP_REUSEADDR);
Harald Welte33cb71a2011-05-21 18:54:32 +0200329 if (rc >= 0)
330 return rc;
331 }
332
333 return -ENODEV;
334}
335
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200336/*! Send a \ref msgb through a GSMTAP source
Harald Welte47379ca2011-08-17 16:35:24 +0200337 * \param[in] gti GSMTAP instance
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100338 * \param[in] msg message buffer
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200339 * \return 0 in case of success; negative in case of error
Neels Hofmeyrc9a4ce62018-02-16 01:23:29 +0100340 * NOTE: in case of nonzero return value, the *caller* must free the msg!
341 * (This enables the caller to attempt re-sending the message.)
342 * If 0 is returned, the msgb was freed by this function.
Harald Welte47379ca2011-08-17 16:35:24 +0200343 */
Harald Welte33cb71a2011-05-21 18:54:32 +0200344int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg)
345{
Harald Welte13692a62011-05-22 20:06:11 +0200346 if (!gti)
347 return -ENODEV;
348
Harald Welte33cb71a2011-05-21 18:54:32 +0200349 if (gti->ofd_wq_mode)
350 return osmo_wqueue_enqueue(&gti->wq, msg);
351 else {
352 /* try immediate send and return error if any */
353 int rc;
354
arehbein1584b2a2023-10-12 00:20:17 +0200355 rc = write(gsmtap_inst_fd2(gti), msg->data, msg->len);
Neels Hofmeyr90539ac2018-02-16 01:24:03 +0100356 if (rc < 0) {
Harald Welte33cb71a2011-05-21 18:54:32 +0200357 return rc;
358 } else if (rc >= msg->len) {
359 msgb_free(msg);
360 return 0;
361 } else {
362 /* short write */
363 return -EIO;
364 }
365 }
366}
367
Harald Welte9e34f082021-11-25 15:35:50 +0100368/*! Send a \ref msgb through a GSMTAP source; free the message even if tx queue full.
369 * \param[in] gti GSMTAP instance
370 * \param[in] msg message buffer; always freed, caller must not reference it later.
371 * \return 0 in case of success; negative in case of error
372 */
373int gsmtap_sendmsg_free(struct gsmtap_inst *gti, struct msgb *msg)
374{
375 int rc;
376 rc = gsmtap_sendmsg(gti, msg);
377 if (rc < 0)
378 msgb_free(msg);
379 return rc;
380}
381
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200382/*! send an arbitrary type through GSMTAP.
Sylvain Munautabf66e72011-09-26 13:23:19 +0200383 * See \ref gsmtap_makemsg_ex for arguments
384 */
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200385int gsmtap_send_ex(struct gsmtap_inst *gti, uint8_t type, uint16_t arfcn, uint8_t ts,
Harald Welte33cb71a2011-05-21 18:54:32 +0200386 uint8_t chan_type, uint8_t ss, uint32_t fn,
Vadim Yanitskiy833e8fa2021-01-04 17:40:05 +0100387 int8_t signal_dbm, int8_t snr, const uint8_t *data,
Harald Welte33cb71a2011-05-21 18:54:32 +0200388 unsigned int len)
Harald Weltee34a9402010-06-29 22:31:21 +0200389{
390 struct msgb *msg;
Neels Hofmeyra4952aa2018-02-16 01:26:00 +0100391 int rc;
Harald Weltee34a9402010-06-29 22:31:21 +0200392
Harald Welte13692a62011-05-22 20:06:11 +0200393 if (!gti)
394 return -ENODEV;
395
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200396 msg = gsmtap_makemsg_ex(type, arfcn, ts, chan_type, ss, fn, signal_dbm,
Harald Weltee34a9402010-06-29 22:31:21 +0200397 snr, data, len);
398 if (!msg)
399 return -ENOMEM;
400
Neels Hofmeyra4952aa2018-02-16 01:26:00 +0100401 rc = gsmtap_sendmsg(gti, msg);
402 if (rc)
403 msgb_free(msg);
404 return rc;
Harald Weltee779c362010-06-29 20:51:13 +0200405}
406
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200407/*! send a message from L1/L2 through GSMTAP.
Sylvain Munautabf66e72011-09-26 13:23:19 +0200408 * See \ref gsmtap_makemsg for arguments
409 */
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200410int gsmtap_send(struct gsmtap_inst *gti, uint16_t arfcn, uint8_t ts,
411 uint8_t chan_type, uint8_t ss, uint32_t fn,
Vadim Yanitskiy833e8fa2021-01-04 17:40:05 +0100412 int8_t signal_dbm, int8_t snr, const uint8_t *data,
Sylvain Munaut15ae7152011-09-26 13:05:07 +0200413 unsigned int len)
414{
415 return gsmtap_send_ex(gti, GSMTAP_TYPE_UM, arfcn, ts, chan_type, ss, fn,
416 signal_dbm, snr, data, len);
417}
418
Harald Weltee779c362010-06-29 20:51:13 +0200419/* Callback from select layer if we can write to the socket */
Harald Welte33cb71a2011-05-21 18:54:32 +0200420static int gsmtap_wq_w_cb(struct osmo_fd *ofd, struct msgb *msg)
Harald Weltee779c362010-06-29 20:51:13 +0200421{
Harald Weltee779c362010-06-29 20:51:13 +0200422 int rc;
423
Harald Welte33cb71a2011-05-21 18:54:32 +0200424 rc = write(ofd->fd, msg->data, msg->len);
Harald Weltee779c362010-06-29 20:51:13 +0200425 if (rc < 0) {
Harald Weltee779c362010-06-29 20:51:13 +0200426 return rc;
427 }
428 if (rc != msg->len) {
Harald Weltee779c362010-06-29 20:51:13 +0200429 return -EIO;
430 }
431
Harald Weltee779c362010-06-29 20:51:13 +0200432 return 0;
433}
434
Harald Welted58ba462011-04-27 10:57:49 +0200435/* Callback from select layer if we can read from the sink socket */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200436static int gsmtap_sink_fd_cb(struct osmo_fd *fd, unsigned int flags)
Harald Welted58ba462011-04-27 10:57:49 +0200437{
438 int rc;
439 uint8_t buf[4096];
440
Harald Welte16886992019-03-20 10:26:39 +0100441 if (!(flags & OSMO_FD_READ))
Harald Welted58ba462011-04-27 10:57:49 +0200442 return 0;
443
444 rc = read(fd->fd, buf, sizeof(buf));
445 if (rc < 0) {
Harald Welted58ba462011-04-27 10:57:49 +0200446 return rc;
447 }
448 /* simply discard any data arriving on the socket */
449
450 return 0;
451}
452
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200453/*! Add a local sink to an existing GSMTAP source and return fd
Vadim Yanitskiy2f65bb12019-03-25 15:57:09 +0700454 * \param[in] gti existing GSMTAP source
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200455 * \returns file descriptor of locally bound receive socket
456 *
457 * In case the GSMTAP socket is connected to a local destination
458 * IP/port, this function creates a corresponding receiving socket
459 * bound to that destination IP + port.
460 *
461 * In case the gsmtap socket is not connected to a local IP/port, or
462 * creation of the receiving socket fails, a negative error code is
463 * returned.
464 *
465 * The file descriptor of the receiving socket is automatically added
466 * to the libosmocore select() handling.
467 */
Harald Welte33cb71a2011-05-21 18:54:32 +0200468int gsmtap_source_add_sink(struct gsmtap_inst *gti)
Harald Welted58ba462011-04-27 10:57:49 +0200469{
Harald Welte9d862c82016-11-26 00:10:07 +0100470 int fd, rc;
Harald Welted58ba462011-04-27 10:57:49 +0200471
arehbein1584b2a2023-10-12 00:20:17 +0200472 fd = gsmtap_source_add_sink_fd(gsmtap_inst_fd2(gti));
Harald Welte33cb71a2011-05-21 18:54:32 +0200473 if (fd < 0)
474 return fd;
Harald Welted58ba462011-04-27 10:57:49 +0200475
Harald Welte33cb71a2011-05-21 18:54:32 +0200476 if (gti->ofd_wq_mode) {
477 struct osmo_fd *sink_ofd;
478
479 sink_ofd = &gti->sink_ofd;
480 sink_ofd->fd = fd;
Harald Welte16886992019-03-20 10:26:39 +0100481 sink_ofd->when = OSMO_FD_READ;
Harald Welte33cb71a2011-05-21 18:54:32 +0200482 sink_ofd->cb = gsmtap_sink_fd_cb;
483
Harald Welte9d862c82016-11-26 00:10:07 +0100484 rc = osmo_fd_register(sink_ofd);
485 if (rc < 0) {
486 close(fd);
487 return rc;
488 }
Harald Welted58ba462011-04-27 10:57:49 +0200489 }
490
Harald Welte33cb71a2011-05-21 18:54:32 +0200491 return fd;
492}
Harald Welted58ba462011-04-27 10:57:49 +0200493
Harald Welte47379ca2011-08-17 16:35:24 +0200494
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200495/*! Open GSMTAP source socket, connect and register osmo_fd
Maxedb5f332023-02-25 16:33:52 +0300496 * \param[in] local_host IP address in string format
497 * \param[in] local_port UDP port number in host byte order
498 * \param[in] rem_host host name or IP address in string format
499 * \param[in] rem_port UDP port number in host byte order
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100500 * \param[in] ofd_wq_mode Register \ref osmo_wqueue (1) or not (0)
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200501 * \return callee-allocated \ref gsmtap_inst
Harald Welte47379ca2011-08-17 16:35:24 +0200502 *
Maxa747d362023-02-18 23:45:42 +0300503 * Open GSMTAP source (sending) socket, connect it to remote host/port,
504 * bind it local host/port,
Harald Welte47379ca2011-08-17 16:35:24 +0200505 * allocate 'struct gsmtap_inst' and optionally osmo_fd/osmo_wqueue
Vadim Yanitskiy2f65bb12019-03-25 15:57:09 +0700506 * registration.
507 */
Maxa747d362023-02-18 23:45:42 +0300508struct gsmtap_inst *gsmtap_source_init2(const char *local_host, uint16_t local_port,
509 const char *rem_host, uint16_t rem_port, int ofd_wq_mode)
Harald Welte33cb71a2011-05-21 18:54:32 +0200510{
511 struct gsmtap_inst *gti;
Harald Welte9d862c82016-11-26 00:10:07 +0100512 int fd, rc;
Harald Welted58ba462011-04-27 10:57:49 +0200513
Maxa747d362023-02-18 23:45:42 +0300514 fd = gsmtap_source_init_fd2(local_host, local_port, rem_host, rem_port);
Harald Welte33cb71a2011-05-21 18:54:32 +0200515 if (fd < 0)
516 return NULL;
517
518 gti = talloc_zero(NULL, struct gsmtap_inst);
519 gti->ofd_wq_mode = ofd_wq_mode;
520 gti->wq.bfd.fd = fd;
521 gti->sink_ofd.fd = -1;
522
523 if (ofd_wq_mode) {
524 osmo_wqueue_init(&gti->wq, 64);
525 gti->wq.write_cb = &gsmtap_wq_w_cb;
526
Harald Welte9d862c82016-11-26 00:10:07 +0100527 rc = osmo_fd_register(&gti->wq.bfd);
528 if (rc < 0) {
Vadim Yanitskiyb9baf022019-03-24 00:01:27 +0700529 talloc_free(gti);
Harald Welte9d862c82016-11-26 00:10:07 +0100530 close(fd);
531 return NULL;
532 }
Harald Welte33cb71a2011-05-21 18:54:32 +0200533 }
534
535 return gti;
Harald Welted58ba462011-04-27 10:57:49 +0200536}
537
Maxa747d362023-02-18 23:45:42 +0300538/*! Open GSMTAP source socket, connect and register osmo_fd
539 * \param[in] host host name or IP address in string format
540 * \param[in] port UDP port number in host byte order
541 * \param[in] ofd_wq_mode Register \ref osmo_wqueue (1) or not (0)
542 * \return callee-allocated \ref gsmtap_inst
543 *
544 * Open GSMTAP source (sending) socket, connect it to host/port,
545 * allocate 'struct gsmtap_inst' and optionally osmo_fd/osmo_wqueue
546 * registration.
547 */
548struct gsmtap_inst *gsmtap_source_init(const char *host, uint16_t port,
549 int ofd_wq_mode)
550{
551 return gsmtap_source_init2(NULL, 0, host, port, ofd_wq_mode);
552}
553
Vadim Yanitskiy2f4186a2021-12-29 21:58:19 +0600554void gsmtap_source_free(struct gsmtap_inst *gti)
555{
Harald Welte3ef61202023-06-28 20:04:16 +0200556 if (!gti)
557 return;
558
Vadim Yanitskiy2f4186a2021-12-29 21:58:19 +0600559 if (gti->ofd_wq_mode) {
560 osmo_fd_unregister(&gti->wq.bfd);
561 osmo_wqueue_clear(&gti->wq);
562
563 if (gti->sink_ofd.fd != -1) {
564 osmo_fd_unregister(&gti->sink_ofd);
565 close(gti->sink_ofd.fd);
566 }
567 }
568
569 close(gti->wq.bfd.fd);
570 talloc_free(gti);
571}
572
Harald Weltee4764422011-05-22 12:25:57 +0200573#endif /* HAVE_SYS_SOCKET_H */
Harald Weltede6e4982012-12-06 21:25:27 +0100574
Harald Welteaa3ba462017-07-13 00:01:02 +0200575const struct value_string gsmtap_gsm_channel_names[] = {
576 { GSMTAP_CHANNEL_UNKNOWN, "UNKNOWN" },
577 { GSMTAP_CHANNEL_BCCH, "BCCH" },
578 { GSMTAP_CHANNEL_CCCH, "CCCH" },
579 { GSMTAP_CHANNEL_RACH, "RACH" },
580 { GSMTAP_CHANNEL_AGCH, "AGCH" },
581 { GSMTAP_CHANNEL_PCH, "PCH" },
582 { GSMTAP_CHANNEL_SDCCH, "SDCCH" },
583 { GSMTAP_CHANNEL_SDCCH4, "SDCCH/4" },
584 { GSMTAP_CHANNEL_SDCCH8, "SDCCH/8" },
Harald Welte67733042020-03-08 17:21:29 +0100585 { GSMTAP_CHANNEL_FACCH_F, "FACCH/F" },
586 { GSMTAP_CHANNEL_FACCH_H, "FACCH/H" },
Harald Welteaa3ba462017-07-13 00:01:02 +0200587 { GSMTAP_CHANNEL_PACCH, "PACCH" },
588 { GSMTAP_CHANNEL_CBCH52, "CBCH" },
589 { GSMTAP_CHANNEL_PDCH, "PDCH" } ,
590 { GSMTAP_CHANNEL_PTCCH, "PTTCH" },
591 { GSMTAP_CHANNEL_CBCH51, "CBCH" },
592 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH, "LSACCH" },
593 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH4, "SACCH/4" },
594 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH8, "SACCH/8" },
Harald Welte67733042020-03-08 17:21:29 +0100595 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_FACCH_F, "SACCH/F" },
596 { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_FACCH_H, "SACCH/H" },
597 { GSMTAP_CHANNEL_VOICE_F, "TCH/F" },
598 { GSMTAP_CHANNEL_VOICE_H, "TCH/H" },
Harald Welteaa3ba462017-07-13 00:01:02 +0200599 { 0, NULL }
600};
601
602/* for debugging */
603const struct value_string gsmtap_type_names[] = {
604 { GSMTAP_TYPE_UM, "GSM Um (MS<->BTS)" },
605 { GSMTAP_TYPE_ABIS, "GSM Abis (BTS<->BSC)" },
606 { GSMTAP_TYPE_UM_BURST, "GSM Um burst (MS<->BTS)" },
607 { GSMTAP_TYPE_SIM, "SIM Card" },
608 { GSMTAP_TYPE_TETRA_I1, "TETRA V+D" },
609 { GSMTAP_TYPE_TETRA_I1_BURST, "TETRA bursts" },
610 { GSMTAP_TYPE_WMX_BURST, "WiMAX burst" },
Vadim Yanitskiy0a60e422023-03-11 03:40:52 +0700611 { GSMTAP_TYPE_GB_LLC, "GPRS Gb LLC" },
612 { GSMTAP_TYPE_GB_SNDCP, "GPRS Gb SNDCP" },
Harald Welteaa3ba462017-07-13 00:01:02 +0200613 { GSMTAP_TYPE_GMR1_UM, "GMR-1 air interfeace (MES-MS<->GTS)"},
614 { GSMTAP_TYPE_UMTS_RLC_MAC, "UMTS RLC/MAC" },
615 { GSMTAP_TYPE_UMTS_RRC, "UMTS RRC" },
616 { GSMTAP_TYPE_LTE_RRC, "LTE RRC" },
617 { GSMTAP_TYPE_LTE_MAC, "LTE MAC" },
618 { GSMTAP_TYPE_LTE_MAC_FRAMED, "LTE MAC with context hdr" },
619 { GSMTAP_TYPE_OSMOCORE_LOG, "libosmocore logging" },
620 { GSMTAP_TYPE_QC_DIAG, "Qualcomm DIAG" },
Vadim Yanitskiy0a60e422023-03-11 03:40:52 +0700621 { GSMTAP_TYPE_LTE_NAS, "LTE Non-Access Stratum" },
622 { GSMTAP_TYPE_E1T1, "E1/T1 lines" },
Harald Welte5e3aaf92023-03-09 18:04:24 +0100623 { GSMTAP_TYPE_GSM_RLP, "GSM Radio Link Protocol" },
Harald Welteaa3ba462017-07-13 00:01:02 +0200624 { 0, NULL }
625};
626
Harald Weltede6e4982012-12-06 21:25:27 +0100627/*! @} */