blob: e3f082c1d2c88b171312998bcc2cf8b94c48391d [file] [log] [blame]
Harald Welte3dcdd202019-03-09 13:06:46 +01001/* (C) 2018-2019 by Harald Welte <laforge@gnumonks.org>
2 *
3 * All Rights Reserved
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
Harald Welte3aa901d2018-08-13 18:32:36 +020022
23
Harald Welte0eaa0ef2019-03-02 15:12:42 +010024#include <netinet/in.h>
25#include <arpa/inet.h>
26
Kévin Redonff5db6e2018-10-11 17:16:18 +020027#include <asn_application.h>
28#include <der_encoder.h>
Harald Welte3aa901d2018-08-13 18:32:36 +020029
30#include <osmocom/core/msgb.h>
31#include <osmocom/rspro/RsproPDU.h>
32
Harald Welte137c4402018-08-17 21:25:56 +020033#include "rspro_util.h"
34
Harald Welte57555aa2018-08-17 22:05:06 +020035#define ASN_ALLOC_COPY(out, in) \
36do { \
37 if (in) { \
38 out = CALLOC(1, sizeof(*in)); \
39 OSMO_ASSERT(out); \
40 memcpy(out, in, sizeof(*in)); \
41 } \
42} while (0)
43
44
Harald Welte3aa901d2018-08-13 18:32:36 +020045struct msgb *rspro_msgb_alloc(void)
46{
47 return msgb_alloc_headroom(1024, 8, "RSPRO");
48}
49
50/*! BER-Encode an RSPRO message into msgb.
51 * \param[in] pdu Structure describing RSPRO PDU. Is freed by this function on success
52 * \returns callee-allocated message buffer containing encoded RSPRO PDU; NULL on error.
53 */
54struct msgb *rspro_enc_msg(RsproPDU_t *pdu)
55{
56 struct msgb *msg = rspro_msgb_alloc();
57 asn_enc_rval_t rval;
58
59 if (!msg)
60 return NULL;
61
Harald Weltefd471192018-09-24 14:51:14 +020062 msg->l2h = msg->data;
Harald Welte6b8d4f82018-08-17 22:06:24 +020063 rval = der_encode_to_buffer(&asn_DEF_RsproPDU, pdu, msgb_data(msg), msgb_tailroom(msg));
Harald Welte3aa901d2018-08-13 18:32:36 +020064 if (rval.encoded < 0) {
Harald Weltea2b23c32018-08-17 22:09:06 +020065 fprintf(stderr, "Failed to encode %s\n", rval.failed_type->name);
Harald Welte703d6862018-09-24 17:44:50 +020066 msgb_free(msg);
Harald Welte3aa901d2018-08-13 18:32:36 +020067 return NULL;
68 }
Harald Welted5c5c0b2018-08-17 22:04:01 +020069 msgb_put(msg, rval.encoded);
Harald Welte3aa901d2018-08-13 18:32:36 +020070
71 ASN_STRUCT_FREE(asn_DEF_RsproPDU, pdu);
72
73 return msg;
74}
75
76/* consumes 'msg' _if_ it is successful */
77RsproPDU_t *rspro_dec_msg(struct msgb *msg)
78{
Harald Welte9ebbacc2018-09-24 17:43:39 +020079 RsproPDU_t *pdu = NULL;
Harald Welte3aa901d2018-08-13 18:32:36 +020080 asn_dec_rval_t rval;
81
Harald Welte75852862018-09-24 14:55:34 +020082 printf("decoding %s\n", msgb_hexdump(msg));
83 rval = ber_decode(NULL, &asn_DEF_RsproPDU, (void **) &pdu, msgb_l2(msg), msgb_l2len(msg));
Harald Welte3aa901d2018-08-13 18:32:36 +020084 if (rval.code != RC_OK) {
Harald Welte75852862018-09-24 14:55:34 +020085 fprintf(stderr, "Failed to decode: %d. Consumed %lu of %u bytes\n",
86 rval.code, rval.consumed, msgb_length(msg));
87 msgb_free(msg);
Harald Welte3aa901d2018-08-13 18:32:36 +020088 return NULL;
89 }
90
91 msgb_free(msg);
92
93 return pdu;
94}
95
Harald Welte3aa901d2018-08-13 18:32:36 +020096static void fill_comp_id(ComponentIdentity_t *out, const struct app_comp_id *in)
97{
Harald Welte137c4402018-08-17 21:25:56 +020098 out->type = in->type;
Harald Welte3aa901d2018-08-13 18:32:36 +020099 OCTET_STRING_fromString(&out->name, in->name);
100 OCTET_STRING_fromString(&out->software, in->software);
101 OCTET_STRING_fromString(&out->swVersion, in->sw_version);
102 if (strlen(in->hw_manufacturer))
103 out->hwManufacturer = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName,
104 in->hw_manufacturer, -1);
105 if (strlen(in->hw_model))
106 out->hwModel = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_model, -1);
107 if (strlen(in->hw_serial_nr))
108 out->hwSerialNr = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_serial_nr, -1);
109 if (strlen(in->hw_version))
110 out->hwVersion = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_version, -1);
111 if (strlen(in->fw_version))
112 out->fwVersion = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->fw_version, -1);
113}
114
Harald Welte92bd8812019-03-02 14:52:17 +0100115void string_fromOCTET_STRING(char *out, size_t out_size, const OCTET_STRING_t *in)
116{
Harald Weltef5a0fa32019-03-03 15:44:18 +0100117 if (!in) {
Harald Welte92bd8812019-03-02 14:52:17 +0100118 out[0] = '\0';
Harald Weltef5a0fa32019-03-03 15:44:18 +0100119 return;
120 }
Harald Welte92bd8812019-03-02 14:52:17 +0100121 memcpy(out, in->buf, out_size < in->size ? out_size : in->size);
122 if (in->size < out_size)
123 out[in->size] = '\0';
124 else
125 out[out_size-1] = '\0';
126}
127#define string_fromOCTET_STRING_ARRAY(out, in) string_fromOCTET_STRING(out, ARRAY_SIZE(out), in)
128
129
130void rspro_comp_id_retrieve(struct app_comp_id *out, const ComponentIdentity_t *in)
131{
132 memset(out, 0, sizeof(*out));
133 out->type = in->type;
134 string_fromOCTET_STRING_ARRAY(out->name, &in->name);
135 string_fromOCTET_STRING_ARRAY(out->software, &in->software);
136 string_fromOCTET_STRING_ARRAY(out->sw_version, &in->swVersion);
137 string_fromOCTET_STRING_ARRAY(out->hw_manufacturer, in->hwManufacturer);
138 string_fromOCTET_STRING_ARRAY(out->hw_serial_nr, in->hwSerialNr);
139 string_fromOCTET_STRING_ARRAY(out->hw_version, in->hwVersion);
140 string_fromOCTET_STRING_ARRAY(out->fw_version, in->fwVersion);
141}
142
Harald Welte0eaa0ef2019-03-02 15:12:42 +0100143const char *rspro_IpAddr2str(const IpAddress_t *in)
144{
145 static char buf[128];
146
147 switch (in->present) {
148 case IpAddress_PR_ipv4:
149 return inet_ntop(AF_INET, in->choice.ipv4.buf, buf, sizeof(buf));
150 case IpAddress_PR_ipv6:
151 return inet_ntop(AF_INET6, in->choice.ipv6.buf, buf, sizeof(buf));
152 default:
153 return NULL;
154 }
155}
156
Harald Welte3aa901d2018-08-13 18:32:36 +0200157static void fill_ip4_port(IpPort_t *out, uint32_t ip, uint16_t port)
158{
159 uint32_t ip_n = htonl(ip);
160 out->ip.present = IpAddress_PR_ipv4;
161 OCTET_STRING_fromBuf(&out->ip.choice.ipv4, (const char *) &ip_n, 4);
162 out->port = htons(port);
163}
164
165
166RsproPDU_t *rspro_gen_ConnectBankReq(const struct app_comp_id *a_cid,
167 uint16_t bank_id, uint16_t num_slots)
168{
169 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
170 if (!pdu)
171 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200172 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200173 pdu->msg.present = RsproPDUchoice_PR_connectBankReq;
174 fill_comp_id(&pdu->msg.choice.connectBankReq.identity, a_cid);
175 pdu->msg.choice.connectBankReq.bankId = bank_id;
176 pdu->msg.choice.connectBankReq.numberOfSlots = num_slots;
177
178 return pdu;
179}
180
Harald Weltef5a0fa32019-03-03 15:44:18 +0100181RsproPDU_t *rspro_gen_ConnectBankRes(const struct app_comp_id *a_cid, e_ResultCode res)
182{
183 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
184 if (!pdu)
185 return NULL;
186 pdu->version = 2;
187 pdu->msg.present = RsproPDUchoice_PR_connectBankRes;
188 fill_comp_id(&pdu->msg.choice.connectBankRes.identity, a_cid);
189 pdu->msg.choice.connectBankRes.result = res;
190
191 return pdu;
192}
193
Harald Welte57555aa2018-08-17 22:05:06 +0200194RsproPDU_t *rspro_gen_ConnectClientReq(const struct app_comp_id *a_cid, const ClientSlot_t *client)
Harald Welte3aa901d2018-08-13 18:32:36 +0200195{
196 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
197 if (!pdu)
198 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200199 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200200 pdu->msg.present = RsproPDUchoice_PR_connectClientReq;
201 fill_comp_id(&pdu->msg.choice.connectClientReq.identity, a_cid);
Harald Weltec3632a72018-10-14 20:38:34 +0200202 if (client)
203 ASN_ALLOC_COPY(pdu->msg.choice.connectClientReq.clientSlot, client);
Harald Welte3aa901d2018-08-13 18:32:36 +0200204
205 return pdu;
206}
207
Harald Welte10f6c212018-09-24 14:55:55 +0200208RsproPDU_t *rspro_gen_ConnectClientRes(const struct app_comp_id *a_cid, e_ResultCode res)
209{
210 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
211 if (!pdu)
212 return NULL;
213 pdu->version = 2;
214 pdu->tag = 2342;
215 pdu->msg.present = RsproPDUchoice_PR_connectClientRes;
216 fill_comp_id(&pdu->msg.choice.connectClientRes.identity, a_cid);
217 pdu->msg.choice.connectClientRes.result = res;
218
219 return pdu;
220}
221
Harald Welte3aa901d2018-08-13 18:32:36 +0200222RsproPDU_t *rspro_gen_CreateMappingReq(const ClientSlot_t *client, const BankSlot_t *bank)
223{
224 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
225 if (!pdu)
226 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200227 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200228 pdu->msg.present = RsproPDUchoice_PR_createMappingReq;
229 pdu->msg.choice.createMappingReq.client = *client;
230 pdu->msg.choice.createMappingReq.bank = *bank;
231
232 return pdu;
233}
234
Harald Weltec0a4ae42018-10-15 00:44:53 +0200235RsproPDU_t *rspro_gen_CreateMappingRes(e_ResultCode res)
236{
237 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
238 if (!pdu)
239 return NULL;
240 pdu->version = 2;
241 pdu->msg.present = RsproPDUchoice_PR_createMappingRes;
242 pdu->msg.choice.createMappingRes.result = res;
243
244 return pdu;
245}
246
247RsproPDU_t *rspro_gen_RemoveMappingReq(const ClientSlot_t *client, const BankSlot_t *bank)
248{
249 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
250 if (!pdu)
251 return NULL;
252 pdu->version = 2;
253 pdu->msg.present = RsproPDUchoice_PR_removeMappingReq;
254 pdu->msg.choice.removeMappingReq.client = *client;
255 pdu->msg.choice.removeMappingReq.bank = *bank;
256
257 return pdu;
258}
259
260RsproPDU_t *rspro_gen_RemoveMappingRes(e_ResultCode res)
261{
262 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
263 if (!pdu)
264 return NULL;
265 pdu->version = 2;
266 pdu->msg.present = RsproPDUchoice_PR_removeMappingRes;
267 pdu->msg.choice.removeMappingRes.result = res;
268
269 return pdu;
270}
271
Harald Welte371d0262018-08-16 15:23:58 +0200272RsproPDU_t *rspro_gen_ConfigClientReq(const ClientSlot_t *client, uint32_t ip, uint16_t port)
Harald Welte3aa901d2018-08-13 18:32:36 +0200273{
274 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
275 if (!pdu)
276 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200277 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200278 pdu->msg.present = RsproPDUchoice_PR_configClientReq;
Harald Welte371d0262018-08-16 15:23:58 +0200279 pdu->msg.choice.configClientReq.clientSlot = *client;
Harald Welte3aa901d2018-08-13 18:32:36 +0200280 fill_ip4_port(&pdu->msg.choice.configClientReq.bankd, ip, port);
281
282 return pdu;
283}
284
Harald Weltec0097b12019-03-02 14:22:24 +0100285RsproPDU_t *rspro_gen_ConfigClientRes(e_ResultCode res)
286{
287 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
288 if (!pdu)
289 return NULL;
290 pdu->version = 2;
291 pdu->msg.present = RsproPDUchoice_PR_configClientRes;
292 pdu->msg.choice.configClientRes.result = res;
293
294 return pdu;
295}
296
Harald Welte3aa901d2018-08-13 18:32:36 +0200297RsproPDU_t *rspro_gen_SetAtrReq(uint16_t client_id, uint16_t slot_nr, const uint8_t *atr,
298 unsigned int atr_len)
299{
300 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
301 if (!pdu)
302 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200303 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200304 pdu->msg.present = RsproPDUchoice_PR_setAtrReq;
305 pdu->msg.choice.setAtrReq.slot.clientId = client_id;
306 pdu->msg.choice.setAtrReq.slot.slotNr = slot_nr;
307 OCTET_STRING_fromBuf(&pdu->msg.choice.setAtrReq.atr, (const char *)atr, atr_len);
308
309 return pdu;
310}
Harald Welte5d16b1c2018-09-23 19:25:46 +0200311
312RsproPDU_t *rspro_gen_TpduModem2Card(const ClientSlot_t *client, const BankSlot_t *bank,
313 const uint8_t *tpdu, unsigned int tpdu_len)
314{
315 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
316 if (!pdu)
317 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200318 pdu->version = 2;
Harald Welte5d16b1c2018-09-23 19:25:46 +0200319 pdu->msg.present = RsproPDUchoice_PR_tpduModemToCard;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200320 OSMO_ASSERT(client);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200321 pdu->msg.choice.tpduModemToCard.fromClientSlot = *client;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200322 OSMO_ASSERT(bank);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200323 pdu->msg.choice.tpduModemToCard.toBankSlot = *bank;
324 /* TODO: flags? */
325 OCTET_STRING_fromBuf(&pdu->msg.choice.tpduModemToCard.data, (const char *)tpdu, tpdu_len);
326
327 return pdu;
328}
329
330RsproPDU_t *rspro_gen_TpduCard2Modem(const BankSlot_t *bank, const ClientSlot_t *client,
331 const uint8_t *tpdu, unsigned int tpdu_len)
332{
333 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
334 if (!pdu)
335 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200336 pdu->version = 2;
Harald Welte5d16b1c2018-09-23 19:25:46 +0200337 pdu->msg.present = RsproPDUchoice_PR_tpduCardToModem;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200338 OSMO_ASSERT(bank);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200339 pdu->msg.choice.tpduCardToModem.fromBankSlot = *bank;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200340 OSMO_ASSERT(client)
Harald Welte5d16b1c2018-09-23 19:25:46 +0200341 pdu->msg.choice.tpduCardToModem.toClientSlot = *client;
342 /* TODO: flags? */
343 OCTET_STRING_fromBuf(&pdu->msg.choice.tpduCardToModem.data, (const char *)tpdu, tpdu_len);
344
345 return pdu;
346}