blob: ed0678e7ff36e3254db250aef8f95163601b111b [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{
96 if (!in)
97 out[0] = '\0';
98 memcpy(out, in->buf, out_size < in->size ? out_size : in->size);
99 if (in->size < out_size)
100 out[in->size] = '\0';
101 else
102 out[out_size-1] = '\0';
103}
104#define string_fromOCTET_STRING_ARRAY(out, in) string_fromOCTET_STRING(out, ARRAY_SIZE(out), in)
105
106
107void rspro_comp_id_retrieve(struct app_comp_id *out, const ComponentIdentity_t *in)
108{
109 memset(out, 0, sizeof(*out));
110 out->type = in->type;
111 string_fromOCTET_STRING_ARRAY(out->name, &in->name);
112 string_fromOCTET_STRING_ARRAY(out->software, &in->software);
113 string_fromOCTET_STRING_ARRAY(out->sw_version, &in->swVersion);
114 string_fromOCTET_STRING_ARRAY(out->hw_manufacturer, in->hwManufacturer);
115 string_fromOCTET_STRING_ARRAY(out->hw_serial_nr, in->hwSerialNr);
116 string_fromOCTET_STRING_ARRAY(out->hw_version, in->hwVersion);
117 string_fromOCTET_STRING_ARRAY(out->fw_version, in->fwVersion);
118}
119
Harald Welte0eaa0ef2019-03-02 15:12:42 +0100120const char *rspro_IpAddr2str(const IpAddress_t *in)
121{
122 static char buf[128];
123
124 switch (in->present) {
125 case IpAddress_PR_ipv4:
126 return inet_ntop(AF_INET, in->choice.ipv4.buf, buf, sizeof(buf));
127 case IpAddress_PR_ipv6:
128 return inet_ntop(AF_INET6, in->choice.ipv6.buf, buf, sizeof(buf));
129 default:
130 return NULL;
131 }
132}
133
Harald Welte3aa901d2018-08-13 18:32:36 +0200134static void fill_ip4_port(IpPort_t *out, uint32_t ip, uint16_t port)
135{
136 uint32_t ip_n = htonl(ip);
137 out->ip.present = IpAddress_PR_ipv4;
138 OCTET_STRING_fromBuf(&out->ip.choice.ipv4, (const char *) &ip_n, 4);
139 out->port = htons(port);
140}
141
142
143RsproPDU_t *rspro_gen_ConnectBankReq(const struct app_comp_id *a_cid,
144 uint16_t bank_id, uint16_t num_slots)
145{
146 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
147 if (!pdu)
148 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200149 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200150 pdu->msg.present = RsproPDUchoice_PR_connectBankReq;
151 fill_comp_id(&pdu->msg.choice.connectBankReq.identity, a_cid);
152 pdu->msg.choice.connectBankReq.bankId = bank_id;
153 pdu->msg.choice.connectBankReq.numberOfSlots = num_slots;
154
155 return pdu;
156}
157
Harald Welte57555aa2018-08-17 22:05:06 +0200158RsproPDU_t *rspro_gen_ConnectClientReq(const struct app_comp_id *a_cid, const ClientSlot_t *client)
Harald Welte3aa901d2018-08-13 18:32:36 +0200159{
160 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
161 if (!pdu)
162 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200163 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200164 pdu->msg.present = RsproPDUchoice_PR_connectClientReq;
165 fill_comp_id(&pdu->msg.choice.connectClientReq.identity, a_cid);
Harald Weltec3632a72018-10-14 20:38:34 +0200166 if (client)
167 ASN_ALLOC_COPY(pdu->msg.choice.connectClientReq.clientSlot, client);
Harald Welte3aa901d2018-08-13 18:32:36 +0200168
169 return pdu;
170}
171
Harald Welte10f6c212018-09-24 14:55:55 +0200172RsproPDU_t *rspro_gen_ConnectClientRes(const struct app_comp_id *a_cid, e_ResultCode res)
173{
174 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
175 if (!pdu)
176 return NULL;
177 pdu->version = 2;
178 pdu->tag = 2342;
179 pdu->msg.present = RsproPDUchoice_PR_connectClientRes;
180 fill_comp_id(&pdu->msg.choice.connectClientRes.identity, a_cid);
181 pdu->msg.choice.connectClientRes.result = res;
182
183 return pdu;
184}
185
Harald Welte3aa901d2018-08-13 18:32:36 +0200186RsproPDU_t *rspro_gen_CreateMappingReq(const ClientSlot_t *client, const BankSlot_t *bank)
187{
188 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
189 if (!pdu)
190 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200191 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200192 pdu->msg.present = RsproPDUchoice_PR_createMappingReq;
193 pdu->msg.choice.createMappingReq.client = *client;
194 pdu->msg.choice.createMappingReq.bank = *bank;
195
196 return pdu;
197}
198
Harald Weltec0a4ae42018-10-15 00:44:53 +0200199RsproPDU_t *rspro_gen_CreateMappingRes(e_ResultCode res)
200{
201 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
202 if (!pdu)
203 return NULL;
204 pdu->version = 2;
205 pdu->msg.present = RsproPDUchoice_PR_createMappingRes;
206 pdu->msg.choice.createMappingRes.result = res;
207
208 return pdu;
209}
210
211RsproPDU_t *rspro_gen_RemoveMappingReq(const ClientSlot_t *client, const BankSlot_t *bank)
212{
213 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
214 if (!pdu)
215 return NULL;
216 pdu->version = 2;
217 pdu->msg.present = RsproPDUchoice_PR_removeMappingReq;
218 pdu->msg.choice.removeMappingReq.client = *client;
219 pdu->msg.choice.removeMappingReq.bank = *bank;
220
221 return pdu;
222}
223
224RsproPDU_t *rspro_gen_RemoveMappingRes(e_ResultCode res)
225{
226 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
227 if (!pdu)
228 return NULL;
229 pdu->version = 2;
230 pdu->msg.present = RsproPDUchoice_PR_removeMappingRes;
231 pdu->msg.choice.removeMappingRes.result = res;
232
233 return pdu;
234}
235
Harald Welte371d0262018-08-16 15:23:58 +0200236RsproPDU_t *rspro_gen_ConfigClientReq(const ClientSlot_t *client, uint32_t ip, uint16_t port)
Harald Welte3aa901d2018-08-13 18:32:36 +0200237{
238 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
239 if (!pdu)
240 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200241 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200242 pdu->msg.present = RsproPDUchoice_PR_configClientReq;
Harald Welte371d0262018-08-16 15:23:58 +0200243 pdu->msg.choice.configClientReq.clientSlot = *client;
Harald Welte3aa901d2018-08-13 18:32:36 +0200244 fill_ip4_port(&pdu->msg.choice.configClientReq.bankd, ip, port);
245
246 return pdu;
247}
248
Harald Weltec0097b12019-03-02 14:22:24 +0100249RsproPDU_t *rspro_gen_ConfigClientRes(e_ResultCode res)
250{
251 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
252 if (!pdu)
253 return NULL;
254 pdu->version = 2;
255 pdu->msg.present = RsproPDUchoice_PR_configClientRes;
256 pdu->msg.choice.configClientRes.result = res;
257
258 return pdu;
259}
260
Harald Welte3aa901d2018-08-13 18:32:36 +0200261RsproPDU_t *rspro_gen_SetAtrReq(uint16_t client_id, uint16_t slot_nr, const uint8_t *atr,
262 unsigned int atr_len)
263{
264 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
265 if (!pdu)
266 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200267 pdu->version = 2;
Harald Welte3aa901d2018-08-13 18:32:36 +0200268 pdu->msg.present = RsproPDUchoice_PR_setAtrReq;
269 pdu->msg.choice.setAtrReq.slot.clientId = client_id;
270 pdu->msg.choice.setAtrReq.slot.slotNr = slot_nr;
271 OCTET_STRING_fromBuf(&pdu->msg.choice.setAtrReq.atr, (const char *)atr, atr_len);
272
273 return pdu;
274}
Harald Welte5d16b1c2018-09-23 19:25:46 +0200275
276RsproPDU_t *rspro_gen_TpduModem2Card(const ClientSlot_t *client, const BankSlot_t *bank,
277 const uint8_t *tpdu, unsigned int tpdu_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 Welte5d16b1c2018-09-23 19:25:46 +0200283 pdu->msg.present = RsproPDUchoice_PR_tpduModemToCard;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200284 OSMO_ASSERT(client);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200285 pdu->msg.choice.tpduModemToCard.fromClientSlot = *client;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200286 OSMO_ASSERT(bank);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200287 pdu->msg.choice.tpduModemToCard.toBankSlot = *bank;
288 /* TODO: flags? */
289 OCTET_STRING_fromBuf(&pdu->msg.choice.tpduModemToCard.data, (const char *)tpdu, tpdu_len);
290
291 return pdu;
292}
293
294RsproPDU_t *rspro_gen_TpduCard2Modem(const BankSlot_t *bank, const ClientSlot_t *client,
295 const uint8_t *tpdu, unsigned int tpdu_len)
296{
297 RsproPDU_t *pdu = CALLOC(1, sizeof(*pdu));
298 if (!pdu)
299 return NULL;
Harald Welte62e3f5f2018-10-15 00:44:25 +0200300 pdu->version = 2;
Harald Welte5d16b1c2018-09-23 19:25:46 +0200301 pdu->msg.present = RsproPDUchoice_PR_tpduCardToModem;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200302 OSMO_ASSERT(bank);
Harald Welte5d16b1c2018-09-23 19:25:46 +0200303 pdu->msg.choice.tpduCardToModem.fromBankSlot = *bank;
Kévin Redon6811e4f2018-10-11 08:37:38 +0200304 OSMO_ASSERT(client)
Harald Welte5d16b1c2018-09-23 19:25:46 +0200305 pdu->msg.choice.tpduCardToModem.toClientSlot = *client;
306 /* TODO: flags? */
307 OCTET_STRING_fromBuf(&pdu->msg.choice.tpduCardToModem.data, (const char *)tpdu, tpdu_len);
308
309 return pdu;
310}