/* (C) 2018-2020 by Harald Welte * * All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ /* This file contains code shared among all remsim client applications, * including the ifd-handler, which is not an executable program with a main() * function or command line parsing, but a shared library */ #include #include #include #include #include #include #include "rspro_util.h" #include "client.h" #include "debug.h" struct client_config *client_config_init(void *ctx) { struct client_config *cfg = talloc_zero(ctx, struct client_config); if (!cfg) return NULL; cfg->server_host = talloc_strdup(cfg, "127.0.0.1"); cfg->server_port = 9998; cfg->client_id = -1; cfg->client_slot = -1; cfg->gsmtap_host = talloc_strdup(cfg, "127.0.0.1"); cfg->keep_running = false; cfg->usb.vendor_id = -1; cfg->usb.product_id = -1; cfg->usb.config_id = -1; cfg->usb.if_num = -1; cfg->usb.altsetting = 0; cfg->usb.addr = -1; cfg->usb.path = NULL; cfg->atr.data[0] = 0x3B; cfg->atr.data[1] = 0x00; // the shortest simplest ATR possible cfg->atr.len = 2; cfg->atr_ignore_rspro = false; return cfg; }; static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu) { struct bankd_client *bc = bankdc2bankd_client(bankdc); switch (pdu->msg.present) { case RsproPDUchoice_PR_connectClientRes: if (pdu->msg.choice.connectClientRes.identity.type != ComponentType_remsimBankd) { LOGPFSML(bankdc->fi, LOGL_ERROR, "Server connection to a ComponentType(%ld) != RemsimBankd? " "Check your IP/Port configuration\n", pdu->msg.choice.connectClientRes.identity.type); osmo_fsm_inst_dispatch(bankdc->fi, SRVC_E_DISCONNECT, NULL); return -1; } /* Store 'identity' of bankd to in peer_comp_id */ rspro_comp_id_retrieve(&bankdc->peer_comp_id, &pdu->msg.choice.connectClientRes.identity); osmo_fsm_inst_dispatch(bankdc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu); break; case RsproPDUchoice_PR_tpduCardToModem: return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_TPDU, (void *) pdu); case RsproPDUchoice_PR_setAtrReq: return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_ATR, (void *) pdu); case RsproPDUchoice_PR_bankSlotStatusInd: return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_SLOT_STATUS, (void *) pdu); default: LOGPFSML(bankdc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU %s\n", rspro_msgt_name(pdu)); return -1; } return 0; } /* handle incoming messages from server */ static int srvc_handle_rx(struct rspro_server_conn *srvc, const RsproPDU_t *pdu) { struct bankd_client *bc = srvc2bankd_client(srvc); RsproPDU_t *resp; switch (pdu->msg.present) { case RsproPDUchoice_PR_connectClientRes: if (pdu->msg.choice.connectClientRes.identity.type != ComponentType_remsimServer) { LOGPFSML(srvc->fi, LOGL_ERROR, "Server connection to a ComponentType(%ld) != RemsimServer? " "Check your IP/Port configuration\n", pdu->msg.choice.connectClientRes.identity.type); osmo_fsm_inst_dispatch(srvc->fi, SRVC_E_DISCONNECT, NULL); return -1; } /* Store 'identity' of server in srvc->peer_comp_id */ rspro_comp_id_retrieve(&srvc->peer_comp_id, &pdu->msg.choice.connectClientRes.identity); osmo_fsm_inst_dispatch(srvc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu); break; case RsproPDUchoice_PR_configClientIdReq: /* store/set the clientID as instructed by the server */ if (!srvc->clslot) srvc->clslot = talloc_zero(srvc, ClientSlot_t); *srvc->clslot = pdu->msg.choice.configClientIdReq.clientSlot; if (!bc->bankd_conn.clslot) bc->bankd_conn.clslot = talloc_zero(bc, ClientSlot_t); *bc->bankd_conn.clslot = *bc->srv_conn.clslot; /* send response to server */ resp = rspro_gen_ConfigClientIdRes(ResultCode_ok); server_conn_send_rspro(srvc, resp); break; case RsproPDUchoice_PR_configClientBankReq: osmo_fsm_inst_dispatch(bc->main_fi, MF_E_SRVC_CONFIG_BANK, (void *) pdu); break; default: LOGPFSML(srvc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU type: %s\n", rspro_msgt_name(pdu)); return -1; } return 0; } struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software, struct client_config *cfg) { struct bankd_client *bc = talloc_zero(ctx, struct bankd_client); struct rspro_server_conn *srvc, *bankdc; int rc; if (!bc) return NULL; bc->cfg = cfg; bc->main_fi = main_fsm_alloc(bc, bc); if (!bc->main_fi) { LOGP(DMAIN, LOGL_FATAL, "Unable to create main client FSM: %s\n", strerror(errno)); exit(1); } remsim_client_set_clslot(bc, cfg->client_id, cfg->client_slot); /* create and [attempt to] establish connection to remsim-server */ srvc = &bc->srv_conn; srvc->server_host = cfg->server_host; srvc->server_port = cfg->server_port; srvc->handle_rx = srvc_handle_rx; srvc->own_comp_id.type = ComponentType_remsimClient; OSMO_STRLCPY_ARRAY(srvc->own_comp_id.name, name); OSMO_STRLCPY_ARRAY(srvc->own_comp_id.software, software); OSMO_STRLCPY_ARRAY(srvc->own_comp_id.sw_version, PACKAGE_VERSION); rc = server_conn_fsm_alloc(bc, srvc); if (rc < 0) { LOGP(DMAIN, LOGL_FATAL, "Unable to create Server conn FSM: %s\n", strerror(errno)); exit(1); } osmo_fsm_inst_change_parent(srvc->fi, bc->main_fi, MF_E_SRVC_LOST); srvc->parent_conn_evt = MF_E_SRVC_CONNECTED; srvc->parent_disc_evt = MF_E_SRVC_LOST; bankdc = &bc->bankd_conn; /* server_host / server_port are configured from remsim-server */ bankdc->handle_rx = bankd_handle_rx; memcpy(&bankdc->own_comp_id, &srvc->own_comp_id, sizeof(bankdc->own_comp_id)); rc = server_conn_fsm_alloc(bc, bankdc); if (rc < 0) { LOGP(DMAIN, LOGL_FATAL, "Unable to connect bankd conn FSM: %s\n", strerror(errno)); exit(1); } osmo_fsm_inst_update_id(bankdc->fi, "bankd"); osmo_fsm_inst_change_parent(bankdc->fi, bc->main_fi, MF_E_BANKD_LOST); bankdc->parent_conn_evt = MF_E_BANKD_CONNECTED; bankdc->parent_disc_evt = MF_E_BANKD_LOST; return bc; } void remsim_client_set_clslot(struct bankd_client *bc, int client_id, int slot_nr) { if (!bc->srv_conn.clslot) { bc->srv_conn.clslot = talloc_zero(bc, ClientSlot_t); OSMO_ASSERT(bc->srv_conn.clslot); } if (!bc->bankd_conn.clslot) { bc->bankd_conn.clslot = talloc_zero(bc, ClientSlot_t); OSMO_ASSERT(bc->bankd_conn.clslot); } if (client_id >= 0) { bc->srv_conn.clslot->clientId = client_id; bc->bankd_conn.clslot->clientId = client_id; } if (slot_nr >= 0) { bc->srv_conn.clslot->slotNr = slot_nr; bc->bankd_conn.clslot->slotNr = slot_nr; } }