blob: e5f4951ef080e82b2e35b6498db12f458bda2027 [file] [log] [blame]
Daniel Willmann97374c02015-12-03 09:37:58 +01001/* Test HNB */
2
3/* (C) 2015 by Daniel Willmann <dwillmann@sysmocom.de>
4 * (C) 2015 by Sysmocom s.f.m.c. GmbH
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <unistd.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <getopt.h>
27#include <errno.h>
28#include <signal.h>
29
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <netinet/sctp.h>
34#include <arpa/inet.h>
35
36#include <osmocom/core/application.h>
37#include <osmocom/core/talloc.h>
38#include <osmocom/core/select.h>
39#include <osmocom/core/logging.h>
40#include <osmocom/core/socket.h>
41#include <osmocom/core/msgb.h>
42#include <osmocom/core/write_queue.h>
43
44#include <osmocom/vty/telnet_interface.h>
45#include <osmocom/vty/logging.h>
46
47#include "hnb-test.h"
Daniel Willmanna1e202e2015-12-07 17:21:07 +010048#include "hnbap_common.h"
49#include "hnbap_ies_defs.h"
Daniel Willmann97374c02015-12-03 09:37:58 +010050
51static void *tall_hnb_ctx;
52void *talloc_asn1_ctx;
53
54struct hnb_test g_hnb_test = {
55 .gw_port = IUH_DEFAULT_SCTP_PORT,
56};
57
Daniel Willmann19dedbb2015-12-17 11:57:41 +010058int hnb_test_ue_de_register_tx(struct hnb_test *hnb_test)
59{
60 struct msgb *msg;
61 int rc, imsi_len;
62 uint32_t ctx_id;
63
64 UEDe_Register_t dereg;
65 UEDe_RegisterIEs_t dereg_ies;
66 memset(&dereg_ies, 0, sizeof(dereg_ies));
67
68 asn1_u24_to_bitstring(&dereg_ies.context_ID, &ctx_id, hnb_test->ctx_id);
69 dereg_ies.cause.present = Cause_PR_radioNetwork;
70 dereg_ies.cause.choice.radioNetwork = CauseRadioNetwork_connection_with_UE_lost;
71
72 memset(&dereg, 0, sizeof(dereg));
73 rc = hnbap_encode_uede_registeries(&dereg, &dereg_ies);
74
75 msg = hnbap_generate_initiating_message(ProcedureCode_id_UEDe_Register,
76 Criticality_ignore,
77 &asn_DEF_UEDe_Register,
78 &dereg);
79
80
81 msgb_ppid(msg) = IUH_PPI_HNBAP;
82
83 return osmo_wqueue_enqueue(&hnb_test->wqueue, msg);
84}
85
Daniel Willmann479cb302015-12-09 17:54:59 +010086int hnb_test_ue_register_tx(struct hnb_test *hnb_test)
87{
Daniel Willmann4e312502015-12-09 17:59:24 +010088 struct msgb *msg;
89 int rc, imsi_len;
90
91 char imsi_buf[16];
92 char *imsi_str = "262019876543210";
93
94 UERegisterRequest_t request_out;
95 UERegisterRequestIEs_t request;
96 memset(&request, 0, sizeof(request));
97
98 request.uE_Identity.present = UE_Identity_PR_iMSI;
99
100 imsi_len = encode_iu_imsi(imsi_buf, sizeof(imsi_buf), imsi_str);
101 request.uE_Identity.choice.iMSI.buf = imsi_buf;
102 request.uE_Identity.choice.iMSI.size = imsi_len;
103
104 request.registration_Cause = Registration_Cause_normal;
105 request.uE_Capabilities.access_stratum_release_indicator = Access_stratum_release_indicator_rel_6;
106 request.uE_Capabilities.csg_capability = CSG_Capability_not_csg_capable;
107
108 memset(&request_out, 0, sizeof(request_out));
109 rc = hnbap_encode_ueregisterrequesties(&request_out, &request);
110
111 msg = hnbap_generate_initiating_message(ProcedureCode_id_UERegister,
112 Criticality_reject,
113 &asn_DEF_UERegisterRequest,
114 &request_out);
115
116
117 msgb_ppid(msg) = IUH_PPI_HNBAP;
118
119 return osmo_wqueue_enqueue(&hnb_test->wqueue, msg);
Daniel Willmann479cb302015-12-09 17:54:59 +0100120}
121
122int hnb_test_rx_hnb_register_acc(struct hnb_test *hnb, ANY_t *in)
123{
124 int rc;
125 HNBRegisterAcceptIEs_t accept;
126
127 rc = hnbap_decode_hnbregisteraccepties(&accept, in);
128 if (rc < 0) {
129 }
130
131 hnb->rnc_id = accept.rnc_id;
132 printf("HNB Register accept with RNC ID %u\n", hnb->rnc_id);
133
134 return hnb_test_ue_register_tx(hnb);
135}
136
Daniel Willmanna7b02402015-12-09 19:05:09 +0100137int hnb_test_rx_ue_register_acc(struct hnb_test *hnb, ANY_t *in)
138{
139 int rc;
140 uint32_t ctx_id;
141 UERegisterAcceptIEs_t accept;
142 char imsi[16];
143
144 rc = hnbap_decode_ueregisteraccepties(&accept, in);
145 if (rc < 0) {
146 return rc;
147 }
148
149 if (accept.uE_Identity.present != UE_Identity_PR_iMSI) {
150 printf("Wrong type in UE register accept\n");
151 return -1;
152 }
153
154 ctx_id = asn1bitstr_to_u24(&accept.context_ID);
155
156 decode_iu_bcd(imsi, sizeof(imsi), accept.uE_Identity.choice.iMSI.buf,
157 accept.uE_Identity.choice.iMSI.size);
158 printf("UE Register accept for IMSI %s, context %u\n", imsi, ctx_id);
159
Daniel Willmann19dedbb2015-12-17 11:57:41 +0100160 hnb->ctx_id = ctx_id;
161
162 return hnb_test_ue_de_register_tx(hnb);
163
Daniel Willmanna7b02402015-12-09 19:05:09 +0100164 return 0;
165}
166
Daniel Willmann479cb302015-12-09 17:54:59 +0100167int hnb_test_hnbap_rx(struct hnb_test *hnb, struct msgb *msg)
168{
169 HNBAP_PDU_t _pdu, *pdu = &_pdu;
170 asn_dec_rval_t dec_ret;
171 int rc;
172
173 memset(pdu, 0, sizeof(*pdu));
174 dec_ret = aper_decode(NULL, &asn_DEF_HNBAP_PDU, (void **) &pdu,
175 msg->data, msgb_length(msg), 0, 0);
176 if (dec_ret.code != RC_OK) {
177 LOGP(DMAIN, LOGL_ERROR, "Error in ASN.1 decode\n");
178 return rc;
179 }
180
181 if (pdu->present != HNBAP_PDU_PR_successfulOutcome) {
182 printf("Unexpected HNBAP message received\n");
183 }
184
185 switch (pdu->choice.successfulOutcome.procedureCode) {
186 case ProcedureCode_id_HNBRegister:
187 /* Get HNB id and send UE Register request */
188 rc = hnb_test_rx_hnb_register_acc(hnb, &pdu->choice.successfulOutcome.value);
189 break;
190 case ProcedureCode_id_UERegister:
Daniel Willmanna7b02402015-12-09 19:05:09 +0100191 rc = hnb_test_rx_ue_register_acc(hnb, &pdu->choice.successfulOutcome.value);
Daniel Willmann479cb302015-12-09 17:54:59 +0100192 break;
193 default:
194 break;
195 }
196
197 return rc;
198}
199
Daniel Willmann97374c02015-12-03 09:37:58 +0100200static int hnb_read_cb(struct osmo_fd *fd)
201{
202 struct hnb_test *hnb_test = fd->data;
203 struct sctp_sndrcvinfo sinfo;
204 struct msgb *msg = msgb_alloc(IUH_MSGB_SIZE, "Iuh rx");
205 int flags = 0;
206 int rc;
207
208 if (!msg)
209 return -ENOMEM;
210
211 rc = sctp_recvmsg(fd->fd, msgb_data(msg), msgb_tailroom(msg),
212 NULL, NULL, &sinfo, &flags);
213 if (rc < 0) {
214 LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
215 /* FIXME: clean up after disappeared HNB */
Daniel Willmann6637a282015-12-17 14:47:51 +0100216 close(fd->fd);
217 osmo_fd_unregister(fd);
Daniel Willmann97374c02015-12-03 09:37:58 +0100218 return rc;
Daniel Willmann6637a282015-12-17 14:47:51 +0100219 } else if (rc == 0) {
220 LOGP(DMAIN, LOGL_INFO, "Connection to HNB closed\n");
221 close(fd->fd);
222 osmo_fd_unregister(fd);
223 fd->fd = -1;
224
225 return -1;
226 } else {
Daniel Willmann97374c02015-12-03 09:37:58 +0100227 msgb_put(msg, rc);
Daniel Willmann6637a282015-12-17 14:47:51 +0100228 }
Daniel Willmann97374c02015-12-03 09:37:58 +0100229
230 if (flags & MSG_NOTIFICATION) {
Daniel Willmann32797802015-12-17 12:53:05 +0100231 LOGP(DMAIN, LOGL_DEBUG, "Ignoring SCTP notification\n");
Daniel Willmann97374c02015-12-03 09:37:58 +0100232 msgb_free(msg);
233 return 0;
234 }
235
236 sinfo.sinfo_ppid = ntohl(sinfo.sinfo_ppid);
237
238 switch (sinfo.sinfo_ppid) {
239 case IUH_PPI_HNBAP:
240 printf("HNBAP mesage received\n");
Daniel Willmann479cb302015-12-09 17:54:59 +0100241 rc = hnb_test_hnbap_rx(hnb_test, msg);
Daniel Willmann97374c02015-12-03 09:37:58 +0100242 break;
243 case IUH_PPI_RUA:
244 printf("RUA mesage received\n");
245// rc = hnbgw_rua_rx(hnb, msg);
246 break;
247 case IUH_PPI_SABP:
248 case IUH_PPI_RNA:
249 case IUH_PPI_PUA:
250 LOGP(DMAIN, LOGL_ERROR, "Unimplemented SCTP PPID=%u received\n",
251 sinfo.sinfo_ppid);
252 rc = 0;
253 break;
254 default:
255 LOGP(DMAIN, LOGL_ERROR, "Unknown SCTP PPID=%u received\n",
256 sinfo.sinfo_ppid);
257 rc = 0;
258 break;
259 }
260
261 msgb_free(msg);
262 return rc;
263}
264
265static int hnb_write_cb(struct osmo_fd *fd, struct msgb *msg)
266{
267 struct hnb_test *ctx = fd->data;
268 struct sctp_sndrcvinfo sinfo = {
269 .sinfo_ppid = htonl(msgb_ppid(msg)),
270 .sinfo_stream = 0,
271 };
272 int rc;
273
274 rc = sctp_send(fd->fd, msgb_data(msg), msgb_length(msg),
275 &sinfo, 0);
276 /* we don't need to msgb_free(), write_queue does this for us */
277 return rc;
278}
279
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100280static void hnb_send_register_req(struct hnb_test *hnb_test)
281{
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100282 HNBRegisterRequest_t request_out;
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100283 struct msgb *msg;
284 int rc;
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100285 uint16_t lac, sac;
286 uint8_t rac;
287 uint32_t cid;
288 uint8_t plmn[] = {0x09, 0xf1, 0x99};
289 char identity[50] = "ATestHNB@";
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100290
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100291 HNBRegisterRequestIEs_t request;
292 memset(&request, 0, sizeof(request));
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100293
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100294 lac = 0xc0fe;
295 sac = 0xabab;
296 rac = 0x42;
Daniel Willmannd6a45b42015-12-08 13:55:17 +0100297 cid = 0xadceaab;
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100298
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100299 asn1_u16_to_str(&request.lac, &lac, lac);
300 asn1_u16_to_str(&request.sac, &sac, sac);
301 asn1_u8_to_str(&request.rac, &rac, rac);
Daniel Willmannd6a45b42015-12-08 13:55:17 +0100302 asn1_u28_to_bitstring(&request.cellIdentity, &cid, cid);
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100303
304 request.hnB_Identity.hNB_Identity_Info.buf = identity;
305 request.hnB_Identity.hNB_Identity_Info.size = strlen(identity);
306
307 request.plmNidentity.buf = plmn;
308 request.plmNidentity.size = 3;
309
310
311
312 memset(&request_out, 0, sizeof(request_out));
313 rc = hnbap_encode_hnbregisterrequesties(&request_out, &request);
314 if (rc < 0) {
315 printf("Could not encode HNB register request IEs\n");
316 }
317
318 msg = hnbap_generate_initiating_message(ProcedureCode_id_HNBRegister,
319 Criticality_reject,
320 &asn_DEF_HNBRegisterRequest,
321 &request_out);
322
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100323
324 msgb_ppid(msg) = IUH_PPI_HNBAP;
325
326 osmo_wqueue_enqueue(&hnb_test->wqueue, msg);
327}
328
329
Daniel Willmann97374c02015-12-03 09:37:58 +0100330static const struct log_info_cat log_cat[] = {
331 [DMAIN] = {
Daniel Willmann32797802015-12-17 12:53:05 +0100332 .name = "DMAIN", .loglevel = LOGL_INFO, .enabled = 1,
Daniel Willmann97374c02015-12-03 09:37:58 +0100333 .color = "",
334 .description = "Main program",
335 },
Daniel Willmann32797802015-12-17 12:53:05 +0100336 [DHNBAP] = {
337 .name = "DHNBAP", .loglevel = LOGL_DEBUG, .enabled = 1,
338 .color = "",
339 .description = "Home Node B Application Part",
340 },
Daniel Willmann97374c02015-12-03 09:37:58 +0100341};
342
343static const struct log_info hnb_test_log_info = {
344 .cat = log_cat,
345 .num_cat = ARRAY_SIZE(log_cat),
346};
347
348static struct vty_app_info vty_info = {
349 .name = "OsmoHNB-Test",
350 .version = "0",
351};
352
Daniel Willmann4abdee02015-12-09 17:57:32 +0100353static int sctp_sock_init(int fd)
354{
355 struct sctp_event_subscribe event;
356 int rc;
357
358 /* subscribe for all events */
359 memset((uint8_t *)&event, 1, sizeof(event));
360 rc = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
361 &event, sizeof(event));
362
363 return rc;
364}
365
Daniel Willmann97374c02015-12-03 09:37:58 +0100366int main(int argc, const char *argv)
367{
368 int rc;
369
370 tall_hnb_ctx = talloc_named_const(NULL, 0, "hnb_context");
371 talloc_asn1_ctx = talloc_named_const(NULL, 0, "asn1_context");
372
373 rc = osmo_init_logging(&hnb_test_log_info);
374 if (rc < 0)
375 exit(1);
376
377 vty_init(&vty_info);
378
379 osmo_wqueue_init(&g_hnb_test.wqueue, 16);
380 g_hnb_test.wqueue.bfd.data = &g_hnb_test;
381 g_hnb_test.wqueue.read_cb = hnb_read_cb;
382 g_hnb_test.wqueue.write_cb = hnb_write_cb;
383
384 rc = osmo_sock_init_ofd(&g_hnb_test.wqueue.bfd, AF_INET, SOCK_STREAM,
385 IPPROTO_SCTP, "127.0.0.1",
386 g_hnb_test.gw_port, OSMO_SOCK_F_CONNECT);
387 if (rc < 0) {
388 perror("Error connecting to Iuh port");
389 exit(1);
390 }
Daniel Willmann4abdee02015-12-09 17:57:32 +0100391 sctp_sock_init(g_hnb_test.wqueue.bfd.fd);
Daniel Willmann97374c02015-12-03 09:37:58 +0100392
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100393 hnb_send_register_req(&g_hnb_test);
394
Daniel Willmann97374c02015-12-03 09:37:58 +0100395 while (1) {
396 rc = osmo_select_main(0);
397 if (rc < 0)
398 exit(3);
399 }
400
401 /* not reached */
402 exit(0);
403}