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