blob: 2f2e2d1c18126f0a55e6487909cd713dfa54ef74 [file] [log] [blame]
Harald Welte3aa901d2018-08-13 18:32:36 +02001
2
Harald Welte0eaa0ef2019-03-02 15:12:42 +01003#include <netinet/in.h>
4#include <arpa/inet.h>
5
Kévin Redonff5db6e2018-10-11 17:16:18 +02006#include <asn_application.h>
7#include <der_encoder.h>
Harald Welte3aa901d2018-08-13 18:32:36 +02008
9#include <osmocom/core/msgb.h>
10#include <osmocom/rspro/RsproPDU.h>
11
Harald Welte137c4402018-08-17 21:25:56 +020012#include "rspro_util.h"
13
Harald Welte57555aa2018-08-17 22:05:06 +020014#define ASN_ALLOC_COPY(out, in) \
15do { \
16 if (in) { \
17 out = CALLOC(1, sizeof(*in)); \
18 OSMO_ASSERT(out); \
19 memcpy(out, in, sizeof(*in)); \
20 } \
21} while (0)
22
23
Harald Welte3aa901d2018-08-13 18:32:36 +020024struct msgb *rspro_msgb_alloc(void)
25{
26 return msgb_alloc_headroom(1024, 8, "RSPRO");
27}
28
29/*! BER-Encode an RSPRO message into msgb.
30 * \param[in] pdu Structure describing RSPRO PDU. Is freed by this function on success
31 * \returns callee-allocated message buffer containing encoded RSPRO PDU; NULL on error.
32 */
33struct msgb *rspro_enc_msg(RsproPDU_t *pdu)
34{
35 struct msgb *msg = rspro_msgb_alloc();
36 asn_enc_rval_t rval;
37
38 if (!msg)
39 return NULL;
40
Harald Weltefd471192018-09-24 14:51:14 +020041 msg->l2h = msg->data;
Harald Welte6b8d4f82018-08-17 22:06:24 +020042 rval = der_encode_to_buffer(&asn_DEF_RsproPDU, pdu, msgb_data(msg), msgb_tailroom(msg));
Harald Welte3aa901d2018-08-13 18:32:36 +020043 if (rval.encoded < 0) {
Harald Weltea2b23c32018-08-17 22:09:06 +020044 fprintf(stderr, "Failed to encode %s\n", rval.failed_type->name);
Harald Welte703d6862018-09-24 17:44:50 +020045 msgb_free(msg);
Harald Welte3aa901d2018-08-13 18:32:36 +020046 return NULL;
47 }
Harald Welted5c5c0b2018-08-17 22:04:01 +020048 msgb_put(msg, rval.encoded);
Harald Welte3aa901d2018-08-13 18:32:36 +020049
50 ASN_STRUCT_FREE(asn_DEF_RsproPDU, pdu);
51
52 return msg;
53}
54
55/* consumes 'msg' _if_ it is successful */
56RsproPDU_t *rspro_dec_msg(struct msgb *msg)
57{
Harald Welte9ebbacc2018-09-24 17:43:39 +020058 RsproPDU_t *pdu = NULL;
Harald Welte3aa901d2018-08-13 18:32:36 +020059 asn_dec_rval_t rval;
60
Harald Welte75852862018-09-24 14:55:34 +020061 printf("decoding %s\n", msgb_hexdump(msg));
62 rval = ber_decode(NULL, &asn_DEF_RsproPDU, (void **) &pdu, msgb_l2(msg), msgb_l2len(msg));
Harald Welte3aa901d2018-08-13 18:32:36 +020063 if (rval.code != RC_OK) {
Harald Welte75852862018-09-24 14:55:34 +020064 fprintf(stderr, "Failed to decode: %d. Consumed %lu of %u bytes\n",
65 rval.code, rval.consumed, msgb_length(msg));
66 msgb_free(msg);
Harald Welte3aa901d2018-08-13 18:32:36 +020067 return NULL;
68 }
69
70 msgb_free(msg);
71
72 return pdu;
73}
74
Harald Welte3aa901d2018-08-13 18:32:36 +020075static void fill_comp_id(ComponentIdentity_t *out, const struct app_comp_id *in)
76{
Harald Welte137c4402018-08-17 21:25:56 +020077 out->type = in->type;
Harald Welte3aa901d2018-08-13 18:32:36 +020078 OCTET_STRING_fromString(&out->name, in->name);
79 OCTET_STRING_fromString(&out->software, in->software);
80 OCTET_STRING_fromString(&out->swVersion, in->sw_version);
81 if (strlen(in->hw_manufacturer))
82 out->hwManufacturer = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName,
83 in->hw_manufacturer, -1);
84 if (strlen(in->hw_model))
85 out->hwModel = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_model, -1);
86 if (strlen(in->hw_serial_nr))
87 out->hwSerialNr = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_serial_nr, -1);
88 if (strlen(in->hw_version))
89 out->hwVersion = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->hw_version, -1);
90 if (strlen(in->fw_version))
91 out->fwVersion = OCTET_STRING_new_fromBuf(&asn_DEF_ComponentName, in->fw_version, -1);
92}
93
Harald Welte92bd8812019-03-02 14:52:17 +010094void string_fromOCTET_STRING(char *out, size_t out_size, const OCTET_STRING_t *in)
95{
Harald Weltef5a0fa32019-03-03 15:44:18 +010096 if (!in) {
Harald Welte92bd8812019-03-02 14:52:17 +010097 out[0] = '\0';
Harald Weltef5a0fa32019-03-03 15:44:18 +010098 return;
99 }
Harald Welte92bd8812019-03-02 14:52:17 +0100100 memcpy(out, in->buf, out_size < in->size ? out_size : in->size);
101 if (in->size < out_size)
102 out[in->size] = '\0';
103 else
104 out[out_size-1] = '\0';
105}
106#define string_fromOCTET_STRING_ARRAY(out, in) string_fromOCTET_STRING(out, ARRAY_SIZE(out), in)
107
108
109void rspro_comp_id_retrieve(struct app_comp_id *out, const ComponentIdentity_t *in)
110{
111 memset(out, 0, sizeof(*out));
112 out->type = in->type;
113 string_fromOCTET_STRING_ARRAY(out->name, &in->name);
114 string_fromOCTET_STRING_ARRAY(out->software, &in->software);
115 string_fromOCTET_STRING_ARRAY(out->sw_version, &in->swVersion);
116 string_fromOCTET_STRING_ARRAY(out->hw_manufacturer, in->hwManufacturer);
117 string_fromOCTET_STRING_ARRAY(out->hw_serial_nr, in->hwSerialNr);
118 string_fromOCTET_STRING_ARRAY(out->hw_version, in->hwVersion);
119 string_fromOCTET_STRING_ARRAY(out->fw_version, in->fwVersion);
120}
121
Harald Welte0eaa0ef2019-03-02 15:12:42 +0100122const char *rspro_IpAddr2str(const IpAddress_t *in)
123{
124 static char buf[128];
125
126 switch (in->present) {
127 case IpAddress_PR_ipv4:
128 return inet_ntop(AF_INET, in->choice.ipv4.buf, buf, sizeof(buf));
129 case IpAddress_PR_ipv6:
130 return inet_ntop(AF_INET6, in->choice.ipv6.buf, buf, sizeof(buf));
131 default:
132 return NULL;
133 }
134}
135
Harald Welte3aa901d2018-08-13 18:32:36 +0200136static void fill_ip4_port(IpPort_t *out, uint32_t ip, uint16_t port)
137{
138 uint32_t ip_n = htonl(ip);
139 out->ip.present = IpAddress_PR_ipv4;
140 OCTET_STRING_fromBuf(&out->ip.choice.ipv4, (const char *) &ip_n, 4);
141 out->port = htons(port);
142}
143
144
145RsproPDU_t *rspro_gen_ConnectBankReq(const struct app_comp_id *a_cid,
146 uint16_t bank_id, uint16_t num_slots)
147{
148 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
149 if (!pdu)
150 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200151 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200152 pdu->msg.present = RsproPDUchoice_PR_connectBankReq;
153 fill_comp_id(&pdu->msg.choice.connectBankReq.identity, a_cid);
154 pdu->msg.choice.connectBankReq.bankId = bank_id;
155 pdu->msg.choice.connectBankReq.numberOfSlots = num_slots;
156
157 return pdu;
158}
159
Harald Weltef5a0fa32019-03-03 15:44:18 +0100160RsproPDU_t *rspro_gen_ConnectBankRes(const struct app_comp_id *a_cid, e_ResultCode res)
161{
162 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
163 if (!pdu)
164 return NULL;
165 pdu->version = 2;
166 pdu->msg.present = RsproPDUchoice_PR_connectBankRes;
167 fill_comp_id(&pdu->msg.choice.connectBankRes.identity, a_cid);
168 pdu->msg.choice.connectBankRes.result = res;
169
170 return pdu;
171}
172
Harald Welte57555aa2018-08-17 22:05:06 +0200173RsproPDU_t *rspro_gen_ConnectClientReq(const struct app_comp_id *a_cid, const ClientSlot_t *client)
Harald Welte3aa901d2018-08-13 18:32:36 +0200174{
175 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
176 if (!pdu)
177 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200178 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200179 pdu->msg.present = RsproPDUchoice_PR_connectClientReq;
180 fill_comp_id(&pdu->msg.choice.connectClientReq.identity, a_cid);
Harald Weltec3632a72018-10-14 20:38:34 +0200181 if (client)
182 ASN_ALLOC_COPY(pdu->msg.choice.connectClientReq.clientSlot, client);
Harald Welte3aa901d2018-08-13 18:32:36 +0200183
184 return pdu;
185}
186
Harald Welte10f6c212018-09-24 14:55:55 +0200187RsproPDU_t *rspro_gen_ConnectClientRes(const struct app_comp_id *a_cid, e_ResultCode res)
188{
189 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
190 if (!pdu)
191 return NULL;
192 pdu->version = 2;
193 pdu->tag = 2342;
194 pdu->msg.present = RsproPDUchoice_PR_connectClientRes;
195 fill_comp_id(&pdu->msg.choice.connectClientRes.identity, a_cid);
196 pdu->msg.choice.connectClientRes.result = res;
197
198 return pdu;
199}
200
Harald Welte3aa901d2018-08-13 18:32:36 +0200201RsproPDU_t *rspro_gen_CreateMappingReq(const ClientSlot_t *client, const BankSlot_t *bank)
202{
203 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
204 if (!pdu)
205 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200206 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200207 pdu->msg.present = RsproPDUchoice_PR_createMappingReq;
208 pdu->msg.choice.createMappingReq.client = *client;
209 pdu->msg.choice.createMappingReq.bank = *bank;
210
211 return pdu;
212}
213
Harald Weltec0a4ae42018-10-15 00:44:53 +0200214RsproPDU_t *rspro_gen_CreateMappingRes(e_ResultCode res)
215{
216 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
217 if (!pdu)
218 return NULL;
219 pdu->version = 2;
220 pdu->msg.present = RsproPDUchoice_PR_createMappingRes;
221 pdu->msg.choice.createMappingRes.result = res;
222
223 return pdu;
224}
225
226RsproPDU_t *rspro_gen_RemoveMappingReq(const ClientSlot_t *client, const BankSlot_t *bank)
227{
228 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
229 if (!pdu)
230 return NULL;
231 pdu->version = 2;
232 pdu->msg.present = RsproPDUchoice_PR_removeMappingReq;
233 pdu->msg.choice.removeMappingReq.client = *client;
234 pdu->msg.choice.removeMappingReq.bank = *bank;
235
236 return pdu;
237}
238
239RsproPDU_t *rspro_gen_RemoveMappingRes(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_removeMappingRes;
246 pdu->msg.choice.removeMappingRes.result = res;
247
248 return pdu;
249}
250
Harald Welte371d0262018-08-16 15:23:58 +0200251RsproPDU_t *rspro_gen_ConfigClientReq(const ClientSlot_t *client, uint32_t ip, uint16_t port)
Harald Welte3aa901d2018-08-13 18:32:36 +0200252{
253 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
254 if (!pdu)
255 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200256 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200257 pdu->msg.present = RsproPDUchoice_PR_configClientReq;
Harald Welte371d0262018-08-16 15:23:58 +0200258 pdu->msg.choice.configClientReq.clientSlot = *client;
Harald Welte3aa901d2018-08-13 18:32:36 +0200259 fill_ip4_port(&pdu->msg.choice.configClientReq.bankd, ip, port);
260
261 return pdu;
262}
263
Harald Weltec0097b12019-03-02 14:22:24 +0100264RsproPDU_t *rspro_gen_ConfigClientRes(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_configClientRes;
271 pdu->msg.choice.configClientRes.result = res;
272
273 return pdu;
274}
275
Harald Welte3aa901d2018-08-13 18:32:36 +0200276RsproPDU_t *rspro_gen_SetAtrReq(uint16_t client_id, uint16_t slot_nr, const uint8_t *atr,
277 unsigned int atr_len)
278{
279 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
280 if (!pdu)
281 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200282 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200283 pdu->msg.present = RsproPDUchoice_PR_setAtrReq;
284 pdu->msg.choice.setAtrReq.slot.clientId = client_id;
285 pdu->msg.choice.setAtrReq.slot.slotNr = slot_nr;
286 OCTET_STRING_fromBuf(&pdu->msg.choice.setAtrReq.atr, (const char *)atr, atr_len);
287
288 return pdu;
289}
Harald Welte5d16b1c2018-09-23 19:25:46 +0200290
291RsproPDU_t *rspro_gen_TpduModem2Card(const ClientSlot_t *client, const BankSlot_t *bank,
292 const uint8_t *tpdu, unsigned int tpdu_len)
293{
294 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
295 if (!pdu)
296 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200297 pdu->version = 2;
Harald Welte5d16b1c2018-09-23 19:25:46 +0200298 pdu->msg.present = RsproPDUchoice_PR_tpduModemToCard;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200299 OSMO_ASSERT(client);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200300 pdu->msg.choice.tpduModemToCard.fromClientSlot = *client;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200301 OSMO_ASSERT(bank);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200302 pdu->msg.choice.tpduModemToCard.toBankSlot = *bank;
303 /* TODO: flags? */
304 OCTET_STRING_fromBuf(&pdu->msg.choice.tpduModemToCard.data, (const char *)tpdu, tpdu_len);
305
306 return pdu;
307}
308
309RsproPDU_t *rspro_gen_TpduCard2Modem(const BankSlot_t *bank, const ClientSlot_t *client,
310 const uint8_t *tpdu, unsigned int tpdu_len)
311{
312 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
313 if (!pdu)
314 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200315 pdu->version = 2;
Harald Welte5d16b1c2018-09-23 19:25:46 +0200316 pdu->msg.present = RsproPDUchoice_PR_tpduCardToModem;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200317 OSMO_ASSERT(bank);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200318 pdu->msg.choice.tpduCardToModem.fromBankSlot = *bank;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200319 OSMO_ASSERT(client)
Harald Welte5d16b1c2018-09-23 19:25:46 +0200320 pdu->msg.choice.tpduCardToModem.toClientSlot = *client;
321 /* TODO: flags? */
322 OCTET_STRING_fromBuf(&pdu->msg.choice.tpduCardToModem.data, (const char *)tpdu, tpdu_len);
323
324 return pdu;
325}