blob: 974ddb3f7884ee3487d27745af956d31ff040677 [file] [log] [blame]
Neels Hofmeyrc036b792018-11-29 22:37:51 +01001/* Code to manage MSC RAN connections over IuCS interface */
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02002
3/*
4 * (C) 2016,2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
5 *
6 * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include <inttypes.h>
26
27#include <osmocom/core/logging.h>
Neels Hofmeyr00e82d62017-07-05 15:19:52 +020028#include <osmocom/ranap/iu_client.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020029#include <osmocom/msc/debug.h>
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020030
Neels Hofmeyr90843962017-09-04 15:04:35 +020031#include <osmocom/msc/gsm_data.h>
32#include <osmocom/msc/gsm_subscriber.h>
Philipp Maier621ba032017-11-07 17:19:25 +010033#include <osmocom/msc/transaction.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020034#include <osmocom/msc/vlr.h>
Philipp Maier621ba032017-11-07 17:19:25 +010035#include <osmocom/core/byteswap.h>
36
37#include "../../bscconfig.h"
38
39#ifdef BUILD_IU
40#include <osmocom/ranap/iu_client.h>
41extern struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id,
42 uint32_t rtp_ip,
43 uint16_t rtp_port,
44 bool use_x213_nsap);
45#else
46#include <osmocom/msc/iu_dummy.h>
47#endif /* BUILD_IU */
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020048
49/* For A-interface see libbsc/bsc_api.c subscr_con_allocate() */
Neels Hofmeyrc036b792018-11-29 22:37:51 +010050static struct ran_conn *ran_conn_allocate_iu(struct gsm_network *network,
Neels Hofmeyr00e82d62017-07-05 15:19:52 +020051 struct ranap_ue_conn_ctx *ue,
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020052 uint16_t lac)
53{
Neels Hofmeyrc036b792018-11-29 22:37:51 +010054 struct ran_conn *conn;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020055
Neels Hofmeyrc036b792018-11-29 22:37:51 +010056 DEBUGP(DIUCS, "Allocating IuCS RAN conn: lac %d, conn_id %" PRIx32 "\n",
Philipp Maierfbf66102017-04-09 12:32:51 +020057 lac, ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020058
Neels Hofmeyr7814a832018-12-26 00:40:18 +010059 conn = ran_conn_alloc(network, OSMO_RAT_UTRAN_IU, lac);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020060 if (!conn)
61 return NULL;
62
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020063 conn->iu.ue_ctx = ue;
64 conn->iu.ue_ctx->rab_assign_addr_enc = network->iu.rab_assign_addr_enc;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020065 return conn;
66}
67
Neels Hofmeyr00e82d62017-07-05 15:19:52 +020068static int same_ue_conn(struct ranap_ue_conn_ctx *a, struct ranap_ue_conn_ctx *b)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020069{
70 if (a == b)
71 return 1;
Philipp Maierfbf66102017-04-09 12:32:51 +020072 return (a->conn_id == b->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020073}
74
75static inline void log_subscribers(struct gsm_network *network)
76{
77 if (!log_check_level(DIUCS, LOGL_DEBUG))
78 return;
79
Neels Hofmeyrc036b792018-11-29 22:37:51 +010080 struct ran_conn *conn;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020081 int i = 0;
Neels Hofmeyrc036b792018-11-29 22:37:51 +010082 llist_for_each_entry(conn, &network->ran_conns, entry) {
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020083 DEBUGP(DIUCS, "%3d: %s", i, vlr_subscr_name(conn->vsub));
84 switch (conn->via_ran) {
Neels Hofmeyr7814a832018-12-26 00:40:18 +010085 case OSMO_RAT_UTRAN_IU:
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020086 DEBUGPC(DIUCS, " Iu");
87 if (conn->iu.ue_ctx) {
Philipp Maierfbf66102017-04-09 12:32:51 +020088 DEBUGPC(DIUCS, " conn_id %d",
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020089 conn->iu.ue_ctx->conn_id
90 );
91 }
92 break;
Neels Hofmeyr7814a832018-12-26 00:40:18 +010093 case OSMO_RAT_GERAN_A:
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020094 DEBUGPC(DIUCS, " A");
95 /* TODO log A-interface connection details */
96 break;
Neels Hofmeyr7814a832018-12-26 00:40:18 +010097 case OSMO_RAT_UNKNOWN:
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020098 DEBUGPC(DIUCS, " ?");
99 break;
100 default:
101 DEBUGPC(DIUCS, " invalid");
102 break;
103 }
104 DEBUGPC(DIUCS, "\n");
105 i++;
106 }
107 DEBUGP(DIUCS, "subscribers registered: %d\n", i);
108}
109
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100110/* Return an existing IuCS RAN connection record for the given
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200111 * connection IDs, or return NULL if not found. */
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100112struct ran_conn *ran_conn_lookup_iu(
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200113 struct gsm_network *network,
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200114 struct ranap_ue_conn_ctx *ue)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200115{
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100116 struct ran_conn *conn;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200117
Philipp Maierfbf66102017-04-09 12:32:51 +0200118 DEBUGP(DIUCS, "Looking for IuCS subscriber: conn_id %" PRIx32 "\n",
119 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200120 log_subscribers(network);
121
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100122 llist_for_each_entry(conn, &network->ran_conns, entry) {
Neels Hofmeyr7814a832018-12-26 00:40:18 +0100123 if (conn->via_ran != OSMO_RAT_UTRAN_IU)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200124 continue;
125 if (!same_ue_conn(conn->iu.ue_ctx, ue))
126 continue;
Philipp Maierfbf66102017-04-09 12:32:51 +0200127 DEBUGP(DIUCS, "Found IuCS subscriber for conn_id %" PRIx32 "\n",
128 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200129 return conn;
130 }
Philipp Maierfbf66102017-04-09 12:32:51 +0200131 DEBUGP(DIUCS, "No IuCS subscriber found for conn_id %" PRIx32 "\n",
132 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200133 return NULL;
134}
135
136/* Receive MM/CC/... message from IuCS (SCCP user SAP).
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200137 * msg->dst must reference a struct ranap_ue_conn_ctx, which identifies the peer that
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200138 * sent the msg.
139 *
140 * For A-interface see libbsc/bsc_api.c gsm0408_rcvmsg(). */
141int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
142 uint16_t *lac)
143{
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200144 struct ranap_ue_conn_ctx *ue_ctx;
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100145 struct ran_conn *conn;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200146
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200147 ue_ctx = (struct ranap_ue_conn_ctx*)msg->dst;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200148
149 /* TODO: are there message types that could allow us to skip this
150 * search? */
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100151 conn = ran_conn_lookup_iu(network, ue_ctx);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200152
153 if (conn && lac && (conn->lac != *lac)) {
154 LOGP(DIUCS, LOGL_ERROR, "IuCS subscriber has changed LAC"
155 " within the same connection, discarding connection:"
156 " %s from LAC %d to %d\n",
157 vlr_subscr_name(conn->vsub), conn->lac, *lac);
158 /* Deallocate conn with previous LAC */
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100159 ran_conn_close(conn, GSM_CAUSE_INV_MAND_INFO);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200160 /* At this point we could be tolerant and allocate a new
161 * connection, but changing the LAC within the same connection
162 * is shifty. Rather cancel everything. */
163 return -1;
164 }
165
166 if (conn) {
167 /* Make sure we don't receive RR over IuCS; otherwise all
168 * messages handled by gsm0408_dispatch() are of interest (CC,
169 * MM, SMS, NS_SS, maybe even MM_GPRS and SM_GPRS). */
170 struct gsm48_hdr *gh = msgb_l3(msg);
171 uint8_t pdisc = gh->proto_discr & 0x0f;
172 OSMO_ASSERT(pdisc != GSM48_PDISC_RR);
173
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100174 ran_conn_dtap(conn, msg);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200175 } else {
176 /* allocate a new connection */
177
178 if (!lac) {
179 LOGP(DIUCS, LOGL_ERROR, "New IuCS subscriber"
180 " but no LAC available. Expecting an InitialUE"
181 " message containing a LAI IE."
182 " Dropping connection.\n");
183 return -1;
184 }
185
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100186 conn = ran_conn_allocate_iu(network, ue_ctx, *lac);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200187 if (!conn)
188 abort();
189
190 /* ownership of conn hereby goes to the MSC: */
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100191 ran_conn_compl_l3(conn, msg, 0);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200192 }
193
Neels Hofmeyrd03e7282018-11-30 01:20:32 +0100194 return 0;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200195}
Philipp Maier621ba032017-11-07 17:19:25 +0100196
197int iu_rab_act_cs(struct gsm_trans *trans)
198{
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100199 struct ran_conn *conn;
Philipp Maier621ba032017-11-07 17:19:25 +0100200 struct msgb *msg;
201 bool use_x213_nsap;
202 uint32_t conn_id;
203 struct ranap_ue_conn_ctx *uectx;
204 uint8_t rab_id;
205 uint32_t rtp_ip;
206 uint16_t rtp_port;
207
208 conn = trans->conn;
209 uectx = conn->iu.ue_ctx;
210 rab_id = conn->iu.rab_id;
211 rtp_ip = osmo_htonl(inet_addr(conn->rtp.local_addr_ran));
212 rtp_port = conn->rtp.local_port_ran;
213 conn_id = uectx->conn_id;
214
215 if (rtp_ip == INADDR_NONE) {
216 LOGP(DIUCS, LOGL_DEBUG,
217 "Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP IP-Address\n",
218 conn_id, rab_id);
219 return -EINVAL;
220 }
221 if (rtp_port == 0) {
222 LOGP(DIUCS, LOGL_DEBUG,
223 "Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP Port\n",
224 conn_id, rab_id);
225 return -EINVAL;
226 }
227
228 use_x213_nsap =
229 (uectx->rab_assign_addr_enc == RANAP_NSAP_ADDR_ENC_X213);
230
231 LOGP(DIUCS, LOGL_DEBUG,
232 "Assigning RAB: conn_id=%u, rab_id=%d, rtp=%x:%u, use_x213_nsap=%d\n",
233 conn_id, rab_id, rtp_ip, rtp_port, use_x213_nsap);
234
235 msg = ranap_new_msg_rab_assign_voice(rab_id, rtp_ip, rtp_port,
236 use_x213_nsap);
237 msg->l2h = msg->data;
238
239 if (ranap_iu_rab_act(uectx, msg))
240 LOGP(DIUCS, LOGL_ERROR,
241 "Failed to send RAB Assignment: conn_id=%d rab_id=%d rtp=%x:%u\n",
242 conn_id, rab_id, rtp_ip, rtp_port);
243 return 0;
244}
245
Daniel Willmann6fbd3bf2018-02-15 10:33:21 +0100246uint32_t iu_get_conn_id(const struct ranap_ue_conn_ctx *ue)
247{
248 return ue->conn_id;
249}