James Tavares | 31e8bd7 | 2022-11-14 17:19:10 -0500 | [diff] [blame] | 1 | /* 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 */ |
| 32 | static 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 | */ |
| 40 | int 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 | */ |
| 68 | int 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 | } |