blob: 432fe6ae768d3e5272334d177d53590b6dcf20a7 [file] [log] [blame]
Harald Weltec4338de2015-12-24 00:40:52 +01001/* IuCS/IuPS Core Network interface of HNB-GW */
2
3/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
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 <osmocom/core/msgb.h>
22#include <osmocom/core/utils.h>
23#include <osmocom/core/timer.h>
24
25#include <osmocom/sigtran/protocol/sua.h>
26#include <osmocom/sigtran/sua.h>
27#include <osmocom/sigtran/sccp_sap.h>
28
29#include "hnbgw.h"
30#include "hnbgw_rua.h"
Neels Hofmeyr96979af2016-01-05 15:19:44 +010031#include <osmocom/ranap/ranap_ies_defs.h>
32#include <osmocom/ranap/ranap_msg_factory.h>
Harald Weltec4338de2015-12-24 00:40:52 +010033#include "context_map.h"
34#include "sccp_helpers.h"
35
Harald Weltec4338de2015-12-24 00:40:52 +010036/***********************************************************************
37 * Outbound RANAP RESET to CN
38 ***********************************************************************/
39
40int hnbgw_cnlink_change_state(struct hnbgw_cnlink *cnlink, enum hnbgw_cnlink_state state);
41
42static int transmit_rst(struct hnbgw_cnlink *cnlink)
43{
44 struct msgb *msg;
45 struct msgb *msgprim;
46 RANAP_CN_DomainIndicator_t domain;
47 RANAP_Cause_t cause = {
48 .present = RANAP_Cause_PR_transmissionNetwork,
49 .choice. transmissionNetwork = RANAP_CauseTransmissionNetwork_signalling_transport_resource_failure,
50 };
51
52 if (cnlink->is_ps)
53 domain = RANAP_CN_DomainIndicator_ps_domain;
54 else
55 domain = RANAP_CN_DomainIndicator_cs_domain;
56
57 msg = ranap_new_msg_reset(domain, &cause);
58
59 return sccp_tx_unitdata_msg(cnlink->sua_link, &cnlink->local_addr,
60 &cnlink->remote_addr, msg);
61}
62
63/* Timer callback once T_RafC expires */
64static void cnlink_trafc_cb(void *data)
65{
66 struct hnbgw_cnlink *cnlink = data;
67
68 transmit_rst(cnlink);
69 hnbgw_cnlink_change_state(cnlink, CNLINK_S_EST_RST_TX_WAIT_ACK);
70 /* The spec states that we should abandon after a configurable
71 * number of times. We decide to simply continue trying */
72}
73
74/* change the state of a CN Link */
75int hnbgw_cnlink_change_state(struct hnbgw_cnlink *cnlink, enum hnbgw_cnlink_state state)
76{
77 switch (state) {
78 case CNLINK_S_NULL:
79 case CNLINK_S_EST_PEND:
80 break;
81 case CNLINK_S_EST_CONF:
82 cnlink_trafc_cb(cnlink);
83 break;
84 case CNLINK_S_EST_RST_TX_WAIT_ACK:
85 osmo_timer_schedule(&cnlink->T_RafC, 5, 0);
86 break;
87 case CNLINK_S_EST_ACTIVE:
88 osmo_timer_del(&cnlink->T_RafC);
89 break;
90 }
91}
92
93/***********************************************************************
94 * Incoming primitives from SCCP User SAP
95 ***********************************************************************/
96
97static int cn_ranap_rx_reset_cmd(struct hnbgw_cnlink *cnlink,
98 RANAP_InitiatingMessage_t *imsg)
99{
100 RANAP_ResetIEs_t ies;
101 int rc;
102
103 rc = ranap_decode_reseties(&ies, &imsg->value);
104 /* FIXME: reset resources and return reset ack */
Daniel Willmann11e912a2016-01-07 13:19:30 +0100105
106 ranap_free_reseties(&ies);
Harald Weltec4338de2015-12-24 00:40:52 +0100107 return rc;
108}
109
110static int cn_ranap_rx_reset_ack(struct hnbgw_cnlink *cnlink,
111 RANAP_SuccessfulOutcome_t *omsg)
112{
113 RANAP_ResetAcknowledgeIEs_t ies;
114 int rc;
115
116 rc = ranap_decode_resetacknowledgeies(&ies, &omsg->value);
117
118 hnbgw_cnlink_change_state(cnlink, CNLINK_S_EST_ACTIVE);
119
Daniel Willmann11e912a2016-01-07 13:19:30 +0100120 ranap_free_resetacknowledgeies(&ies);
Harald Weltec4338de2015-12-24 00:40:52 +0100121 return rc;
122}
123
124static int cn_ranap_rx_paging_cmd(struct hnbgw_cnlink *cnlink,
Harald Weltebc4560c2015-12-24 08:46:58 +0100125 RANAP_InitiatingMessage_t *imsg,
126 const uint8_t *data, unsigned int len)
Harald Weltec4338de2015-12-24 00:40:52 +0100127{
Harald Weltebc4560c2015-12-24 08:46:58 +0100128 struct hnb_gw *gw;
129 struct hnb_context *hnb;
Harald Weltec4338de2015-12-24 00:40:52 +0100130 RANAP_PagingIEs_t ies;
Harald Weltebc4560c2015-12-24 08:46:58 +0100131 int rc = 0;
Harald Weltec4338de2015-12-24 00:40:52 +0100132
133 rc = ranap_decode_pagingies(&ies, &imsg->value);
134
Harald Weltebc4560c2015-12-24 08:46:58 +0100135 /* FIXME: determine which HNBs to send this Paging command,
136 * rather than broadcasting to all HNBs */
137 llist_for_each_entry(hnb, &gw->hnb_list, list) {
138 rc = rua_tx_udt(hnb, data, len);
139 }
Daniel Willmann11e912a2016-01-07 13:19:30 +0100140
141 ranap_free_pagingies(&ies);
Harald Weltebc4560c2015-12-24 08:46:58 +0100142 return 0;
Harald Weltec4338de2015-12-24 00:40:52 +0100143}
144
145static int cn_ranap_rx_initiating_msg(struct hnbgw_cnlink *cnlink,
Harald Weltebc4560c2015-12-24 08:46:58 +0100146 RANAP_InitiatingMessage_t *imsg,
147 const uint8_t *data, unsigned int len)
Harald Weltec4338de2015-12-24 00:40:52 +0100148{
149 int rc;
150
151 switch (imsg->procedureCode) {
152 case RANAP_ProcedureCode_id_Reset:
153 return cn_ranap_rx_reset_cmd(cnlink, imsg);
154 case RANAP_ProcedureCode_id_Paging:
Harald Weltebc4560c2015-12-24 08:46:58 +0100155 return cn_ranap_rx_paging_cmd(cnlink, imsg, data, len);
Harald Weltec4338de2015-12-24 00:40:52 +0100156 case RANAP_ProcedureCode_id_OverloadControl: /* Overload ind */
157 break;
158 case RANAP_ProcedureCode_id_ErrorIndication: /* Error ind */
159 break;
160 case RANAP_ProcedureCode_id_ResetResource: /* request */
161 case RANAP_ProcedureCode_id_InformationTransfer:
162 case RANAP_ProcedureCode_id_DirectInformationTransfer:
163 case RANAP_ProcedureCode_id_UplinkInformationExchange:
164 LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
165 "Procedure %u from CN, ignoring\n", imsg->procedureCode);
166 break;
167 default:
168 LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
169 "Procedure %u from CN, ignoring\n", imsg->procedureCode);
170 break;
171 }
172 return 0;
173}
174
175static int cn_ranap_rx_successful_msg(struct hnbgw_cnlink *cnlink,
176 RANAP_SuccessfulOutcome_t *omsg)
177{
178 int rc;
179
180 switch (omsg->procedureCode) {
181 case RANAP_ProcedureCode_id_Reset: /* Reset acknowledge */
182 return cn_ranap_rx_reset_ack(cnlink, omsg);
183 case RANAP_ProcedureCode_id_ResetResource: /* response */
184 case RANAP_ProcedureCode_id_InformationTransfer:
185 case RANAP_ProcedureCode_id_DirectInformationTransfer:
186 case RANAP_ProcedureCode_id_UplinkInformationExchange:
187 LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
188 "Procedure %u from CN, ignoring\n", omsg->procedureCode);
189 break;
190 default:
191 LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
192 "Procedure %u from CN, ignoring\n", omsg->procedureCode);
193 break;
194 }
195 return 0;
196}
197
198
Harald Weltebc4560c2015-12-24 08:46:58 +0100199static int _cn_ranap_rx(struct hnbgw_cnlink *cnlink, RANAP_RANAP_PDU_t *pdu,
200 const uint8_t *data, unsigned int len)
Harald Weltec4338de2015-12-24 00:40:52 +0100201{
202 int rc;
203
204 switch (pdu->present) {
205 case RANAP_RANAP_PDU_PR_initiatingMessage:
Harald Weltebc4560c2015-12-24 08:46:58 +0100206 rc = cn_ranap_rx_initiating_msg(cnlink, &pdu->choice.initiatingMessage,
207 data, len);
Harald Weltec4338de2015-12-24 00:40:52 +0100208 break;
209 case RANAP_RANAP_PDU_PR_successfulOutcome:
210 rc = cn_ranap_rx_successful_msg(cnlink, &pdu->choice.successfulOutcome);
211 break;
212 case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
213 LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
214 "unsuccessful outcome procedure %u from CN, ignoring\n",
215 pdu->choice.unsuccessfulOutcome.procedureCode);
216 break;
217 default:
218 LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
219 "presence %u from CN, ignoring\n", pdu->present);
220 break;
221 }
222}
223
224static int handle_cn_ranap(struct hnbgw_cnlink *cnlink, const uint8_t *data,
225 unsigned int len)
226{
227 RANAP_RANAP_PDU_t _pdu, *pdu = &_pdu;
228 asn_dec_rval_t dec_ret;
229 int rc;
230
231 memset(pdu, 0, sizeof(*pdu));
232 dec_ret = aper_decode(NULL,&asn_DEF_RANAP_RANAP_PDU, (void **) &pdu,
233 data, len, 0, 0);
234 if (dec_ret.code != RC_OK) {
235 LOGP(DRANAP, LOGL_ERROR, "Error in RANAP ASN.1 decode\n");
236 return rc;
237 }
238
Harald Weltebc4560c2015-12-24 08:46:58 +0100239 rc = _cn_ranap_rx(cnlink, pdu, data, len);
Harald Weltec4338de2015-12-24 00:40:52 +0100240
241 return rc;
242}
243
244
245static int handle_cn_unitdata(struct hnbgw_cnlink *cnlink,
246 const struct osmo_scu_unitdata_param *param,
247 struct osmo_prim_hdr *oph)
248{
Harald Welte8c572fe2015-12-26 08:42:07 +0100249 if (param->called_addr.ssn != OSMO_SCCP_SSN_RANAP) {
Harald Weltec4338de2015-12-24 00:40:52 +0100250 LOGP(DMAIN, LOGL_NOTICE, "N-UNITDATA.ind for unknown SSN %u\n",
251 param->called_addr.ssn);
252 return -1;
253 }
254
255 return handle_cn_ranap(cnlink, msgb_l2(oph->msg), msgb_l2len(oph->msg));
256}
257
Harald Welte2ebe42f2015-12-26 23:38:38 +0100258static int handle_cn_conn_conf(void *slink,
Harald Weltec4338de2015-12-24 00:40:52 +0100259 const struct osmo_scu_connect_param *param,
260 struct osmo_prim_hdr *oph)
261{
262 /* we don't actually need to do anything, as RUA towards the HNB
263 * doesn't seem to know any confirmations to its CONNECT
264 * operation */
265
266 return 0;
267}
268
Harald Welte2ebe42f2015-12-26 23:38:38 +0100269static int handle_cn_data_ind(void *slink,
Harald Weltec4338de2015-12-24 00:40:52 +0100270 const struct osmo_scu_data_param *param,
271 struct osmo_prim_hdr *oph)
272{
273 struct hnbgw_context_map *map;
Harald Welte2ebe42f2015-12-26 23:38:38 +0100274 struct hnbgw_cnlink *cnlink = osmo_sua_link_get_user_priv(slink);
Harald Weltec4338de2015-12-24 00:40:52 +0100275
276 /* connection-oriented data is always passed transparently
277 * towards the specific HNB, via a RUA connection identified by
278 * conn_id */
279
280 map = context_map_by_cn(cnlink, param->conn_id);
281 if (!map) {
282 /* FIXME: Return an error / released primitive */
283 return 0;
284 }
285
286 return rua_tx_dt(map->hnb_ctx, map->cn_link->is_ps, map->rua_ctx_id,
287 msgb_l2(oph->msg), msgb_l2len(oph->msg));
288}
289
Harald Welte2ebe42f2015-12-26 23:38:38 +0100290static int handle_cn_disc_ind(void *slink,
Harald Weltec4338de2015-12-24 00:40:52 +0100291 const struct osmo_scu_disconn_param *param,
292 struct osmo_prim_hdr *oph)
293{
294 struct hnbgw_context_map *map;
Harald Welte2ebe42f2015-12-26 23:38:38 +0100295 struct hnbgw_cnlink *cnlink = osmo_sua_link_get_user_priv(slink);
Harald Weltec4338de2015-12-24 00:40:52 +0100296
297 RUA_Cause_t rua_cause = {
298 .present = RUA_Cause_PR_NOTHING,
299 /* FIXME: Convert incoming SCCP cause to RUA cause */
300 };
301
302 /* we need to notify the HNB associated with this connection via
303 * a RUA DISCONNECT */
304
305 map = context_map_by_cn(cnlink, param->conn_id);
306 if (!map) {
307 /* FIXME: Return an error / released primitive */
308 return 0;
309 }
310
311 return rua_tx_disc(map->hnb_ctx, map->cn_link->is_ps, map->rua_ctx_id,
312 &rua_cause, msgb_l2(oph->msg), msgb_l2len(oph->msg));
313}
314
315/* Entry point for primitives coming up from SCCP User SAP */
316static int sccp_sap_up(struct osmo_prim_hdr *oph, void *slink)
317{
318 struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;
319 int rc;
320
321 LOGP(DMAIN, LOGL_DEBUG, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph));
322
323 switch (OSMO_PRIM_HDR(oph)) {
324 case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
325 rc = handle_cn_unitdata(slink, &prim->u.unitdata, oph);
326 break;
327 case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
328 rc = handle_cn_conn_conf(slink, &prim->u.connect, oph);
329 break;
330 case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
331 rc = handle_cn_data_ind(slink, &prim->u.data, oph);
332 break;
333 case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
334 rc = handle_cn_disc_ind(slink, &prim->u.disconnect, oph);
335 break;
336 defualt:
337 LOGP(DMAIN, LOGL_ERROR,
338 "Received unknown prim %u from SCCP USER SAP\n",
339 OSMO_PRIM_HDR(oph));
340 break;
341 }
342
343 msgb_free(oph->msg);
344
345 return 0;
346}
347
348
Daniel Willmann4deab942016-01-14 15:35:11 +0100349struct hnbgw_cnlink *hnbgw_cnlink_init(struct hnb_gw *gw, const char *host, uint16_t port, int is_ps)
Harald Weltec4338de2015-12-24 00:40:52 +0100350{
351 struct hnbgw_cnlink *cnlink = talloc_zero(gw, struct hnbgw_cnlink);
352 int rc;
353
354 INIT_LLIST_HEAD(&cnlink->map_list);
355 cnlink->T_RafC.cb = cnlink_trafc_cb;
356 cnlink->T_RafC.data = cnlink;
Harald Welte552fdf12015-12-26 23:39:30 +0100357 cnlink->next_conn_id = 1000;
Daniel Willmann4deab942016-01-14 15:35:11 +0100358 cnlink->is_ps = is_ps;
Harald Welte8c572fe2015-12-26 08:42:07 +0100359 sccp_make_addr_pc_ssn(&cnlink->local_addr, 2, OSMO_SCCP_SSN_RANAP);
360 sccp_make_addr_pc_ssn(&cnlink->remote_addr, 1, OSMO_SCCP_SSN_RANAP);
Harald Weltec4338de2015-12-24 00:40:52 +0100361
Harald Welte2ebe42f2015-12-26 23:38:38 +0100362 cnlink->sua_user = osmo_sua_user_create(cnlink, sccp_sap_up, cnlink);
Harald Weltec4338de2015-12-24 00:40:52 +0100363 if (!cnlink->sua_user) {
364 LOGP(DMAIN, LOGL_ERROR, "Failed to init SUA\n");
365 goto out_free;
366 }
367 rc = osmo_sua_client_connect(cnlink->sua_user, host, port);
368 if (rc < 0) {
369 LOGP(DMAIN, LOGL_ERROR, "Failed to connect SUA\n");
370 goto out_user;
371 }
372 cnlink->sua_link = osmo_sua_client_get_link(cnlink->sua_user);
373 if (!cnlink->sua_link) {
374 LOGP(DMAIN, LOGL_ERROR, "Failed to get SUA link\n");
375 goto out_disconnect;
376 }
377
378 llist_add_tail(&cnlink->list, &gw->cn_list);
379
380 return cnlink;
381
382out_disconnect:
383 /* FIXME */
384out_user:
385 osmo_sua_user_destroy(cnlink->sua_user);
386out_free:
387 talloc_free(cnlink);
388}