blob: 422aef4f0b0db5bceef890b06ef42abe9dd11c1a [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
Harald Welteb49ac9c2019-03-09 20:36:07 +010030#include "asn1c_helpers.h"
31
Harald Welte3aa901d2018-08-13 18:32:36 +020032#include <osmocom/core/msgb.h>
33#include <osmocom/rspro/RsproPDU.h>
34
Harald Welte137c4402018-08-17 21:25:56 +020035#include "rspro_util.h"
36
Harald Welte57555aa2018-08-17 22:05:06 +020037#define ASN_ALLOC_COPY(out, in) \
38do { \
39 if (in) { \
40 out = CALLOC(1, sizeof(*in)); \
41 OSMO_ASSERT(out); \
42 memcpy(out, in, sizeof(*in)); \
43 } \
44} while (0)
45
46
Harald Welteb49ac9c2019-03-09 20:36:07 +010047const char *rspro_msgt_name(const RsproPDU_t *pdu)
48{
49 return asn_choice_name(&asn_DEF_RsproPDUchoice, &pdu->msg);
50}
51
Harald Welte3aa901d2018-08-13 18:32:36 +020052struct msgb *rspro_msgb_alloc(void)
53{
54 return msgb_alloc_headroom(1024, 8, "RSPRO");
55}
56
57/*! BER-Encode an RSPRO message into msgb.
58 * \param[in] pdu Structure describing RSPRO PDU. Is freed by this function on success
59 * \returns callee-allocated message buffer containing encoded RSPRO PDU; NULL on error.
60 */
61struct msgb *rspro_enc_msg(RsproPDU_t *pdu)
62{
63 struct msgb *msg = rspro_msgb_alloc();
64 asn_enc_rval_t rval;
65
66 if (!msg)
67 return NULL;
68
Harald Weltefd471192018-09-24 14:51:14 +020069 msg->l2h = msg->data;
Harald Welte6b8d4f82018-08-17 22:06:24 +020070 rval = der_encode_to_buffer(&asn_DEF_RsproPDU, pdu, msgb_data(msg), msgb_tailroom(msg));
Harald Welte3aa901d2018-08-13 18:32:36 +020071 if (rval.encoded < 0) {
Harald Weltea2b23c32018-08-17 22:09:06 +020072 fprintf(stderr, "Failed to encode %s\n", rval.failed_type->name);
Harald Welte703d6862018-09-24 17:44:50 +020073 msgb_free(msg);
Harald Welte3aa901d2018-08-13 18:32:36 +020074 return NULL;
75 }
Harald Welted5c5c0b2018-08-17 22:04:01 +020076 msgb_put(msg, rval.encoded);
Harald Welte3aa901d2018-08-13 18:32:36 +020077
78 ASN_STRUCT_FREE(asn_DEF_RsproPDU, pdu);
79
80 return msg;
81}
82
Harald Welte573a5b92019-09-12 20:27:58 +020083/* caller must make sure to free msg */
Harald Welte3aa901d2018-08-13 18:32:36 +020084RsproPDU_t *rspro_dec_msg(struct msgb *msg)
85{
Harald Welte9ebbacc2018-09-24 17:43:39 +020086 RsproPDU_t *pdu = NULL;
Harald Welte3aa901d2018-08-13 18:32:36 +020087 asn_dec_rval_t rval;
88
Harald Welte05dc39e2019-04-01 10:51:08 +020089 //printf("decoding %s\n", msgb_hexdump(msg));
Harald Welte75852862018-09-24 14:55:34 +020090 rval = ber_decode(NULL, &asn_DEF_RsproPDU, (void **) &pdu, msgb_l2(msg), msgb_l2len(msg));
Harald Welte3aa901d2018-08-13 18:32:36 +020091 if (rval.code != RC_OK) {
Harald Welte75852862018-09-24 14:55:34 +020092 fprintf(stderr, "Failed to decode: %d. Consumed %lu of %u bytes\n",
93 rval.code, rval.consumed, msgb_length(msg));
Harald Welte3aa901d2018-08-13 18:32:36 +020094 return NULL;
95 }
96
Harald Welte3aa901d2018-08-13 18:32:36 +020097 return pdu;
98}
99
Harald Welte3aa901d2018-08-13 18:32:36 +0200100static void fill_comp_id(ComponentIdentity_t *out, const struct app_comp_id *in)
101{
Harald Welte137c4402018-08-17 21:25:56 +0200102 out->type = in->type;
Harald Welte3aa901d2018-08-13 18:32:36 +0200103 OCTET_STRING_fromString(&out->name, in->name);
104 OCTET_STRING_fromString(&out->software, in->software);
105 OCTET_STRING_fromString(&out->swVersion, in->sw_version);
106 if (strlen(in->hw_manufacturer))
107 out->hwManufacturer = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName,
108 in->hw_manufacturer, -1);
109 if (strlen(in->hw_model))
110 out->hwModel = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_model, -1);
111 if (strlen(in->hw_serial_nr))
112 out->hwSerialNr = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_serial_nr, -1);
113 if (strlen(in->hw_version))
114 out->hwVersion = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_version, -1);
115 if (strlen(in->fw_version))
116 out->fwVersion = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->fw_version, -1);
117}
118
Harald Welte92bd8812019-03-02 14:52:17 +0100119void string_fromOCTET_STRING(char *out, size_t out_size, const OCTET_STRING_t *in)
120{
Harald Weltef5a0fa32019-03-03 15:44:18 +0100121 if (!in) {
Harald Welte92bd8812019-03-02 14:52:17 +0100122 out[0] = '\0';
Harald Weltef5a0fa32019-03-03 15:44:18 +0100123 return;
124 }
Harald Welte92bd8812019-03-02 14:52:17 +0100125 memcpy(out, in->buf, out_size < in->size ? out_size : in->size);
126 if (in->size < out_size)
127 out[in->size] = '\0';
128 else
129 out[out_size-1] = '\0';
130}
131#define string_fromOCTET_STRING_ARRAY(out, in) string_fromOCTET_STRING(out, ARRAY_SIZE(out), in)
132
133
134void rspro_comp_id_retrieve(struct app_comp_id *out, const ComponentIdentity_t *in)
135{
136 memset(out, 0, sizeof(*out));
137 out->type = in->type;
138 string_fromOCTET_STRING_ARRAY(out->name, &in->name);
139 string_fromOCTET_STRING_ARRAY(out->software, &in->software);
140 string_fromOCTET_STRING_ARRAY(out->sw_version, &in->swVersion);
141 string_fromOCTET_STRING_ARRAY(out->hw_manufacturer, in->hwManufacturer);
142 string_fromOCTET_STRING_ARRAY(out->hw_serial_nr, in->hwSerialNr);
143 string_fromOCTET_STRING_ARRAY(out->hw_version, in->hwVersion);
144 string_fromOCTET_STRING_ARRAY(out->fw_version, in->fwVersion);
145}
146
Harald Welte0eaa0ef2019-03-02 15:12:42 +0100147const char *rspro_IpAddr2str(const IpAddress_t *in)
148{
149 static char buf[128];
150
151 switch (in->present) {
152 case IpAddress_PR_ipv4:
153 return inet_ntop(AF_INET, in->choice.ipv4.buf, buf, sizeof(buf));
154 case IpAddress_PR_ipv6:
155 return inet_ntop(AF_INET6, in->choice.ipv6.buf, buf, sizeof(buf));
156 default:
157 return NULL;
158 }
159}
160
Harald Welte3aa901d2018-08-13 18:32:36 +0200161static void fill_ip4_port(IpPort_t *out, uint32_t ip, uint16_t port)
162{
163 uint32_t ip_n = htonl(ip);
164 out->ip.present = IpAddress_PR_ipv4;
165 OCTET_STRING_fromBuf(&out->ip.choice.ipv4, (const char *) &ip_n, 4);
Harald Welte69714122019-03-30 19:16:30 +0100166 out->port = port;
Harald Welte3aa901d2018-08-13 18:32:36 +0200167}
168
169
170RsproPDU_t *rspro_gen_ConnectBankReq(const struct app_comp_id *a_cid,
171 uint16_t bank_id, uint16_t num_slots)
172{
173 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
174 if (!pdu)
175 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200176 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200177 pdu->msg.present = RsproPDUchoice_PR_connectBankReq;
178 fill_comp_id(&pdu->msg.choice.connectBankReq.identity, a_cid);
179 pdu->msg.choice.connectBankReq.bankId = bank_id;
180 pdu->msg.choice.connectBankReq.numberOfSlots = num_slots;
181
182 return pdu;
183}
184
Harald Weltef5a0fa32019-03-03 15:44:18 +0100185RsproPDU_t *rspro_gen_ConnectBankRes(const struct app_comp_id *a_cid, e_ResultCode res)
186{
187 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
188 if (!pdu)
189 return NULL;
190 pdu->version = 2;
191 pdu->msg.present = RsproPDUchoice_PR_connectBankRes;
192 fill_comp_id(&pdu->msg.choice.connectBankRes.identity, a_cid);
193 pdu->msg.choice.connectBankRes.result = res;
194
195 return pdu;
196}
197
Harald Welte57555aa2018-08-17 22:05:06 +0200198RsproPDU_t *rspro_gen_ConnectClientReq(const struct app_comp_id *a_cid, const ClientSlot_t *client)
Harald Welte3aa901d2018-08-13 18:32:36 +0200199{
200 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
201 if (!pdu)
202 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200203 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200204 pdu->msg.present = RsproPDUchoice_PR_connectClientReq;
205 fill_comp_id(&pdu->msg.choice.connectClientReq.identity, a_cid);
Harald Weltec3632a72018-10-14 20:38:34 +0200206 if (client)
207 ASN_ALLOC_COPY(pdu->msg.choice.connectClientReq.clientSlot, client);
Harald Welte3aa901d2018-08-13 18:32:36 +0200208
209 return pdu;
210}
211
Harald Welte10f6c212018-09-24 14:55:55 +0200212RsproPDU_t *rspro_gen_ConnectClientRes(const struct app_comp_id *a_cid, e_ResultCode res)
213{
214 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
215 if (!pdu)
216 return NULL;
217 pdu->version = 2;
218 pdu->tag = 2342;
219 pdu->msg.present = RsproPDUchoice_PR_connectClientRes;
220 fill_comp_id(&pdu->msg.choice.connectClientRes.identity, a_cid);
221 pdu->msg.choice.connectClientRes.result = res;
222
223 return pdu;
224}
225
Harald Welte3aa901d2018-08-13 18:32:36 +0200226RsproPDU_t *rspro_gen_CreateMappingReq(const ClientSlot_t *client, const BankSlot_t *bank)
227{
228 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
229 if (!pdu)
230 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200231 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200232 pdu->msg.present = RsproPDUchoice_PR_createMappingReq;
233 pdu->msg.choice.createMappingReq.client = *client;
234 pdu->msg.choice.createMappingReq.bank = *bank;
235
236 return pdu;
237}
238
Harald Weltec0a4ae42018-10-15 00:44:53 +0200239RsproPDU_t *rspro_gen_CreateMappingRes(e_ResultCode res)
240{
241 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
242 if (!pdu)
243 return NULL;
244 pdu->version = 2;
245 pdu->msg.present = RsproPDUchoice_PR_createMappingRes;
246 pdu->msg.choice.createMappingRes.result = res;
247
248 return pdu;
249}
250
251RsproPDU_t *rspro_gen_RemoveMappingReq(const ClientSlot_t *client, const BankSlot_t *bank)
252{
253 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
254 if (!pdu)
255 return NULL;
256 pdu->version = 2;
257 pdu->msg.present = RsproPDUchoice_PR_removeMappingReq;
258 pdu->msg.choice.removeMappingReq.client = *client;
259 pdu->msg.choice.removeMappingReq.bank = *bank;
260
261 return pdu;
262}
263
264RsproPDU_t *rspro_gen_RemoveMappingRes(e_ResultCode res)
265{
266 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
267 if (!pdu)
268 return NULL;
269 pdu->version = 2;
270 pdu->msg.present = RsproPDUchoice_PR_removeMappingRes;
271 pdu->msg.choice.removeMappingRes.result = res;
272
273 return pdu;
274}
275
Harald Welteeae30c32019-03-30 17:32:37 +0100276RsproPDU_t *rspro_gen_ConfigClientIdReq(const ClientSlot_t *client)
Harald Welte3aa901d2018-08-13 18:32:36 +0200277{
278 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
279 if (!pdu)
280 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200281 pdu->version = 2;
Harald Welted571a3e2019-03-11 22:09:50 +0100282 pdu->msg.present = RsproPDUchoice_PR_configClientIdReq;
283 pdu->msg.choice.configClientIdReq.clientSlot = *client;
Harald Welte3aa901d2018-08-13 18:32:36 +0200284
285 return pdu;
286}
287
Harald Welted571a3e2019-03-11 22:09:50 +0100288RsproPDU_t *rspro_gen_ConfigClientIdRes(e_ResultCode res)
Harald Weltec0097b12019-03-02 14:22:24 +0100289{
290 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
291 if (!pdu)
292 return NULL;
293 pdu->version = 2;
Harald Welted571a3e2019-03-11 22:09:50 +0100294 pdu->msg.present = RsproPDUchoice_PR_configClientIdRes;
295 pdu->msg.choice.configClientIdRes.result = res;
296
297 return pdu;
298}
299
300RsproPDU_t *rspro_gen_ConfigClientBankReq(const BankSlot_t *bank, uint32_t ip, uint16_t port)
301{
302 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
303 if (!pdu)
304 return NULL;
305 pdu->version = 2;
306 pdu->msg.present = RsproPDUchoice_PR_configClientBankReq;
307 pdu->msg.choice.configClientBankReq.bankSlot = *bank;
308 fill_ip4_port(&pdu->msg.choice.configClientBankReq.bankd, ip, port);
309
310 return pdu;
311}
312
313RsproPDU_t *rspro_gen_ConfigClientBankRes(e_ResultCode res)
314{
315 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
316 if (!pdu)
317 return NULL;
318 pdu->version = 2;
319 pdu->msg.present = RsproPDUchoice_PR_configClientBankRes;
320 pdu->msg.choice.configClientBankRes.result = res;
Harald Weltec0097b12019-03-02 14:22:24 +0100321
322 return pdu;
323}
324
Harald Welte3aa901d2018-08-13 18:32:36 +0200325RsproPDU_t *rspro_gen_SetAtrReq(uint16_t client_id, uint16_t slot_nr, const uint8_t *atr,
326 unsigned int atr_len)
327{
328 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
329 if (!pdu)
330 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200331 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200332 pdu->msg.present = RsproPDUchoice_PR_setAtrReq;
333 pdu->msg.choice.setAtrReq.slot.clientId = client_id;
334 pdu->msg.choice.setAtrReq.slot.slotNr = slot_nr;
335 OCTET_STRING_fromBuf(&pdu->msg.choice.setAtrReq.atr, (const char *)atr, atr_len);
336
337 return pdu;
338}
Harald Welte5d16b1c2018-09-23 19:25:46 +0200339
Harald Weltefa365592019-03-28 20:28:57 +0100340RsproPDU_t *rspro_gen_SetAtrRes(e_ResultCode res)
341{
342 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
343 if (!pdu)
344 return NULL;
345 pdu->version = 2;
346 pdu->msg.present = RsproPDUchoice_PR_setAtrRes;
347 pdu->msg.choice.setAtrRes.result = res;
348
349 return pdu;
350}
351
Harald Welte5d16b1c2018-09-23 19:25:46 +0200352RsproPDU_t *rspro_gen_TpduModem2Card(const ClientSlot_t *client, const BankSlot_t *bank,
353 const uint8_t *tpdu, unsigned int tpdu_len)
354{
355 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
356 if (!pdu)
357 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200358 pdu->version = 2;
Harald Welte5d16b1c2018-09-23 19:25:46 +0200359 pdu->msg.present = RsproPDUchoice_PR_tpduModemToCard;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200360 OSMO_ASSERT(client);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200361 pdu->msg.choice.tpduModemToCard.fromClientSlot = *client;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200362 OSMO_ASSERT(bank);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200363 pdu->msg.choice.tpduModemToCard.toBankSlot = *bank;
364 /* TODO: flags? */
365 OCTET_STRING_fromBuf(&pdu->msg.choice.tpduModemToCard.data, (const char *)tpdu, tpdu_len);
366
367 return pdu;
368}
369
370RsproPDU_t *rspro_gen_TpduCard2Modem(const BankSlot_t *bank, const ClientSlot_t *client,
371 const uint8_t *tpdu, unsigned int tpdu_len)
372{
373 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
374 if (!pdu)
375 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200376 pdu->version = 2;
Harald Welte5d16b1c2018-09-23 19:25:46 +0200377 pdu->msg.present = RsproPDUchoice_PR_tpduCardToModem;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200378 OSMO_ASSERT(bank);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200379 pdu->msg.choice.tpduCardToModem.fromBankSlot = *bank;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200380 OSMO_ASSERT(client)
Harald Welte5d16b1c2018-09-23 19:25:46 +0200381 pdu->msg.choice.tpduCardToModem.toClientSlot = *client;
382 /* TODO: flags? */
383 OCTET_STRING_fromBuf(&pdu->msg.choice.tpduCardToModem.data, (const char *)tpdu, tpdu_len);
384
385 return pdu;
386}
Harald Weltecf8b89a2019-03-11 22:16:22 +0100387
Harald Welte3f966322019-12-04 19:09:58 +0100388RsproPDU_t *rspro_gen_ResetStateReq(void)
389{
390 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
391 if (!pdu)
392 return NULL;
393 pdu->version = 2;
394 pdu->msg.present = RsproPDUchoice_PR_resetStateReq;
395
396 return pdu;
397}
398
399RsproPDU_t *rspro_gen_ResetStateRes(e_ResultCode res)
400{
401 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
402 if (!pdu)
403 return NULL;
404 pdu->version = 2;
405 pdu->msg.present = RsproPDUchoice_PR_resetStateRes;
406 pdu->msg.choice.resetStateRes.result = res;
407
408 return pdu;
409}
410
Harald Welte4e7a2852019-03-17 21:01:50 +0100411e_ResultCode rspro_get_result(const RsproPDU_t *pdu)
412{
413 switch (pdu->msg.present) {
414 case RsproPDUchoice_PR_connectBankRes:
415 return pdu->msg.choice.connectBankRes.result;
416 case RsproPDUchoice_PR_connectClientRes:
417 return pdu->msg.choice.connectClientRes.result;
418 case RsproPDUchoice_PR_createMappingRes:
419 return pdu->msg.choice.createMappingRes.result;
420 case RsproPDUchoice_PR_removeMappingRes:
421 return pdu->msg.choice.removeMappingRes.result;
422 case RsproPDUchoice_PR_configClientIdRes:
423 return pdu->msg.choice.configClientIdRes.result;
424 case RsproPDUchoice_PR_configClientBankRes:
425 return pdu->msg.choice.configClientBankRes.result;
426 case RsproPDUchoice_PR_setAtrRes:
427 return pdu->msg.choice.setAtrRes.result;
Harald Welte3f966322019-12-04 19:09:58 +0100428 case RsproPDUchoice_PR_resetStateRes:
429 return pdu->msg.choice.resetStateRes.result;
Harald Welte4e7a2852019-03-17 21:01:50 +0100430 default:
431 OSMO_ASSERT(0);
432 }
433}
434
Harald Weltecf8b89a2019-03-11 22:16:22 +0100435void rspro2bank_slot(struct bank_slot *out, const BankSlot_t *in)
436{
437 out->bank_id = in->bankId;
438 out->slot_nr = in->slotNr;
439}
440
441void bank_slot2rspro(BankSlot_t *out, const struct bank_slot *in)
442{
443 out->bankId = in->bank_id;
444 out->slotNr = in->slot_nr;
445}
446
447void rspro2client_slot(struct client_slot *out, const ClientSlot_t *in)
448{
449 out->client_id = in->clientId;
450 out->slot_nr = in->slotNr;
451}
452
453void client_slot2rspro(ClientSlot_t *out, const struct client_slot *in)
454{
455 out->clientId = in->client_id;
456 out->slotNr = in->slot_nr;
457}