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