blob: 325ace84034850aa17df3685b4410813da83ae10 [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
Daniel Willmann141a0ba2015-12-17 18:03:52 +010094 if (hnb_test->ues > 0) {
95 hnb_test->ues--;
96 } else {
97 return 0;
98 }
99
Daniel Willmann4e312502015-12-09 17:59:24 +0100100 UERegisterRequest_t request_out;
101 UERegisterRequestIEs_t request;
102 memset(&request, 0, sizeof(request));
103
104 request.uE_Identity.present = UE_Identity_PR_iMSI;
105
106 imsi_len = encode_iu_imsi(imsi_buf, sizeof(imsi_buf), imsi_str);
107 request.uE_Identity.choice.iMSI.buf = imsi_buf;
108 request.uE_Identity.choice.iMSI.size = imsi_len;
109
110 request.registration_Cause = Registration_Cause_normal;
111 request.uE_Capabilities.access_stratum_release_indicator = Access_stratum_release_indicator_rel_6;
112 request.uE_Capabilities.csg_capability = CSG_Capability_not_csg_capable;
113
114 memset(&request_out, 0, sizeof(request_out));
115 rc = hnbap_encode_ueregisterrequesties(&request_out, &request);
116
117 msg = hnbap_generate_initiating_message(ProcedureCode_id_UERegister,
118 Criticality_reject,
119 &asn_DEF_UERegisterRequest,
120 &request_out);
121
122
123 msgb_ppid(msg) = IUH_PPI_HNBAP;
124
125 return osmo_wqueue_enqueue(&hnb_test->wqueue, msg);
Daniel Willmann479cb302015-12-09 17:54:59 +0100126}
127
128int hnb_test_rx_hnb_register_acc(struct hnb_test *hnb, ANY_t *in)
129{
130 int rc;
131 HNBRegisterAcceptIEs_t accept;
132
133 rc = hnbap_decode_hnbregisteraccepties(&accept, in);
134 if (rc < 0) {
135 }
136
137 hnb->rnc_id = accept.rnc_id;
138 printf("HNB Register accept with RNC ID %u\n", hnb->rnc_id);
139
140 return hnb_test_ue_register_tx(hnb);
141}
142
Daniel Willmanna7b02402015-12-09 19:05:09 +0100143int hnb_test_rx_ue_register_acc(struct hnb_test *hnb, ANY_t *in)
144{
145 int rc;
146 uint32_t ctx_id;
147 UERegisterAcceptIEs_t accept;
148 char imsi[16];
149
150 rc = hnbap_decode_ueregisteraccepties(&accept, in);
151 if (rc < 0) {
152 return rc;
153 }
154
155 if (accept.uE_Identity.present != UE_Identity_PR_iMSI) {
156 printf("Wrong type in UE register accept\n");
157 return -1;
158 }
159
160 ctx_id = asn1bitstr_to_u24(&accept.context_ID);
161
162 decode_iu_bcd(imsi, sizeof(imsi), accept.uE_Identity.choice.iMSI.buf,
163 accept.uE_Identity.choice.iMSI.size);
164 printf("UE Register accept for IMSI %s, context %u\n", imsi, ctx_id);
165
Daniel Willmann19dedbb2015-12-17 11:57:41 +0100166 hnb->ctx_id = ctx_id;
167
168 return hnb_test_ue_de_register_tx(hnb);
169
Daniel Willmanna7b02402015-12-09 19:05:09 +0100170 return 0;
171}
172
Daniel Willmann479cb302015-12-09 17:54:59 +0100173int hnb_test_hnbap_rx(struct hnb_test *hnb, struct msgb *msg)
174{
175 HNBAP_PDU_t _pdu, *pdu = &_pdu;
176 asn_dec_rval_t dec_ret;
177 int rc;
178
179 memset(pdu, 0, sizeof(*pdu));
180 dec_ret = aper_decode(NULL, &asn_DEF_HNBAP_PDU, (void **) &pdu,
181 msg->data, msgb_length(msg), 0, 0);
182 if (dec_ret.code != RC_OK) {
183 LOGP(DMAIN, LOGL_ERROR, "Error in ASN.1 decode\n");
184 return rc;
185 }
186
187 if (pdu->present != HNBAP_PDU_PR_successfulOutcome) {
188 printf("Unexpected HNBAP message received\n");
189 }
190
191 switch (pdu->choice.successfulOutcome.procedureCode) {
192 case ProcedureCode_id_HNBRegister:
193 /* Get HNB id and send UE Register request */
194 rc = hnb_test_rx_hnb_register_acc(hnb, &pdu->choice.successfulOutcome.value);
195 break;
196 case ProcedureCode_id_UERegister:
Daniel Willmanna7b02402015-12-09 19:05:09 +0100197 rc = hnb_test_rx_ue_register_acc(hnb, &pdu->choice.successfulOutcome.value);
Daniel Willmann141a0ba2015-12-17 18:03:52 +0100198 hnb_test_ue_register_tx(hnb);
Daniel Willmann479cb302015-12-09 17:54:59 +0100199 break;
200 default:
201 break;
202 }
203
204 return rc;
205}
206
Daniel Willmann97374c02015-12-03 09:37:58 +0100207static int hnb_read_cb(struct osmo_fd *fd)
208{
209 struct hnb_test *hnb_test = fd->data;
210 struct sctp_sndrcvinfo sinfo;
211 struct msgb *msg = msgb_alloc(IUH_MSGB_SIZE, "Iuh rx");
212 int flags = 0;
213 int rc;
214
215 if (!msg)
216 return -ENOMEM;
217
218 rc = sctp_recvmsg(fd->fd, msgb_data(msg), msgb_tailroom(msg),
219 NULL, NULL, &sinfo, &flags);
220 if (rc < 0) {
221 LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
222 /* FIXME: clean up after disappeared HNB */
Daniel Willmann6637a282015-12-17 14:47:51 +0100223 close(fd->fd);
224 osmo_fd_unregister(fd);
Daniel Willmann97374c02015-12-03 09:37:58 +0100225 return rc;
Daniel Willmann6637a282015-12-17 14:47:51 +0100226 } else if (rc == 0) {
227 LOGP(DMAIN, LOGL_INFO, "Connection to HNB closed\n");
228 close(fd->fd);
229 osmo_fd_unregister(fd);
230 fd->fd = -1;
231
232 return -1;
233 } else {
Daniel Willmann97374c02015-12-03 09:37:58 +0100234 msgb_put(msg, rc);
Daniel Willmann6637a282015-12-17 14:47:51 +0100235 }
Daniel Willmann97374c02015-12-03 09:37:58 +0100236
237 if (flags & MSG_NOTIFICATION) {
Daniel Willmann32797802015-12-17 12:53:05 +0100238 LOGP(DMAIN, LOGL_DEBUG, "Ignoring SCTP notification\n");
Daniel Willmann97374c02015-12-03 09:37:58 +0100239 msgb_free(msg);
240 return 0;
241 }
242
243 sinfo.sinfo_ppid = ntohl(sinfo.sinfo_ppid);
244
245 switch (sinfo.sinfo_ppid) {
246 case IUH_PPI_HNBAP:
247 printf("HNBAP mesage received\n");
Daniel Willmann479cb302015-12-09 17:54:59 +0100248 rc = hnb_test_hnbap_rx(hnb_test, msg);
Daniel Willmann97374c02015-12-03 09:37:58 +0100249 break;
250 case IUH_PPI_RUA:
251 printf("RUA mesage received\n");
252// rc = hnbgw_rua_rx(hnb, msg);
253 break;
254 case IUH_PPI_SABP:
255 case IUH_PPI_RNA:
256 case IUH_PPI_PUA:
257 LOGP(DMAIN, LOGL_ERROR, "Unimplemented SCTP PPID=%u received\n",
258 sinfo.sinfo_ppid);
259 rc = 0;
260 break;
261 default:
262 LOGP(DMAIN, LOGL_ERROR, "Unknown SCTP PPID=%u received\n",
263 sinfo.sinfo_ppid);
264 rc = 0;
265 break;
266 }
267
268 msgb_free(msg);
269 return rc;
270}
271
272static int hnb_write_cb(struct osmo_fd *fd, struct msgb *msg)
273{
274 struct hnb_test *ctx = fd->data;
275 struct sctp_sndrcvinfo sinfo = {
276 .sinfo_ppid = htonl(msgb_ppid(msg)),
277 .sinfo_stream = 0,
278 };
279 int rc;
280
281 rc = sctp_send(fd->fd, msgb_data(msg), msgb_length(msg),
282 &sinfo, 0);
283 /* we don't need to msgb_free(), write_queue does this for us */
284 return rc;
285}
286
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100287static void hnb_send_register_req(struct hnb_test *hnb_test)
288{
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100289 HNBRegisterRequest_t request_out;
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100290 struct msgb *msg;
291 int rc;
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100292 uint16_t lac, sac;
293 uint8_t rac;
294 uint32_t cid;
295 uint8_t plmn[] = {0x09, 0xf1, 0x99};
296 char identity[50] = "ATestHNB@";
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100297
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100298 HNBRegisterRequestIEs_t request;
299 memset(&request, 0, sizeof(request));
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100300
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100301 lac = 0xc0fe;
302 sac = 0xabab;
303 rac = 0x42;
Daniel Willmannd6a45b42015-12-08 13:55:17 +0100304 cid = 0xadceaab;
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100305
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100306 asn1_u16_to_str(&request.lac, &lac, lac);
307 asn1_u16_to_str(&request.sac, &sac, sac);
308 asn1_u8_to_str(&request.rac, &rac, rac);
Daniel Willmannd6a45b42015-12-08 13:55:17 +0100309 asn1_u28_to_bitstring(&request.cellIdentity, &cid, cid);
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100310
311 request.hnB_Identity.hNB_Identity_Info.buf = identity;
312 request.hnB_Identity.hNB_Identity_Info.size = strlen(identity);
313
314 request.plmNidentity.buf = plmn;
315 request.plmNidentity.size = 3;
316
317
318
319 memset(&request_out, 0, sizeof(request_out));
320 rc = hnbap_encode_hnbregisterrequesties(&request_out, &request);
321 if (rc < 0) {
322 printf("Could not encode HNB register request IEs\n");
323 }
324
325 msg = hnbap_generate_initiating_message(ProcedureCode_id_HNBRegister,
326 Criticality_reject,
327 &asn_DEF_HNBRegisterRequest,
328 &request_out);
329
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100330
331 msgb_ppid(msg) = IUH_PPI_HNBAP;
332
333 osmo_wqueue_enqueue(&hnb_test->wqueue, msg);
334}
335
336
Daniel Willmann97374c02015-12-03 09:37:58 +0100337static const struct log_info_cat log_cat[] = {
338 [DMAIN] = {
Daniel Willmann32797802015-12-17 12:53:05 +0100339 .name = "DMAIN", .loglevel = LOGL_INFO, .enabled = 1,
Daniel Willmann97374c02015-12-03 09:37:58 +0100340 .color = "",
341 .description = "Main program",
342 },
Daniel Willmann32797802015-12-17 12:53:05 +0100343 [DHNBAP] = {
344 .name = "DHNBAP", .loglevel = LOGL_DEBUG, .enabled = 1,
345 .color = "",
346 .description = "Home Node B Application Part",
347 },
Daniel Willmann97374c02015-12-03 09:37:58 +0100348};
349
350static const struct log_info hnb_test_log_info = {
351 .cat = log_cat,
352 .num_cat = ARRAY_SIZE(log_cat),
353};
354
355static struct vty_app_info vty_info = {
356 .name = "OsmoHNB-Test",
357 .version = "0",
358};
359
Daniel Willmann4abdee02015-12-09 17:57:32 +0100360static int sctp_sock_init(int fd)
361{
362 struct sctp_event_subscribe event;
363 int rc;
364
365 /* subscribe for all events */
366 memset((uint8_t *)&event, 1, sizeof(event));
367 rc = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
368 &event, sizeof(event));
369
370 return rc;
371}
372
Daniel Willmann141a0ba2015-12-17 18:03:52 +0100373static void handle_options(int argc, char **argv)
374{
375 while (1) {
376 int idx = 0, c;
377 static const struct option long_options[] = {
378 { "ues", 1, 0, 'u' },
379 { 0, 0, 0, 0 },
380 };
381
382 c = getopt_long(argc, argv, "u:", long_options, &idx);
383
384 if (c == -1)
385 break;
386
387 switch (c) {
388 case 'u':
389 g_hnb_test.ues = atoi(optarg);
390 break;
391 }
392 }
393}
394
Daniel Willmann97374c02015-12-03 09:37:58 +0100395int main(int argc, const char *argv)
396{
397 int rc;
398
399 tall_hnb_ctx = talloc_named_const(NULL, 0, "hnb_context");
400 talloc_asn1_ctx = talloc_named_const(NULL, 0, "asn1_context");
401
402 rc = osmo_init_logging(&hnb_test_log_info);
403 if (rc < 0)
404 exit(1);
405
406 vty_init(&vty_info);
407
Daniel Willmann141a0ba2015-12-17 18:03:52 +0100408 handle_options(argc, argv);
409
Daniel Willmann97374c02015-12-03 09:37:58 +0100410 osmo_wqueue_init(&g_hnb_test.wqueue, 16);
411 g_hnb_test.wqueue.bfd.data = &g_hnb_test;
412 g_hnb_test.wqueue.read_cb = hnb_read_cb;
413 g_hnb_test.wqueue.write_cb = hnb_write_cb;
414
415 rc = osmo_sock_init_ofd(&g_hnb_test.wqueue.bfd, AF_INET, SOCK_STREAM,
416 IPPROTO_SCTP, "127.0.0.1",
417 g_hnb_test.gw_port, OSMO_SOCK_F_CONNECT);
418 if (rc < 0) {
419 perror("Error connecting to Iuh port");
420 exit(1);
421 }
Daniel Willmann4abdee02015-12-09 17:57:32 +0100422 sctp_sock_init(g_hnb_test.wqueue.bfd.fd);
Daniel Willmann97374c02015-12-03 09:37:58 +0100423
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100424 hnb_send_register_req(&g_hnb_test);
425
Daniel Willmann97374c02015-12-03 09:37:58 +0100426 while (1) {
427 rc = osmo_select_main(0);
428 if (rc < 0)
429 exit(3);
430 }
431
432 /* not reached */
433 exit(0);
434}