blob: 90b2f38f065b8f8fe375c2c8c6c857dfbc395170 [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 Willmann479cb302015-12-09 17:54:59 +010058int hnb_test_ue_register_tx(struct hnb_test *hnb_test)
59{
Daniel Willmann4e312502015-12-09 17:59:24 +010060 struct msgb *msg;
61 int rc, imsi_len;
62
63 char imsi_buf[16];
64 char *imsi_str = "262019876543210";
65
66 UERegisterRequest_t request_out;
67 UERegisterRequestIEs_t request;
68 memset(&request, 0, sizeof(request));
69
70 request.uE_Identity.present = UE_Identity_PR_iMSI;
71
72 imsi_len = encode_iu_imsi(imsi_buf, sizeof(imsi_buf), imsi_str);
73 request.uE_Identity.choice.iMSI.buf = imsi_buf;
74 request.uE_Identity.choice.iMSI.size = imsi_len;
75
76 request.registration_Cause = Registration_Cause_normal;
77 request.uE_Capabilities.access_stratum_release_indicator = Access_stratum_release_indicator_rel_6;
78 request.uE_Capabilities.csg_capability = CSG_Capability_not_csg_capable;
79
80 memset(&request_out, 0, sizeof(request_out));
81 rc = hnbap_encode_ueregisterrequesties(&request_out, &request);
82
83 msg = hnbap_generate_initiating_message(ProcedureCode_id_UERegister,
84 Criticality_reject,
85 &asn_DEF_UERegisterRequest,
86 &request_out);
87
88
89 msgb_ppid(msg) = IUH_PPI_HNBAP;
90
91 return osmo_wqueue_enqueue(&hnb_test->wqueue, msg);
Daniel Willmann479cb302015-12-09 17:54:59 +010092}
93
94int hnb_test_rx_hnb_register_acc(struct hnb_test *hnb, ANY_t *in)
95{
96 int rc;
97 HNBRegisterAcceptIEs_t accept;
98
99 rc = hnbap_decode_hnbregisteraccepties(&accept, in);
100 if (rc < 0) {
101 }
102
103 hnb->rnc_id = accept.rnc_id;
104 printf("HNB Register accept with RNC ID %u\n", hnb->rnc_id);
105
106 return hnb_test_ue_register_tx(hnb);
107}
108
109int hnb_test_hnbap_rx(struct hnb_test *hnb, struct msgb *msg)
110{
111 HNBAP_PDU_t _pdu, *pdu = &_pdu;
112 asn_dec_rval_t dec_ret;
113 int rc;
114
115 memset(pdu, 0, sizeof(*pdu));
116 dec_ret = aper_decode(NULL, &asn_DEF_HNBAP_PDU, (void **) &pdu,
117 msg->data, msgb_length(msg), 0, 0);
118 if (dec_ret.code != RC_OK) {
119 LOGP(DMAIN, LOGL_ERROR, "Error in ASN.1 decode\n");
120 return rc;
121 }
122
123 if (pdu->present != HNBAP_PDU_PR_successfulOutcome) {
124 printf("Unexpected HNBAP message received\n");
125 }
126
127 switch (pdu->choice.successfulOutcome.procedureCode) {
128 case ProcedureCode_id_HNBRegister:
129 /* Get HNB id and send UE Register request */
130 rc = hnb_test_rx_hnb_register_acc(hnb, &pdu->choice.successfulOutcome.value);
131 break;
132 case ProcedureCode_id_UERegister:
133 break;
134 default:
135 break;
136 }
137
138 return rc;
139}
140
Daniel Willmann97374c02015-12-03 09:37:58 +0100141static int hnb_read_cb(struct osmo_fd *fd)
142{
143 struct hnb_test *hnb_test = fd->data;
144 struct sctp_sndrcvinfo sinfo;
145 struct msgb *msg = msgb_alloc(IUH_MSGB_SIZE, "Iuh rx");
146 int flags = 0;
147 int rc;
148
149 if (!msg)
150 return -ENOMEM;
151
152 rc = sctp_recvmsg(fd->fd, msgb_data(msg), msgb_tailroom(msg),
153 NULL, NULL, &sinfo, &flags);
154 if (rc < 0) {
155 LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
156 /* FIXME: clean up after disappeared HNB */
157 return rc;
158 } else
159 msgb_put(msg, rc);
160
161 if (flags & MSG_NOTIFICATION) {
162 LOGP(DMAIN, LOGL_INFO, "Ignoring SCTP notification\n");
163 msgb_free(msg);
164 return 0;
165 }
166
167 sinfo.sinfo_ppid = ntohl(sinfo.sinfo_ppid);
168
169 switch (sinfo.sinfo_ppid) {
170 case IUH_PPI_HNBAP:
171 printf("HNBAP mesage received\n");
Daniel Willmann479cb302015-12-09 17:54:59 +0100172 rc = hnb_test_hnbap_rx(hnb_test, msg);
Daniel Willmann97374c02015-12-03 09:37:58 +0100173 break;
174 case IUH_PPI_RUA:
175 printf("RUA mesage received\n");
176// rc = hnbgw_rua_rx(hnb, msg);
177 break;
178 case IUH_PPI_SABP:
179 case IUH_PPI_RNA:
180 case IUH_PPI_PUA:
181 LOGP(DMAIN, LOGL_ERROR, "Unimplemented SCTP PPID=%u received\n",
182 sinfo.sinfo_ppid);
183 rc = 0;
184 break;
185 default:
186 LOGP(DMAIN, LOGL_ERROR, "Unknown SCTP PPID=%u received\n",
187 sinfo.sinfo_ppid);
188 rc = 0;
189 break;
190 }
191
192 msgb_free(msg);
193 return rc;
194}
195
196static int hnb_write_cb(struct osmo_fd *fd, struct msgb *msg)
197{
198 struct hnb_test *ctx = fd->data;
199 struct sctp_sndrcvinfo sinfo = {
200 .sinfo_ppid = htonl(msgb_ppid(msg)),
201 .sinfo_stream = 0,
202 };
203 int rc;
204
205 rc = sctp_send(fd->fd, msgb_data(msg), msgb_length(msg),
206 &sinfo, 0);
207 /* we don't need to msgb_free(), write_queue does this for us */
208 return rc;
209}
210
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100211#include "pdus.h"
212
213static void hnb_send_register_req(struct hnb_test *hnb_test)
214{
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100215 HNBRegisterRequest_t request_out;
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100216 struct msgb *msg;
217 int rc;
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100218 uint16_t lac, sac;
219 uint8_t rac;
220 uint32_t cid;
221 uint8_t plmn[] = {0x09, 0xf1, 0x99};
222 char identity[50] = "ATestHNB@";
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100223
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100224 HNBRegisterRequestIEs_t request;
225 memset(&request, 0, sizeof(request));
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100226
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100227 lac = 0xc0fe;
228 sac = 0xabab;
229 rac = 0x42;
Daniel Willmannd6a45b42015-12-08 13:55:17 +0100230 cid = 0xadceaab;
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100231
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100232 asn1_u16_to_str(&request.lac, &lac, lac);
233 asn1_u16_to_str(&request.sac, &sac, sac);
234 asn1_u8_to_str(&request.rac, &rac, rac);
Daniel Willmannd6a45b42015-12-08 13:55:17 +0100235 asn1_u28_to_bitstring(&request.cellIdentity, &cid, cid);
Daniel Willmanna1e202e2015-12-07 17:21:07 +0100236
237 request.hnB_Identity.hNB_Identity_Info.buf = identity;
238 request.hnB_Identity.hNB_Identity_Info.size = strlen(identity);
239
240 request.plmNidentity.buf = plmn;
241 request.plmNidentity.size = 3;
242
243
244
245 memset(&request_out, 0, sizeof(request_out));
246 rc = hnbap_encode_hnbregisterrequesties(&request_out, &request);
247 if (rc < 0) {
248 printf("Could not encode HNB register request IEs\n");
249 }
250
251 msg = hnbap_generate_initiating_message(ProcedureCode_id_HNBRegister,
252 Criticality_reject,
253 &asn_DEF_HNBRegisterRequest,
254 &request_out);
255
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100256
257 msgb_ppid(msg) = IUH_PPI_HNBAP;
258
259 osmo_wqueue_enqueue(&hnb_test->wqueue, msg);
260}
261
262
Daniel Willmann97374c02015-12-03 09:37:58 +0100263static const struct log_info_cat log_cat[] = {
264 [DMAIN] = {
265 .name = "DMAIN", .loglevel = LOGL_DEBUG, .enabled = 1,
266 .color = "",
267 .description = "Main program",
268 },
269};
270
271static const struct log_info hnb_test_log_info = {
272 .cat = log_cat,
273 .num_cat = ARRAY_SIZE(log_cat),
274};
275
276static struct vty_app_info vty_info = {
277 .name = "OsmoHNB-Test",
278 .version = "0",
279};
280
Daniel Willmann4abdee02015-12-09 17:57:32 +0100281static int sctp_sock_init(int fd)
282{
283 struct sctp_event_subscribe event;
284 int rc;
285
286 /* subscribe for all events */
287 memset((uint8_t *)&event, 1, sizeof(event));
288 rc = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
289 &event, sizeof(event));
290
291 return rc;
292}
293
Daniel Willmann97374c02015-12-03 09:37:58 +0100294int main(int argc, const char *argv)
295{
296 int rc;
297
298 tall_hnb_ctx = talloc_named_const(NULL, 0, "hnb_context");
299 talloc_asn1_ctx = talloc_named_const(NULL, 0, "asn1_context");
300
301 rc = osmo_init_logging(&hnb_test_log_info);
302 if (rc < 0)
303 exit(1);
304
305 vty_init(&vty_info);
306
307 osmo_wqueue_init(&g_hnb_test.wqueue, 16);
308 g_hnb_test.wqueue.bfd.data = &g_hnb_test;
309 g_hnb_test.wqueue.read_cb = hnb_read_cb;
310 g_hnb_test.wqueue.write_cb = hnb_write_cb;
311
312 rc = osmo_sock_init_ofd(&g_hnb_test.wqueue.bfd, AF_INET, SOCK_STREAM,
313 IPPROTO_SCTP, "127.0.0.1",
314 g_hnb_test.gw_port, OSMO_SOCK_F_CONNECT);
315 if (rc < 0) {
316 perror("Error connecting to Iuh port");
317 exit(1);
318 }
Daniel Willmann4abdee02015-12-09 17:57:32 +0100319 sctp_sock_init(g_hnb_test.wqueue.bfd.fd);
Daniel Willmann97374c02015-12-03 09:37:58 +0100320
Daniel Willmann4aeef6c2015-12-03 17:02:13 +0100321 hnb_send_register_req(&g_hnb_test);
322
Daniel Willmann97374c02015-12-03 09:37:58 +0100323 while (1) {
324 rc = osmo_select_main(0);
325 if (rc < 0)
326 exit(3);
327 }
328
329 /* not reached */
330 exit(0);
331}