blob: 8aced6a837c87d4068f136039afadfcf6555a5d1 [file] [log] [blame]
James Tavares31e8bd72022-11-14 17:19:10 -05001/* gsmtap - How to encapsulate SIM protocol traces in GSMTAP
2 *
3 * (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16/* among other things, bring in GNU-specific strerror_r() */
17#define _GNU_SOURCE
18
19#include <osmocom/core/gsmtap.h>
20#include <osmocom/core/gsmtap_util.h>
21#include <osmocom/core/logging.h>
22
23#include <errno.h>
24#include <string.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <sys/uio.h>
28
29#include "debug.h"
30
31/*! global GSMTAP instance */
32static struct gsmtap_inst *g_gti;
33
34/*! initialize the global GSMTAP instance for SIM traces
35 *
36 * \param[in] gsmtap_host Hostname to send GSMTAP packets
37 *
38 * \return 0 on success, non-zero on error
39 */
40int bankd_gsmtap_init(const char *gsmtap_host)
41{
42 if (g_gti)
43 return -EEXIST;
44
45 errno = 0;
46 g_gti = gsmtap_source_init(gsmtap_host, GSMTAP_UDP_PORT, 0);
47 if (!g_gti) {
48 LOGP(DGSMTAP, LOGL_ERROR, "unable to initialize GSMTAP\n");
49 return -EIO;
50 }
51 gsmtap_source_add_sink(g_gti);
52
53 LOGP(DGSMTAP, LOGL_INFO, "initialized GSMTAP to %s\n", gsmtap_host);
54
55 return 0;
56}
57
58/*! Log one APDU via the global GSMTAP instance by concatenating mdm_tpdu and sim_tpdu.
59 *
60 * \param[in] sub_type GSMTAP sub-type (GSMTAP_SIM_* constant)
61 * \param[in] mdm_tpdu User-provided buffer with ModemToCard TPDU to log. May be NULL.
62 * \param[in] mdm_tpdu_len Length of ModemToCard TPDU, in bytes.
63 * \param[in] sim_tpdu User-provided buffer with CardToModem TPDU to log. May be NULL.
64 * \param[in] sim_tpdu_len Length of CardToModem TPDU, in bytes.
65 *
66 * \return number of bytes sent on success, -1 on failure
67 */
68int bankd_gsmtap_send_apdu(uint8_t sub_type, const uint8_t *mdm_tpdu, unsigned int mdm_tpdu_len,
69 const uint8_t *sim_tpdu, unsigned int sim_tpdu_len)
70{
71 const struct gsmtap_hdr gh = {
72 .version = GSMTAP_VERSION,
73 .hdr_len = sizeof(struct gsmtap_hdr)/4,
74 .type = GSMTAP_TYPE_SIM,
75 .sub_type = sub_type,
76 };
77
78 struct iovec iov[3];
79 unsigned int cnt = 0;
80
81 iov[cnt].iov_base = (void *)&gh;
82 iov[cnt].iov_len = sizeof(gh);
83 cnt++;
84
85 if (mdm_tpdu && mdm_tpdu_len) {
86 iov[cnt].iov_base = (void *)mdm_tpdu;
87 iov[cnt].iov_len = mdm_tpdu_len;
88 cnt++;
89 }
90
91 if (sim_tpdu && sim_tpdu_len) {
92 iov[cnt].iov_base = (void *)sim_tpdu;
93 iov[cnt].iov_len = sim_tpdu_len;
94 cnt++;
95 }
96
97 LOGP(DGSMTAP, LOGL_DEBUG, "sending APDU sub_type=%u, mdm_tpdu len=%u, sim_tpdu len=%u, iov cnt=%u\n",
98 sub_type, mdm_tpdu_len, sim_tpdu_len, cnt);
99
100 const int rc = writev(gsmtap_inst_fd(g_gti), iov, cnt);
101 if (rc < 0) {
102 char errtxt[128];
103 LOGP(DGSMTAP, LOGL_ERROR, "writev() failed with errno=%d: %s\n", errno, strerror_r(errno,
104 errtxt, sizeof(errtxt)));
105 return rc;
106 }
107
108 return 0;
109}