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