blob: 17d955d3ad0aab561c07b1627a7d8017e6eb3ba3 [file] [log] [blame]
Neels Hofmeyraae68b22017-07-05 14:38:52 +02001/* Common parts of IuCS and IuPS interfaces implementation */
2
3/* (C) 2016-2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <stdint.h>
22#include <unistd.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <stdbool.h>
27
28#include <osmocom/ranap/iu_client.h>
29
30#include <osmocom/core/logging.h>
31#include <osmocom/crypt/auth.h>
32#include <osmocom/gprs/gprs_msgb.h>
33#include <osmocom/sigtran/sccp_sap.h>
34#include <osmocom/ranap/ranap_ies_defs.h>
35#include <osmocom/ranap/ranap_msg_factory.h>
36
37/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the
38 * PLMN identity is a BCD representation of the MCC and MNC.
39 * See iu_grnc_id_parse(). */
40struct iu_grnc_id {
41 uint16_t mcc;
42 uint16_t mnc;
43 uint16_t rnc_id;
44};
45
46/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has
47 * called us and is currently reachable at the given osmo_sccp_addr. So, when we
48 * know a LAC for a subscriber, we can page it at the RNC matching that LAC or
49 * RAC. An HNB-GW typically presents itself as if it were a single RNC, even
50 * though it may have several RNCs in hNodeBs connected to it. Those will then
51 * share the same RNC id, which they actually receive and adopt from the HNB-GW
52 * in the HNBAP HNB REGISTER ACCEPT message. */
53struct ranap_iu_rnc {
54 struct llist_head entry;
55
56 uint16_t rnc_id;
57 uint16_t lac; /* Location Area Code (used for CS and PS) */
58 uint8_t rac; /* Routing Area Code (used for PS only) */
59 struct osmo_sccp_addr sccp_addr;
60};
61
62void *talloc_iu_ctx;
63void *talloc_asn1_ctx;
64
65/* Implement the extern asn_debug from libasn1c to indicate whether to print
66 * asn.1 debug messages (see libasn1c). */
67int asn_debug = 0;
68
69/* Implement the extern asn1_xer_print to indicate whether the ASN.1 binary
70 * code decoded and encoded during Iu communication should be logged to stderr
71 * (see asn.1 generated code in osmo-iuh). */
72int asn1_xer_print = 0;
73
74ranap_iu_recv_cb_t global_iu_recv_cb = NULL;
75ranap_iu_event_cb_t global_iu_event_cb = NULL;
76int iu_log_subsystem = 0;
77
78#define LOGPIU(level, fmt, args...) \
79 LOGP(iu_log_subsystem, level, fmt, ## args)
80
81static LLIST_HEAD(ue_conn_ctx_list);
82static LLIST_HEAD(rnc_list);
83
84static struct osmo_sccp_instance *g_sccp;
85static struct osmo_sccp_user *g_scu;
Neels Hofmeyr1aef9a62017-08-12 18:02:44 +020086static struct osmo_sccp_addr g_local_sccp_addr;
Neels Hofmeyraae68b22017-07-05 14:38:52 +020087
88const struct value_string ranap_iu_event_type_names[] = {
89 OSMO_VALUE_STRING(RANAP_IU_EVENT_RAB_ASSIGN),
90 OSMO_VALUE_STRING(RANAP_IU_EVENT_SECURITY_MODE_COMPLETE),
91 OSMO_VALUE_STRING(RANAP_IU_EVENT_IU_RELEASE),
92 OSMO_VALUE_STRING(RANAP_IU_EVENT_LINK_INVALIDATED),
93 { 0, NULL }
94};
95
96static struct ranap_ue_conn_ctx *ue_conn_ctx_alloc(struct ranap_iu_rnc *rnc, uint32_t conn_id)
97{
98 struct ranap_ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ranap_ue_conn_ctx);
99
100 ctx->rnc = rnc;
101 ctx->conn_id = conn_id;
102 llist_add(&ctx->list, &ue_conn_ctx_list);
103
104 return ctx;
105}
106
107static struct ranap_ue_conn_ctx *ue_conn_ctx_find(uint32_t conn_id)
108{
109 struct ranap_ue_conn_ctx *ctx;
110
111 llist_for_each_entry(ctx, &ue_conn_ctx_list, list) {
112 if (ctx->conn_id == conn_id)
113 return ctx;
114 }
115 return NULL;
116}
117
118static struct ranap_iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac,
119 struct osmo_sccp_addr *addr)
120{
121 struct ranap_iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct ranap_iu_rnc);
122
123 rnc->rnc_id = rnc_id;
124 rnc->lac = lac;
125 rnc->rac = rac;
126 rnc->sccp_addr = *addr;
127 llist_add(&rnc->entry, &rnc_list);
128
129 LOGPIU(LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n",
130 rnc->rnc_id, rnc->lac, rnc->rac);
131
132 return rnc;
133}
134
135static struct ranap_iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac,
136 uint8_t rac, struct osmo_sccp_addr *addr)
137{
138 struct ranap_iu_rnc *rnc;
139 llist_for_each_entry(rnc, &rnc_list, entry) {
140 if (rnc->rnc_id != rnc_id)
141 continue;
142
143 /* We have this RNC Id registered already. Make sure that the
144 * details match. */
145
146 /* TODO should a mismatch be an error? */
147 if (rnc->lac != lac || rnc->rac != rac)
148 LOGPIU(LOGL_NOTICE, "RNC %d changes its details:"
149 " LAC=%d RAC=%d --> LAC=%d RAC=%d\n",
150 rnc->rnc_id, rnc->lac, rnc->rac,
151 lac, rac);
152 rnc->lac = lac;
153 rnc->rac = rac;
154
155 if (addr && memcmp(&rnc->sccp_addr, addr, sizeof(*addr)))
156 LOGPIU(LOGL_NOTICE, "RNC %d on New SCCP Addr %s"
157 " (LAC=%d RAC=%d)\n",
158 rnc->rnc_id, osmo_sccp_addr_dump(addr), rnc->lac, rnc->rac);
159 rnc->sccp_addr = *addr;
160 return rnc;
161 }
162
163 /* Not found, make a new one. */
164 return iu_rnc_alloc(rnc_id, lac, rac, addr);
165}
166
167/***********************************************************************
168 * RANAP handling
169 ***********************************************************************/
170
171int ranap_iu_rab_act(struct ranap_ue_conn_ctx *ue_ctx, struct msgb *msg)
172{
173 struct osmo_scu_prim *prim;
174
175 /* wrap RANAP message in SCCP N-DATA.req */
176 prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
177 prim->u.data.conn_id = ue_ctx->conn_id;
178 osmo_prim_init(&prim->oph,
179 SCCP_SAP_USER,
180 OSMO_SCU_PRIM_N_DATA,
181 PRIM_OP_REQUEST,
182 msg);
183 return osmo_sccp_user_sap_down(g_scu, &prim->oph);
184}
185
186int ranap_iu_rab_deact(struct ranap_ue_conn_ctx *ue_ctx, uint8_t rab_id)
187{
188 /* FIXME */
189 return -1;
190}
191
192int ranap_iu_tx_sec_mode_cmd(struct ranap_ue_conn_ctx *uectx, struct osmo_auth_vector *vec,
193 int send_ck, int new_key)
194{
195 struct osmo_scu_prim *prim;
196 struct msgb *msg;
197
198 /* create RANAP message */
199 msg = ranap_new_msg_sec_mod_cmd(vec->ik, send_ck? vec->ck : NULL,
200 new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old);
201 msg->l2h = msg->data;
202 /* wrap RANAP message in SCCP N-DATA.req */
203 prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
204 prim->u.data.conn_id = uectx->conn_id;
205 osmo_prim_init(&prim->oph, SCCP_SAP_USER,
206 OSMO_SCU_PRIM_N_DATA,
207 PRIM_OP_REQUEST, msg);
208 osmo_sccp_user_sap_down(g_scu, &prim->oph);
209
210 return 0;
211}
212
213int ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *uectx, const char *imsi)
214{
215 struct msgb *msg;
216 struct osmo_scu_prim *prim;
217
218 LOGPIU(LOGL_INFO, "Transmitting RANAP CommonID (SCCP conn_id %u)\n",
219 uectx->conn_id);
220
221 msg = ranap_new_msg_common_id(imsi);
222 msg->l2h = msg->data;
223 prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
224 prim->u.data.conn_id = uectx->conn_id;
225 osmo_prim_init(&prim->oph, SCCP_SAP_USER,
226 OSMO_SCU_PRIM_N_DATA,
227 PRIM_OP_REQUEST, msg);
228 osmo_sccp_user_sap_down(g_scu, &prim->oph);
229 return 0;
230}
231
232static int iu_grnc_id_parse(struct iu_grnc_id *dst, struct RANAP_GlobalRNC_ID *src)
233{
234 /* The size is coming from arbitrary sender, check it gracefully */
235 if (src->pLMNidentity.size != 3) {
236 LOGPIU(LOGL_ERROR, "Invalid PLMN Identity size:"
237 " should be 3, is %d\n", src->pLMNidentity.size);
238 return -1;
239 }
240 gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0],
241 &dst->mcc, &dst->mnc);
242 dst->rnc_id = (uint16_t)src->rNC_ID;
243 return 0;
244}
245
246#if 0
247 -- not used at present --
248static int iu_grnc_id_compose(struct iu_grnc_id *src, struct RANAP_GlobalRNC_ID *dst)
249{
250 /* The caller must ensure proper size */
251 OSMO_ASSERT(dst->pLMNidentity.size == 3);
252 gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0],
253 src->mcc, src->mnc);
254 dst->rNC_ID = src->rnc_id;
255 return 0;
256}
257#endif
258
259struct new_ue_conn_ctx {
260 struct osmo_sccp_addr sccp_addr;
261 uint32_t conn_id;
262};
263
264static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies)
265{
266 struct new_ue_conn_ctx *new_ctx = ctx;
267 struct gprs_ra_id ra_id;
268 struct iu_grnc_id grnc_id;
269 uint16_t sai;
270 struct ranap_ue_conn_ctx *ue;
271 struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
272 struct ranap_iu_rnc *rnc;
273
274 if (ranap_parse_lai(&ra_id, &ies->lai) != 0) {
275 LOGPIU(LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
276 return -1;
277 }
278
279 if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) {
280 ra_id.rac = asn1str_to_u8(&ies->rac);
281 }
282
283 if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) {
284 LOGPIU(LOGL_ERROR,
285 "Failed to parse RANAP Global-RNC-ID IE\n");
286 return -1;
287 }
288
289 sai = asn1str_to_u16(&ies->sai.sAC);
290 msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
291 memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
292
293 /* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */
294 rnc = iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, &new_ctx->sccp_addr);
295
296 ue = ue_conn_ctx_alloc(rnc, new_ctx->conn_id);
297 OSMO_ASSERT(ue);
298 ue->ra_id = ra_id;
299
300 /* Feed into the MM layer */
301 msg->dst = ue;
302 global_iu_recv_cb(msg, &ra_id, &sai);
303
304 msgb_free(msg);
305
306 return 0;
307}
308
309static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies)
310{
311 struct gprs_ra_id _ra_id, *ra_id = NULL;
312 uint16_t _sai, *sai = NULL;
313 struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
314
315 if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) {
316 if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) {
317 LOGPIU(LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
318 return -1;
319 }
320 ra_id = &_ra_id;
321 if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) {
322 _ra_id.rac = asn1str_to_u8(&ies->rac);
323 }
324 if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) {
325 _sai = asn1str_to_u16(&ies->sai.sAC);
326 sai = &_sai;
327 }
328 }
329
330 msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
331 memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
332
333 /* Feed into the MM/CC/SMS-CP layer */
334 msg->dst = ctx;
335 global_iu_recv_cb(msg, ra_id, sai);
336
337 msgb_free(msg);
338
339 return 0;
340}
341
342static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies)
343{
344 if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT)
345 LOGPIU(LOGL_ERROR, "Rx Error Indication (%s)\n",
346 ranap_cause_str(&ies->cause));
347 else
348 LOGPIU(LOGL_ERROR, "Rx Error Indication\n");
349
350 return 0;
351}
352
353int ranap_iu_tx(struct msgb *msg_nas, uint8_t sapi)
354{
355 struct ranap_ue_conn_ctx *uectx = msg_nas->dst;
356 struct msgb *msg;
357 struct osmo_scu_prim *prim;
358
359 LOGPIU(LOGL_INFO, "Transmitting L3 Message as RANAP DT (SCCP conn_id %u)\n",
360 uectx->conn_id);
361
362 msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas));
363 msgb_free(msg_nas);
364 msg->l2h = msg->data;
365 prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
366 prim->u.data.conn_id = uectx->conn_id;
367 osmo_prim_init(&prim->oph, SCCP_SAP_USER,
368 OSMO_SCU_PRIM_N_DATA,
369 PRIM_OP_REQUEST, msg);
370 osmo_sccp_user_sap_down(g_scu, &prim->oph);
371 return 0;
372}
373
374/* Send Iu Release for the given UE connection.
375 * If cause is NULL, the standard "No remaining RAB" cause is sent, otherwise
376 * the provided cause. */
377int ranap_iu_tx_release(struct ranap_ue_conn_ctx *ctx, const struct RANAP_Cause *cause)
378{
379 struct msgb *msg;
380 struct osmo_scu_prim *prim;
381 static const struct RANAP_Cause default_cause = {
382 .present = RANAP_Cause_PR_radioNetwork,
383 .choice.radioNetwork = RANAP_CauseRadioNetwork_no_remaining_rab,
384 };
385
386 if (!cause)
387 cause = &default_cause;
388
389 msg = ranap_new_msg_iu_rel_cmd(cause);
390 msg->l2h = msg->data;
391 prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
392 prim->u.data.conn_id = ctx->conn_id;
393 osmo_prim_init(&prim->oph, SCCP_SAP_USER,
394 OSMO_SCU_PRIM_N_DATA,
395 PRIM_OP_REQUEST, msg);
396 return osmo_sccp_user_sap_down(g_scu, &prim->oph);
397}
398
399static int ranap_handle_co_iu_rel_req(struct ranap_ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies)
400{
401 LOGPIU(LOGL_INFO, "Received Iu Release Request, Sending Release Command\n");
402 ranap_iu_tx_release(ctx, &ies->cause);
403 return 0;
404}
405
406static int ranap_handle_co_rab_ass_resp(struct ranap_ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies)
407{
408 int rc = -1;
409
410 LOGPIU(LOGL_INFO,
411 "Rx RAB Assignment Response for UE conn_id %u\n", ctx->conn_id);
412 if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) {
413 /* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */
414 RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0];
415 RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies;
416
417 rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value);
418 if (rc) {
419 LOGPIU(LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n");
420 return rc;
421 }
422
423 rc = global_iu_event_cb(ctx, RANAP_IU_EVENT_RAB_ASSIGN, &setup_ies);
424
425 ranap_free_rab_setupormodifieditemies(&setup_ies);
426 }
427 /* FIXME: handle RAB Ass failure? */
428
429 return rc;
430}
431
432static void cn_ranap_handle_co_initial(void *ctx, ranap_message *message)
433{
434 int rc;
435
436 LOGPIU(LOGL_NOTICE, "handle_co_initial(dir=%u, proc=%u)\n", message->direction, message->procedureCode);
437
438 if (message->direction != RANAP_RANAP_PDU_PR_initiatingMessage
439 || message->procedureCode != RANAP_ProcedureCode_id_InitialUE_Message) {
440 LOGPIU(LOGL_ERROR, "Expected direction 'InitiatingMessage',"
441 " procedureCode 'InitialUE_Message', instead got %u and %u\n",
442 message->direction, message->procedureCode);
443 rc = -1;
444 }
445 else
446 rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs);
447
448 if (rc) {
449 LOGPIU(LOGL_ERROR, "Error in %s (%d)\n", __func__, rc);
450 /* TODO handling of the error? */
451 }
452}
453
454/* Entry point for connection-oriented RANAP message */
455static void cn_ranap_handle_co(void *ctx, ranap_message *message)
456{
457 int rc;
458
459 LOGPIU(LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode);
460
461 switch (message->direction) {
462 case RANAP_RANAP_PDU_PR_initiatingMessage:
463 switch (message->procedureCode) {
464 case RANAP_ProcedureCode_id_InitialUE_Message:
465 LOGPIU(LOGL_ERROR, "Got InitialUE_Message but this is not a new conn\n");
466 rc = -1;
467 break;
468 case RANAP_ProcedureCode_id_DirectTransfer:
469 rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs);
470 break;
471 case RANAP_ProcedureCode_id_ErrorIndication:
472 rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs);
473 break;
474 case RANAP_ProcedureCode_id_Iu_ReleaseRequest:
475 /* Iu Release Request */
476 rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs);
477 break;
478 default:
479 LOGPIU(LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n",
480 message->procedureCode);
481 rc = -1;
482 break;
483 }
484 break;
485 case RANAP_RANAP_PDU_PR_successfulOutcome:
486 switch (message->procedureCode) {
487 case RANAP_ProcedureCode_id_SecurityModeControl:
488 /* Security Mode Complete */
489 rc = global_iu_event_cb(ctx, RANAP_IU_EVENT_SECURITY_MODE_COMPLETE, NULL);
490 break;
491 case RANAP_ProcedureCode_id_Iu_Release:
492 /* Iu Release Complete */
493 rc = global_iu_event_cb(ctx, RANAP_IU_EVENT_IU_RELEASE, NULL);
494 if (rc) {
495 LOGPIU(LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n",
496 rc);
497 }
498 break;
499 default:
500 LOGPIU(LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n",
501 message->procedureCode);
502 rc = -1;
503 break;
504 }
505 break;
506 case RANAP_RANAP_PDU_PR_outcome:
507 switch (message->procedureCode) {
508 case RANAP_ProcedureCode_id_RAB_Assignment:
509 /* RAB Assignment Response */
510 rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs);
511 break;
512 default:
513 LOGPIU(LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n",
514 message->procedureCode);
515 rc = -1;
516 break;
517 }
518 break;
519 case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
520 default:
521 LOGPIU(LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n",
522 message->procedureCode);
523 rc = -1;
524 break;
525 }
526
527 if (rc) {
528 LOGPIU(LOGL_ERROR, "Error in %s (%d)\n", __func__, rc);
529 /* TODO handling of the error? */
530 }
531}
532
533static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies)
534{
535 /* FIXME: send reset response */
536 return -1;
537}
538
539static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies)
540{
541 if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT)
542 LOGPIU(LOGL_ERROR, "Rx Error Indication (%s)\n",
543 ranap_cause_str(&ies->cause));
544 else
545 LOGPIU(LOGL_ERROR, "Rx Error Indication\n");
546
547 return 0;
548}
549
550/* Entry point for connection-less RANAP message */
551static void cn_ranap_handle_cl(void *ctx, ranap_message *message)
552{
553 int rc;
554
555 switch (message->direction) {
556 case RANAP_RANAP_PDU_PR_initiatingMessage:
557 switch (message->procedureCode) {
558 case RANAP_ProcedureCode_id_Reset:
559 /* received reset.req, send reset.resp */
560 rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs);
561 break;
562 case RANAP_ProcedureCode_id_ErrorIndication:
563 rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs);
564 break;
565 default:
566 rc = -1;
567 break;
568 }
569 break;
570 case RANAP_RANAP_PDU_PR_successfulOutcome:
571 case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
572 case RANAP_RANAP_PDU_PR_outcome:
573 default:
574 rc = -1;
575 break;
576 }
577
578 if (rc) {
579 LOGPIU(LOGL_ERROR, "Error in %s (%d)\n", __func__, rc);
580 /* TODO handling of the error? */
581 }
582}
583
584/***********************************************************************
585 * Paging
586 ***********************************************************************/
587
Neels Hofmeyraae68b22017-07-05 14:38:52 +0200588/* Send a paging command down a given SCCP User. tmsi and paging_cause are
589 * optional and may be passed NULL and 0, respectively, to disable their use.
590 * See enum RANAP_PagingCause.
591 *
592 * If TMSI is given, the IMSI is not sent over the air interface. Nevertheless,
593 * the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */
594static int iu_tx_paging_cmd(struct osmo_sccp_addr *called_addr,
595 const char *imsi, const uint32_t *tmsi,
596 bool is_ps, uint32_t paging_cause)
597{
598 struct msgb *msg;
599 msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause);
600 msg->l2h = msg->data;
Neels Hofmeyr1aef9a62017-08-12 18:02:44 +0200601 osmo_sccp_tx_unitdata_msg(g_scu, &g_local_sccp_addr, called_addr, msg);
Neels Hofmeyraae68b22017-07-05 14:38:52 +0200602 return 0;
603}
604
605static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi,
606 uint16_t lac, uint8_t rac, bool is_ps)
607{
608 struct ranap_iu_rnc *rnc;
609 int pagings_sent = 0;
610
611 if (tmsi_or_ptimsi) {
612 LOGPIU(LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s"
613 " (paging will use %s %x)\n",
614 is_ps? "IuPS" : "IuCS",
615 imsi,
616 is_ps? "PTMSI" : "TMSI",
617 *tmsi_or_ptimsi);
618 } else {
619 LOGPIU(LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s"
620 " (paging will use IMSI)\n",
621 is_ps? "IuPS" : "IuCS",
622 imsi
623 );
624 }
625
626 llist_for_each_entry(rnc, &rnc_list, entry) {
627 if (rnc->lac != lac)
628 continue;
629 if (is_ps && rnc->rac != rac)
630 continue;
631
632 /* Found a match! */
633 if (iu_tx_paging_cmd(&rnc->sccp_addr, imsi, tmsi_or_ptimsi, is_ps, 0)
634 == 0) {
635 LOGPIU(LOGL_DEBUG,
636 "%s: Paged for IMSI %s on RNC %d, on SCCP addr %s\n",
637 is_ps? "IuPS" : "IuCS",
638 imsi, rnc->rnc_id, osmo_sccp_addr_dump(&rnc->sccp_addr));
639 pagings_sent ++;
640 }
641 }
642
643 /* Some logging... */
644 if (pagings_sent > 0) {
645 LOGPIU(LOGL_DEBUG,
646 "%s: %d RNCs were paged for IMSI %s.\n",
647 is_ps? "IuPS" : "IuCS",
648 pagings_sent, imsi);
649 }
650 else {
651 if (is_ps) {
652 LOGPIU(LOGL_ERROR, "IuPS: Found no RNC to page for"
653 " LAC %d RAC %d (would have paged IMSI %s)\n",
654 lac, rac, imsi);
655 }
656 else {
657 LOGPIU(LOGL_ERROR, "IuCS: Found no RNC to page for"
658 " LAC %d (would have paged IMSI %s)\n",
659 lac, imsi);
660 }
661 }
662
663 return pagings_sent;
664}
665
666int ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac)
667{
668 return iu_page(imsi, tmsi, lac, 0, false);
669}
670
671int ranap_iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac)
672{
673 return iu_page(imsi, ptmsi, lac, rac, true);
674}
675
676
677/***********************************************************************
678 *
679 ***********************************************************************/
680
681int tx_unitdata(struct osmo_sccp_user *scu);
682int tx_conn_req(struct osmo_sccp_user *scu, uint32_t conn_id);
683
684struct osmo_prim_hdr *make_conn_req(uint32_t conn_id);
685struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len);
686
687static struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param)
688{
689 struct msgb *msg = msgb_alloc(1024, "conn_resp");
690 struct osmo_scu_prim *prim;
691
692 prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim));
693 osmo_prim_init(&prim->oph, SCCP_SAP_USER,
694 OSMO_SCU_PRIM_N_CONNECT,
695 PRIM_OP_RESPONSE, msg);
696 memcpy(&prim->u.connect, param, sizeof(prim->u.connect));
697 return &prim->oph;
698}
699
700static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
701{
702 struct osmo_sccp_user *scu = _scu;
703 struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;
704 struct osmo_prim_hdr *resp = NULL;
705 int rc;
706 struct ranap_ue_conn_ctx *ue;
707 struct new_ue_conn_ctx new_ctx = {};
708
709 LOGPIU(LOGL_DEBUG, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph));
710
711 switch (OSMO_PRIM_HDR(oph)) {
712 case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
713 /* confirmation of outbound connection */
714 rc = -1;
715 break;
716 case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):
717 /* indication of new inbound connection request*/
718 LOGPIU(LOGL_DEBUG, "N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id);
719 if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */
720 !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) {
721 LOGPIU(LOGL_NOTICE,
722 "Received invalid N-CONNECT.ind\n");
723 return 0;
724 }
725 new_ctx.sccp_addr = prim->u.connect.calling_addr;
726 new_ctx.conn_id = prim->u.connect.conn_id;
727 /* first ensure the local SCCP socket is ACTIVE */
728 resp = make_conn_resp(&prim->u.connect);
729 osmo_sccp_user_sap_down(scu, resp);
730 /* then handle the RANAP payload */
731 rc = ranap_cn_rx_co(cn_ranap_handle_co_initial, &new_ctx, msgb_l2(oph->msg), msgb_l2len(oph->msg));
732 break;
733 case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
734 /* indication of disconnect */
735 LOGPIU(LOGL_DEBUG, "N-DISCONNECT.ind(%u)\n",
736 prim->u.disconnect.conn_id);
737 ue = ue_conn_ctx_find(prim->u.disconnect.conn_id);
738 rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
739 break;
740 case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
741 /* connection-oriented data received */
742 LOGPIU(LOGL_DEBUG, "N-DATA.ind(%u, %s)\n", prim->u.data.conn_id,
743 osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
744 /* resolve UE context */
745 ue = ue_conn_ctx_find(prim->u.data.conn_id);
746 rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
747 break;
748 case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
749 /* connection-less data received */
750 LOGPIU(LOGL_DEBUG, "N-UNITDATA.ind(%s)\n",
751 osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
752 rc = ranap_cn_rx_cl(cn_ranap_handle_cl, scu, msgb_l2(oph->msg), msgb_l2len(oph->msg));
753 break;
754 default:
755 rc = -1;
756 break;
757 }
758
759 msgb_free(oph->msg);
760 return rc;
761}
762
763int ranap_iu_init(void *ctx, int log_subsystem, const char *sccp_user_name, struct osmo_sccp_instance *sccp,
764 ranap_iu_recv_cb_t iu_recv_cb, ranap_iu_event_cb_t iu_event_cb)
765{
766 iu_log_subsystem = log_subsystem;
767 talloc_iu_ctx = talloc_named_const(ctx, 1, "iu");
768 talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1");
769
770 global_iu_recv_cb = iu_recv_cb;
771 global_iu_event_cb = iu_event_cb;
772 g_sccp = sccp;
Neels Hofmeyr1aef9a62017-08-12 18:02:44 +0200773 osmo_sccp_local_addr_by_instance(&g_local_sccp_addr, sccp, OSMO_SCCP_SSN_RANAP);
Neels Hofmeyraae68b22017-07-05 14:38:52 +0200774 g_scu = osmo_sccp_user_bind(g_sccp, sccp_user_name, sccp_sap_up, OSMO_SCCP_SSN_RANAP);
775
776 return 0;
777}
778