blob: ede00c840ae0083ec7665fcea3f380d23daae757 [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
Neels Hofmeyr37017f52016-04-15 22:47:21 +020021#include <arpa/inet.h>
Neels Hofmeyre3644ac2018-01-15 23:25:42 +010022#include <errno.h>
Neels Hofmeyr37017f52016-04-15 22:47:21 +020023
Harald Weltec4338de2015-12-24 00:40:52 +010024#include <osmocom/core/msgb.h>
25#include <osmocom/core/utils.h>
26#include <osmocom/core/timer.h>
27
Neels Hofmeyr0f88c112017-07-03 16:49:43 +020028#include <osmocom/sigtran/protocol/m3ua.h>
Harald Weltec4338de2015-12-24 00:40:52 +010029#include <osmocom/sigtran/sccp_sap.h>
Neels Hofmeyr3da86082016-03-30 12:36:15 +020030#include <osmocom/sigtran/sccp_helpers.h>
Harald Weltec4338de2015-12-24 00:40:52 +010031
Neels Hofmeyrdf63de22016-08-18 13:13:55 +020032#include <osmocom/iuh/hnbgw.h>
33#include <osmocom/iuh/hnbgw_rua.h>
Neels Hofmeyr96979af2016-01-05 15:19:44 +010034#include <osmocom/ranap/ranap_ies_defs.h>
35#include <osmocom/ranap/ranap_msg_factory.h>
Neels Hofmeyrdf63de22016-08-18 13:13:55 +020036#include <osmocom/iuh/context_map.h>
Harald Weltec4338de2015-12-24 00:40:52 +010037
Harald Weltec4338de2015-12-24 00:40:52 +010038/***********************************************************************
39 * Outbound RANAP RESET to CN
40 ***********************************************************************/
41
Harald Welteda86fe52017-11-21 08:14:37 +010042void hnbgw_cnlink_change_state(struct hnbgw_cnlink *cnlink, enum hnbgw_cnlink_state state);
Harald Weltec4338de2015-12-24 00:40:52 +010043
Neels Hofmeyr0f88c112017-07-03 16:49:43 +020044static int transmit_rst(struct hnb_gw *gw, RANAP_CN_DomainIndicator_t domain,
45 struct osmo_sccp_addr *remote_addr)
Harald Weltec4338de2015-12-24 00:40:52 +010046{
47 struct msgb *msg;
Harald Weltec4338de2015-12-24 00:40:52 +010048 RANAP_Cause_t cause = {
49 .present = RANAP_Cause_PR_transmissionNetwork,
50 .choice. transmissionNetwork = RANAP_CauseTransmissionNetwork_signalling_transport_resource_failure,
51 };
52
Harald Weltec4338de2015-12-24 00:40:52 +010053 msg = ranap_new_msg_reset(domain, &cause);
54
Neels Hofmeyr0f88c112017-07-03 16:49:43 +020055 return osmo_sccp_tx_unitdata_msg(gw->sccp.cnlink->sccp_user,
56 &gw->sccp.local_addr,
57 remote_addr,
58 msg);
Harald Weltec4338de2015-12-24 00:40:52 +010059}
60
61/* Timer callback once T_RafC expires */
62static void cnlink_trafc_cb(void *data)
63{
Neels Hofmeyr0f88c112017-07-03 16:49:43 +020064 struct hnb_gw *gw = data;
Harald Weltec4338de2015-12-24 00:40:52 +010065
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +020066 transmit_rst(gw, RANAP_CN_DomainIndicator_cs_domain, &gw->sccp.iucs_remote_addr);
67 transmit_rst(gw, RANAP_CN_DomainIndicator_ps_domain, &gw->sccp.iups_remote_addr);
Neels Hofmeyr0f88c112017-07-03 16:49:43 +020068 hnbgw_cnlink_change_state(gw->sccp.cnlink, CNLINK_S_EST_RST_TX_WAIT_ACK);
Harald Weltec4338de2015-12-24 00:40:52 +010069 /* The spec states that we should abandon after a configurable
70 * number of times. We decide to simply continue trying */
71}
72
73/* change the state of a CN Link */
Harald Welteda86fe52017-11-21 08:14:37 +010074void hnbgw_cnlink_change_state(struct hnbgw_cnlink *cnlink, enum hnbgw_cnlink_state state)
Harald Weltec4338de2015-12-24 00:40:52 +010075{
76 switch (state) {
77 case CNLINK_S_NULL:
78 case CNLINK_S_EST_PEND:
79 break;
80 case CNLINK_S_EST_CONF:
Neels Hofmeyr0f88c112017-07-03 16:49:43 +020081 cnlink_trafc_cb(cnlink->gw);
Harald Weltec4338de2015-12-24 00:40:52 +010082 break;
83 case CNLINK_S_EST_RST_TX_WAIT_ACK:
84 osmo_timer_schedule(&cnlink->T_RafC, 5, 0);
85 break;
86 case CNLINK_S_EST_ACTIVE:
87 osmo_timer_del(&cnlink->T_RafC);
88 break;
89 }
90}
91
92/***********************************************************************
93 * Incoming primitives from SCCP User SAP
94 ***********************************************************************/
95
96static int cn_ranap_rx_reset_cmd(struct hnbgw_cnlink *cnlink,
97 RANAP_InitiatingMessage_t *imsg)
98{
99 RANAP_ResetIEs_t ies;
100 int rc;
101
102 rc = ranap_decode_reseties(&ies, &imsg->value);
103 /* FIXME: reset resources and return reset ack */
Daniel Willmann11e912a2016-01-07 13:19:30 +0100104
105 ranap_free_reseties(&ies);
Harald Weltec4338de2015-12-24 00:40:52 +0100106 return rc;
107}
108
109static int cn_ranap_rx_reset_ack(struct hnbgw_cnlink *cnlink,
110 RANAP_SuccessfulOutcome_t *omsg)
111{
112 RANAP_ResetAcknowledgeIEs_t ies;
113 int rc;
114
115 rc = ranap_decode_resetacknowledgeies(&ies, &omsg->value);
116
117 hnbgw_cnlink_change_state(cnlink, CNLINK_S_EST_ACTIVE);
118
Daniel Willmann11e912a2016-01-07 13:19:30 +0100119 ranap_free_resetacknowledgeies(&ies);
Harald Weltec4338de2015-12-24 00:40:52 +0100120 return rc;
121}
122
123static int cn_ranap_rx_paging_cmd(struct hnbgw_cnlink *cnlink,
Harald Weltebc4560c2015-12-24 08:46:58 +0100124 RANAP_InitiatingMessage_t *imsg,
125 const uint8_t *data, unsigned int len)
Harald Weltec4338de2015-12-24 00:40:52 +0100126{
Neels Hofmeyr2b01f3a2016-04-19 17:57:03 +0200127 struct hnb_gw *gw = cnlink->gw;
Harald Weltebc4560c2015-12-24 08:46:58 +0100128 struct hnb_context *hnb;
Harald Weltec4338de2015-12-24 00:40:52 +0100129 RANAP_PagingIEs_t ies;
Harald Welteda86fe52017-11-21 08:14:37 +0100130 int rc;
Harald Weltec4338de2015-12-24 00:40:52 +0100131
132 rc = ranap_decode_pagingies(&ies, &imsg->value);
Harald Welteda86fe52017-11-21 08:14:37 +0100133 if (rc < 0)
134 return rc;
Harald Weltec4338de2015-12-24 00:40:52 +0100135
Harald Weltebc4560c2015-12-24 08:46:58 +0100136 /* FIXME: determine which HNBs to send this Paging command,
137 * rather than broadcasting to all HNBs */
138 llist_for_each_entry(hnb, &gw->hnb_list, list) {
139 rc = rua_tx_udt(hnb, data, len);
140 }
Daniel Willmann11e912a2016-01-07 13:19:30 +0100141
142 ranap_free_pagingies(&ies);
Harald Weltebc4560c2015-12-24 08:46:58 +0100143 return 0;
Harald Weltec4338de2015-12-24 00:40:52 +0100144}
145
146static int cn_ranap_rx_initiating_msg(struct hnbgw_cnlink *cnlink,
Harald Weltebc4560c2015-12-24 08:46:58 +0100147 RANAP_InitiatingMessage_t *imsg,
148 const uint8_t *data, unsigned int len)
Harald Weltec4338de2015-12-24 00:40:52 +0100149{
Harald Weltec4338de2015-12-24 00:40:52 +0100150 switch (imsg->procedureCode) {
151 case RANAP_ProcedureCode_id_Reset:
152 return cn_ranap_rx_reset_cmd(cnlink, imsg);
153 case RANAP_ProcedureCode_id_Paging:
Harald Weltebc4560c2015-12-24 08:46:58 +0100154 return cn_ranap_rx_paging_cmd(cnlink, imsg, data, len);
Harald Weltec4338de2015-12-24 00:40:52 +0100155 case RANAP_ProcedureCode_id_OverloadControl: /* Overload ind */
156 break;
157 case RANAP_ProcedureCode_id_ErrorIndication: /* Error ind */
158 break;
159 case RANAP_ProcedureCode_id_ResetResource: /* request */
160 case RANAP_ProcedureCode_id_InformationTransfer:
161 case RANAP_ProcedureCode_id_DirectInformationTransfer:
162 case RANAP_ProcedureCode_id_UplinkInformationExchange:
163 LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
Harald Welteda86fe52017-11-21 08:14:37 +0100164 "Procedure %ld from CN, ignoring\n", imsg->procedureCode);
Harald Weltec4338de2015-12-24 00:40:52 +0100165 break;
166 default:
167 LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
Harald Welteda86fe52017-11-21 08:14:37 +0100168 "Procedure %ld from CN, ignoring\n", imsg->procedureCode);
Harald Weltec4338de2015-12-24 00:40:52 +0100169 break;
170 }
171 return 0;
172}
173
174static int cn_ranap_rx_successful_msg(struct hnbgw_cnlink *cnlink,
175 RANAP_SuccessfulOutcome_t *omsg)
176{
Harald Weltec4338de2015-12-24 00:40:52 +0100177 switch (omsg->procedureCode) {
178 case RANAP_ProcedureCode_id_Reset: /* Reset acknowledge */
179 return cn_ranap_rx_reset_ack(cnlink, omsg);
180 case RANAP_ProcedureCode_id_ResetResource: /* response */
181 case RANAP_ProcedureCode_id_InformationTransfer:
182 case RANAP_ProcedureCode_id_DirectInformationTransfer:
183 case RANAP_ProcedureCode_id_UplinkInformationExchange:
184 LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
Harald Welteda86fe52017-11-21 08:14:37 +0100185 "Procedure %ld from CN, ignoring\n", omsg->procedureCode);
Harald Weltec4338de2015-12-24 00:40:52 +0100186 break;
187 default:
188 LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
Harald Welteda86fe52017-11-21 08:14:37 +0100189 "Procedure %ld from CN, ignoring\n", omsg->procedureCode);
Harald Weltec4338de2015-12-24 00:40:52 +0100190 break;
191 }
192 return 0;
193}
194
195
Harald Weltebc4560c2015-12-24 08:46:58 +0100196static int _cn_ranap_rx(struct hnbgw_cnlink *cnlink, RANAP_RANAP_PDU_t *pdu,
197 const uint8_t *data, unsigned int len)
Harald Weltec4338de2015-12-24 00:40:52 +0100198{
199 int rc;
200
201 switch (pdu->present) {
202 case RANAP_RANAP_PDU_PR_initiatingMessage:
Harald Weltebc4560c2015-12-24 08:46:58 +0100203 rc = cn_ranap_rx_initiating_msg(cnlink, &pdu->choice.initiatingMessage,
204 data, len);
Harald Weltec4338de2015-12-24 00:40:52 +0100205 break;
206 case RANAP_RANAP_PDU_PR_successfulOutcome:
207 rc = cn_ranap_rx_successful_msg(cnlink, &pdu->choice.successfulOutcome);
208 break;
209 case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
210 LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
Harald Welteda86fe52017-11-21 08:14:37 +0100211 "unsuccessful outcome procedure %ld from CN, ignoring\n",
Harald Weltec4338de2015-12-24 00:40:52 +0100212 pdu->choice.unsuccessfulOutcome.procedureCode);
Neels Hofmeyre3644ac2018-01-15 23:25:42 +0100213 rc = -ENOTSUP;
Harald Weltec4338de2015-12-24 00:40:52 +0100214 break;
215 default:
216 LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
217 "presence %u from CN, ignoring\n", pdu->present);
Neels Hofmeyre3644ac2018-01-15 23:25:42 +0100218 rc = -EINVAL;
Harald Weltec4338de2015-12-24 00:40:52 +0100219 break;
220 }
Harald Welteda86fe52017-11-21 08:14:37 +0100221
222 return rc;
Harald Weltec4338de2015-12-24 00:40:52 +0100223}
224
225static int handle_cn_ranap(struct hnbgw_cnlink *cnlink, const uint8_t *data,
226 unsigned int len)
227{
228 RANAP_RANAP_PDU_t _pdu, *pdu = &_pdu;
229 asn_dec_rval_t dec_ret;
230 int rc;
231
232 memset(pdu, 0, sizeof(*pdu));
233 dec_ret = aper_decode(NULL,&asn_DEF_RANAP_RANAP_PDU, (void **) &pdu,
234 data, len, 0, 0);
235 if (dec_ret.code != RC_OK) {
236 LOGP(DRANAP, LOGL_ERROR, "Error in RANAP ASN.1 decode\n");
Neels Hofmeyra6a68e62016-11-25 13:21:02 +0100237 return -1;
Harald Weltec4338de2015-12-24 00:40:52 +0100238 }
239
Harald Weltebc4560c2015-12-24 08:46:58 +0100240 rc = _cn_ranap_rx(cnlink, pdu, data, len);
Harald Weltec4338de2015-12-24 00:40:52 +0100241
242 return rc;
243}
244
Neels Hofmeyra3bcd6d2017-07-03 14:29:04 +0200245static bool pc_and_ssn_match(const struct osmo_sccp_addr *a, const struct osmo_sccp_addr *b)
246{
247 return (a == b)
248 || ((a->pc == b->pc)
249 && (a->ssn == b->ssn));
250}
251
252static int classify_cn_remote_addr(const struct hnb_gw *gw,
253 const struct osmo_sccp_addr *cn_remote_addr,
254 bool *is_ps)
255{
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200256 if (pc_and_ssn_match(cn_remote_addr, &gw->sccp.iucs_remote_addr)) {
Neels Hofmeyra3bcd6d2017-07-03 14:29:04 +0200257 if (is_ps)
258 *is_ps = false;
259 return 0;
260 }
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200261 if (pc_and_ssn_match(cn_remote_addr, &gw->sccp.iups_remote_addr)) {
Neels Hofmeyra3bcd6d2017-07-03 14:29:04 +0200262 if (is_ps)
263 *is_ps = true;
264 return 0;
265 }
266 LOGP(DMAIN, LOGL_ERROR, "Unexpected remote address, matches neither CS nor PS address: %s\n",
267 osmo_sccp_addr_dump(cn_remote_addr));
268 return -1;
269}
Harald Weltec4338de2015-12-24 00:40:52 +0100270
271static int handle_cn_unitdata(struct hnbgw_cnlink *cnlink,
272 const struct osmo_scu_unitdata_param *param,
273 struct osmo_prim_hdr *oph)
274{
Harald Welte8c572fe2015-12-26 08:42:07 +0100275 if (param->called_addr.ssn != OSMO_SCCP_SSN_RANAP) {
Harald Weltec4338de2015-12-24 00:40:52 +0100276 LOGP(DMAIN, LOGL_NOTICE, "N-UNITDATA.ind for unknown SSN %u\n",
277 param->called_addr.ssn);
278 return -1;
279 }
280
Neels Hofmeyra3bcd6d2017-07-03 14:29:04 +0200281 if (classify_cn_remote_addr(cnlink->gw, &param->calling_addr, NULL) < 0)
282 return -1;
283
Harald Weltec4338de2015-12-24 00:40:52 +0100284 return handle_cn_ranap(cnlink, msgb_l2(oph->msg), msgb_l2len(oph->msg));
285}
286
Neels Hofmeyr65037672016-04-19 18:00:54 +0200287static int handle_cn_conn_conf(struct hnbgw_cnlink *cnlink,
Neels Hofmeyr630483b2016-04-19 18:01:25 +0200288 const struct osmo_scu_connect_param *param,
289 struct osmo_prim_hdr *oph)
Harald Weltec4338de2015-12-24 00:40:52 +0100290{
291 /* we don't actually need to do anything, as RUA towards the HNB
292 * doesn't seem to know any confirmations to its CONNECT
293 * operation */
294
Neels Hofmeyr0ff24432016-04-04 18:33:33 +0200295 LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() conn_id=%d\n",
296 param->conn_id);
297 LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() called_addr=%s\n",
298 inet_ntoa(param->called_addr.ip.v4));
299 LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() calling_addr=%s\n",
300 inet_ntoa(param->calling_addr.ip.v4));
301 LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() responding_addr=%s\n",
302 inet_ntoa(param->responding_addr.ip.v4));
303
Harald Weltec4338de2015-12-24 00:40:52 +0100304 return 0;
305}
306
Neels Hofmeyr65037672016-04-19 18:00:54 +0200307static int handle_cn_data_ind(struct hnbgw_cnlink *cnlink,
Harald Weltec4338de2015-12-24 00:40:52 +0100308 const struct osmo_scu_data_param *param,
309 struct osmo_prim_hdr *oph)
310{
311 struct hnbgw_context_map *map;
312
313 /* connection-oriented data is always passed transparently
314 * towards the specific HNB, via a RUA connection identified by
315 * conn_id */
316
317 map = context_map_by_cn(cnlink, param->conn_id);
318 if (!map) {
319 /* FIXME: Return an error / released primitive */
320 return 0;
321 }
322
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200323 return rua_tx_dt(map->hnb_ctx, map->is_ps, map->rua_ctx_id,
Harald Weltec4338de2015-12-24 00:40:52 +0100324 msgb_l2(oph->msg), msgb_l2len(oph->msg));
325}
326
Neels Hofmeyr65037672016-04-19 18:00:54 +0200327static int handle_cn_disc_ind(struct hnbgw_cnlink *cnlink,
Harald Weltec4338de2015-12-24 00:40:52 +0100328 const struct osmo_scu_disconn_param *param,
329 struct osmo_prim_hdr *oph)
330{
331 struct hnbgw_context_map *map;
332
Neels Hofmeyr02be4e32016-04-04 19:29:35 +0200333 LOGP(DMAIN, LOGL_DEBUG, "handle_cn_disc_ind() conn_id=%d originator=%d\n",
334 param->conn_id, param->originator);
335 LOGP(DMAIN, LOGL_DEBUG, "handle_cn_disc_ind() responding_addr=%s\n",
336 inet_ntoa(param->responding_addr.ip.v4));
337
Harald Weltec4338de2015-12-24 00:40:52 +0100338 RUA_Cause_t rua_cause = {
339 .present = RUA_Cause_PR_NOTHING,
340 /* FIXME: Convert incoming SCCP cause to RUA cause */
341 };
342
343 /* we need to notify the HNB associated with this connection via
344 * a RUA DISCONNECT */
345
346 map = context_map_by_cn(cnlink, param->conn_id);
347 if (!map) {
348 /* FIXME: Return an error / released primitive */
349 return 0;
350 }
351
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200352 return rua_tx_disc(map->hnb_ctx, map->is_ps, map->rua_ctx_id,
Harald Weltec4338de2015-12-24 00:40:52 +0100353 &rua_cause, msgb_l2(oph->msg), msgb_l2len(oph->msg));
354}
355
356/* Entry point for primitives coming up from SCCP User SAP */
Neels Hofmeyra1bf4f32016-07-07 15:36:07 +0200357static int sccp_sap_up(struct osmo_prim_hdr *oph, void *ctx)
Harald Weltec4338de2015-12-24 00:40:52 +0100358{
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200359 struct osmo_sccp_user *scu = ctx;
Neels Hofmeyrcb246312017-06-20 22:49:34 +0200360 struct hnbgw_cnlink *cnlink;
Harald Weltec4338de2015-12-24 00:40:52 +0100361 struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;
Harald Welteda86fe52017-11-21 08:14:37 +0100362 int rc = 0;
Harald Weltec4338de2015-12-24 00:40:52 +0100363
364 LOGP(DMAIN, LOGL_DEBUG, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph));
365
Neels Hofmeyrcb246312017-06-20 22:49:34 +0200366 if (!scu) {
367 LOGP(DMAIN, LOGL_ERROR,
368 "sccp_sap_up(): NULL osmo_sccp_user, cannot send prim (sap %u prim %u op %d)\n",
369 oph->sap, oph->primitive, oph->operation);
370 return -1;
371 }
372
373 cnlink = osmo_sccp_user_get_priv(scu);
374 if (!cnlink) {
375 LOGP(DMAIN, LOGL_ERROR,
376 "sccp_sap_up(): NULL hnbgw_cnlink, cannot send prim (sap %u prim %u op %d)\n",
377 oph->sap, oph->primitive, oph->operation);
378 return -1;
379 }
380
Harald Weltec4338de2015-12-24 00:40:52 +0100381 switch (OSMO_PRIM_HDR(oph)) {
382 case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
Neels Hofmeyr65037672016-04-19 18:00:54 +0200383 rc = handle_cn_unitdata(cnlink, &prim->u.unitdata, oph);
Harald Weltec4338de2015-12-24 00:40:52 +0100384 break;
385 case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
Neels Hofmeyr65037672016-04-19 18:00:54 +0200386 rc = handle_cn_conn_conf(cnlink, &prim->u.connect, oph);
Harald Weltec4338de2015-12-24 00:40:52 +0100387 break;
388 case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
Neels Hofmeyr65037672016-04-19 18:00:54 +0200389 rc = handle_cn_data_ind(cnlink, &prim->u.data, oph);
Harald Weltec4338de2015-12-24 00:40:52 +0100390 break;
391 case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
Neels Hofmeyr65037672016-04-19 18:00:54 +0200392 rc = handle_cn_disc_ind(cnlink, &prim->u.disconnect, oph);
Harald Weltec4338de2015-12-24 00:40:52 +0100393 break;
Harald Welteffc20932017-11-21 08:09:40 +0100394 default:
Harald Weltec4338de2015-12-24 00:40:52 +0100395 LOGP(DMAIN, LOGL_ERROR,
396 "Received unknown prim %u from SCCP USER SAP\n",
397 OSMO_PRIM_HDR(oph));
398 break;
399 }
400
401 msgb_free(oph->msg);
402
Harald Welteda86fe52017-11-21 08:14:37 +0100403 return rc;
Harald Weltec4338de2015-12-24 00:40:52 +0100404}
405
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200406static bool addr_has_pc_and_ssn(const struct osmo_sccp_addr *addr)
Harald Weltec4338de2015-12-24 00:40:52 +0100407{
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200408 if (!(addr->presence & OSMO_SCCP_ADDR_T_SSN))
409 return false;
410 if (!(addr->presence & OSMO_SCCP_ADDR_T_PC))
411 return false;
412 return true;
413}
Harald Weltec4338de2015-12-24 00:40:52 +0100414
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200415static int resolve_addr_name(struct osmo_sccp_addr *dest, struct osmo_ss7_instance **ss7,
Neels Hofmeyr2af648f2017-11-23 00:39:53 +0100416 const char *addr_name, const char *label,
417 uint32_t default_pc)
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200418{
419 struct osmo_ss7_instance *ss7_tmp;
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200420
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200421 if (!addr_name) {
Neels Hofmeyr2af648f2017-11-23 00:39:53 +0100422 osmo_sccp_make_addr_pc_ssn(dest, default_pc, OSMO_SCCP_SSN_RANAP);
423 LOGP(DMAIN, LOGL_INFO, "%s remote addr not configured, using default: %s\n", label,
424 osmo_sccp_addr_name(*ss7, dest));
425 return 0;
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200426 }
427
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200428 ss7_tmp = osmo_sccp_addr_by_name(dest, addr_name);
429 if (!ss7_tmp) {
430 LOGP(DMAIN, LOGL_ERROR, "%s remote addr: no such SCCP address book entry: '%s'\n",
431 label, addr_name);
432 return -1;
433 }
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200434
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200435 if (*ss7 && (*ss7 != ss7_tmp)) {
436 LOGP(DMAIN, LOGL_ERROR, "IuCS and IuPS cannot be served from separate CS7 instances,"
437 " cs7 instance %d != %d\n", (*ss7)->cfg.id, ss7_tmp->cfg.id);
438 return -1;
439 }
440
441 *ss7 = ss7_tmp;
442
443 osmo_sccp_addr_set_ssn(dest, OSMO_SCCP_SSN_RANAP);
444
445 if (!addr_has_pc_and_ssn(dest)) {
446 LOGP(DMAIN, LOGL_ERROR, "Invalid/incomplete %s remote-addr: %s\n",
Alexander Couzense03d8a02017-08-15 12:19:45 +0000447 label, osmo_sccp_addr_name(*ss7, dest));
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200448 return -1;
449 }
450
451 LOGP(DRANAP, LOGL_NOTICE, "Remote %s SCCP addr: %s\n",
452 label, osmo_sccp_addr_name(*ss7, dest));
453 return 0;
454}
455
456int hnbgw_cnlink_init(struct hnb_gw *gw, const char *stp_host, uint16_t stp_port, const char *local_ip)
457{
458 struct hnbgw_cnlink *cnlink;
459 struct osmo_ss7_instance *ss7;
460 uint32_t local_pc;
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200461
462 OSMO_ASSERT(!gw->sccp.client);
463 OSMO_ASSERT(!gw->sccp.cnlink);
464
465 ss7 = NULL;
466 if (resolve_addr_name(&gw->sccp.iucs_remote_addr, &ss7,
Neels Hofmeyr2af648f2017-11-23 00:39:53 +0100467 gw->config.iucs_remote_addr_name, "IuCS", (23 << 3) + 1))
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200468 return -1;
469 if (resolve_addr_name(&gw->sccp.iups_remote_addr, &ss7,
Neels Hofmeyr2af648f2017-11-23 00:39:53 +0100470 gw->config.iups_remote_addr_name, "IuPS", (23 << 3) + 4))
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200471 return -1;
472
Neels Hofmeyr2af648f2017-11-23 00:39:53 +0100473 if (!ss7) {
474 LOGP(DRANAP, LOGL_NOTICE, "No cs7 instance configured for IuCS nor IuPS,"
475 " creating default instance\n");
476 ss7 = osmo_ss7_instance_find_or_create(gw, 0);
477 ss7->cfg.primary_pc = (23 << 3) + 5;
478 }
479
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200480 if (!osmo_ss7_pc_is_valid(ss7->cfg.primary_pc)) {
481 LOGP(DMAIN, LOGL_ERROR, "IuCS/IuPS uplink cannot be setup: CS7 instance %d has no point-code set\n",
482 ss7->cfg.id);
483 return -1;
484 }
485 local_pc = ss7->cfg.primary_pc;
486
487 osmo_sccp_make_addr_pc_ssn(&gw->sccp.local_addr, local_pc, OSMO_SCCP_SSN_RANAP);
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200488 LOGP(DRANAP, LOGL_NOTICE, "Local SCCP addr: %s\n", osmo_sccp_addr_name(ss7, &gw->sccp.local_addr));
489
490 gw->sccp.client = osmo_sccp_simple_client_on_ss7_id(gw, ss7->cfg.id, "OsmoHNBGW",
491 local_pc, OSMO_SS7_ASP_PROT_M3UA,
492 0, local_ip, stp_port, stp_host);
493 if (!gw->sccp.client) {
494 LOGP(DMAIN, LOGL_ERROR, "Failed to init SCCP Client\n");
495 return -1;
496 }
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200497
498 cnlink = talloc_zero(gw, struct hnbgw_cnlink);
Neels Hofmeyr2b01f3a2016-04-19 17:57:03 +0200499 cnlink->gw = gw;
Harald Weltec4338de2015-12-24 00:40:52 +0100500 INIT_LLIST_HEAD(&cnlink->map_list);
501 cnlink->T_RafC.cb = cnlink_trafc_cb;
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200502 cnlink->T_RafC.data = gw;
Harald Welte552fdf12015-12-26 23:39:30 +0100503 cnlink->next_conn_id = 1000;
Harald Weltec4338de2015-12-24 00:40:52 +0100504
Neels Hofmeyrecbdc5c2017-07-31 13:13:24 +0200505 cnlink->sccp_user = osmo_sccp_user_bind_pc(gw->sccp.client, "OsmoHNBGW", sccp_sap_up,
506 OSMO_SCCP_SSN_RANAP, gw->sccp.local_addr.pc);
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200507 if (!cnlink->sccp_user) {
508 LOGP(DMAIN, LOGL_ERROR, "Failed to init SCCP User\n");
509 return -1;
Harald Weltec4338de2015-12-24 00:40:52 +0100510 }
511
Neels Hofmeyrb5939692017-11-23 00:40:04 +0100512 LOGP(DRANAP, LOGL_NOTICE, "Remote SCCP addr: IuCS: %s\n",
513 osmo_sccp_addr_name(ss7, &gw->sccp.iucs_remote_addr));
514 LOGP(DRANAP, LOGL_NOTICE, "Remote SCCP addr: IuPS: %s\n",
515 osmo_sccp_addr_name(ss7, &gw->sccp.iups_remote_addr));
516
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200517 /* In sccp_sap_up() we expect the cnlink in the user's priv. */
518 osmo_sccp_user_set_priv(cnlink->sccp_user, cnlink);
Harald Weltec4338de2015-12-24 00:40:52 +0100519
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200520 gw->sccp.cnlink = cnlink;
Harald Weltec4338de2015-12-24 00:40:52 +0100521
Neels Hofmeyr0f88c112017-07-03 16:49:43 +0200522 return 0;
Harald Weltec4338de2015-12-24 00:40:52 +0100523}