blob: 1e4ab1958e440914c431286f423c042cc4efaedf [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/osmo_msc.h>
35#include <osmocom/msc/vlr.h>
Philipp Maier621ba032017-11-07 17:19:25 +010036#include <osmocom/core/byteswap.h>
37
38#include "../../bscconfig.h"
39
40#ifdef BUILD_IU
41#include <osmocom/ranap/iu_client.h>
42extern struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id,
43 uint32_t rtp_ip,
44 uint16_t rtp_port,
45 bool use_x213_nsap);
46#else
47#include <osmocom/msc/iu_dummy.h>
48#endif /* BUILD_IU */
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020049
50/* For A-interface see libbsc/bsc_api.c subscr_con_allocate() */
Neels Hofmeyrc036b792018-11-29 22:37:51 +010051static struct ran_conn *ran_conn_allocate_iu(struct gsm_network *network,
Neels Hofmeyr00e82d62017-07-05 15:19:52 +020052 struct ranap_ue_conn_ctx *ue,
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020053 uint16_t lac)
54{
Neels Hofmeyrc036b792018-11-29 22:37:51 +010055 struct ran_conn *conn;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020056
Neels Hofmeyrc036b792018-11-29 22:37:51 +010057 DEBUGP(DIUCS, "Allocating IuCS RAN conn: lac %d, conn_id %" PRIx32 "\n",
Philipp Maierfbf66102017-04-09 12:32:51 +020058 lac, ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020059
Neels Hofmeyrc036b792018-11-29 22:37:51 +010060 conn = ran_conn_alloc(network, RAN_UTRAN_IU, lac);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020061 if (!conn)
62 return NULL;
63
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020064 conn->iu.ue_ctx = ue;
65 conn->iu.ue_ctx->rab_assign_addr_enc = network->iu.rab_assign_addr_enc;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020066 return conn;
67}
68
Neels Hofmeyr00e82d62017-07-05 15:19:52 +020069static int same_ue_conn(struct ranap_ue_conn_ctx *a, struct ranap_ue_conn_ctx *b)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020070{
71 if (a == b)
72 return 1;
Philipp Maierfbf66102017-04-09 12:32:51 +020073 return (a->conn_id == b->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020074}
75
76static inline void log_subscribers(struct gsm_network *network)
77{
78 if (!log_check_level(DIUCS, LOGL_DEBUG))
79 return;
80
Neels Hofmeyrc036b792018-11-29 22:37:51 +010081 struct ran_conn *conn;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020082 int i = 0;
Neels Hofmeyrc036b792018-11-29 22:37:51 +010083 llist_for_each_entry(conn, &network->ran_conns, entry) {
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020084 DEBUGP(DIUCS, "%3d: %s", i, vlr_subscr_name(conn->vsub));
85 switch (conn->via_ran) {
86 case RAN_UTRAN_IU:
87 DEBUGPC(DIUCS, " Iu");
88 if (conn->iu.ue_ctx) {
Philipp Maierfbf66102017-04-09 12:32:51 +020089 DEBUGPC(DIUCS, " conn_id %d",
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020090 conn->iu.ue_ctx->conn_id
91 );
92 }
93 break;
94 case RAN_GERAN_A:
95 DEBUGPC(DIUCS, " A");
96 /* TODO log A-interface connection details */
97 break;
98 case RAN_UNKNOWN:
99 DEBUGPC(DIUCS, " ?");
100 break;
101 default:
102 DEBUGPC(DIUCS, " invalid");
103 break;
104 }
105 DEBUGPC(DIUCS, "\n");
106 i++;
107 }
108 DEBUGP(DIUCS, "subscribers registered: %d\n", i);
109}
110
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100111/* Return an existing IuCS RAN connection record for the given
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200112 * connection IDs, or return NULL if not found. */
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100113struct ran_conn *ran_conn_lookup_iu(
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200114 struct gsm_network *network,
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200115 struct ranap_ue_conn_ctx *ue)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200116{
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100117 struct ran_conn *conn;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200118
Philipp Maierfbf66102017-04-09 12:32:51 +0200119 DEBUGP(DIUCS, "Looking for IuCS subscriber: conn_id %" PRIx32 "\n",
120 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200121 log_subscribers(network);
122
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100123 llist_for_each_entry(conn, &network->ran_conns, entry) {
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200124 if (conn->via_ran != RAN_UTRAN_IU)
125 continue;
126 if (!same_ue_conn(conn->iu.ue_ctx, ue))
127 continue;
Philipp Maierfbf66102017-04-09 12:32:51 +0200128 DEBUGP(DIUCS, "Found IuCS subscriber for conn_id %" PRIx32 "\n",
129 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200130 return conn;
131 }
Philipp Maierfbf66102017-04-09 12:32:51 +0200132 DEBUGP(DIUCS, "No IuCS subscriber found for conn_id %" PRIx32 "\n",
133 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200134 return NULL;
135}
136
137/* Receive MM/CC/... message from IuCS (SCCP user SAP).
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200138 * msg->dst must reference a struct ranap_ue_conn_ctx, which identifies the peer that
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200139 * sent the msg.
140 *
141 * For A-interface see libbsc/bsc_api.c gsm0408_rcvmsg(). */
142int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
143 uint16_t *lac)
144{
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200145 struct ranap_ue_conn_ctx *ue_ctx;
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100146 struct ran_conn *conn;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200147
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200148 ue_ctx = (struct ranap_ue_conn_ctx*)msg->dst;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200149
150 /* TODO: are there message types that could allow us to skip this
151 * search? */
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100152 conn = ran_conn_lookup_iu(network, ue_ctx);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200153
154 if (conn && lac && (conn->lac != *lac)) {
155 LOGP(DIUCS, LOGL_ERROR, "IuCS subscriber has changed LAC"
156 " within the same connection, discarding connection:"
157 " %s from LAC %d to %d\n",
158 vlr_subscr_name(conn->vsub), conn->lac, *lac);
159 /* Deallocate conn with previous LAC */
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100160 ran_conn_close(conn, GSM_CAUSE_INV_MAND_INFO);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200161 /* At this point we could be tolerant and allocate a new
162 * connection, but changing the LAC within the same connection
163 * is shifty. Rather cancel everything. */
164 return -1;
165 }
166
167 if (conn) {
168 /* Make sure we don't receive RR over IuCS; otherwise all
169 * messages handled by gsm0408_dispatch() are of interest (CC,
170 * MM, SMS, NS_SS, maybe even MM_GPRS and SM_GPRS). */
171 struct gsm48_hdr *gh = msgb_l3(msg);
172 uint8_t pdisc = gh->proto_discr & 0x0f;
173 OSMO_ASSERT(pdisc != GSM48_PDISC_RR);
174
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100175 ran_conn_dtap(conn, msg);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200176 } else {
177 /* allocate a new connection */
178
179 if (!lac) {
180 LOGP(DIUCS, LOGL_ERROR, "New IuCS subscriber"
181 " but no LAC available. Expecting an InitialUE"
182 " message containing a LAI IE."
183 " Dropping connection.\n");
184 return -1;
185 }
186
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100187 conn = ran_conn_allocate_iu(network, ue_ctx, *lac);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200188 if (!conn)
189 abort();
190
191 /* ownership of conn hereby goes to the MSC: */
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100192 ran_conn_compl_l3(conn, msg, 0);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200193 }
194
Neels Hofmeyrd03e7282018-11-30 01:20:32 +0100195 return 0;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200196}
Philipp Maier621ba032017-11-07 17:19:25 +0100197
198int iu_rab_act_cs(struct gsm_trans *trans)
199{
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100200 struct ran_conn *conn;
Philipp Maier621ba032017-11-07 17:19:25 +0100201 struct msgb *msg;
202 bool use_x213_nsap;
203 uint32_t conn_id;
204 struct ranap_ue_conn_ctx *uectx;
205 uint8_t rab_id;
206 uint32_t rtp_ip;
207 uint16_t rtp_port;
208
209 conn = trans->conn;
210 uectx = conn->iu.ue_ctx;
211 rab_id = conn->iu.rab_id;
212 rtp_ip = osmo_htonl(inet_addr(conn->rtp.local_addr_ran));
213 rtp_port = conn->rtp.local_port_ran;
214 conn_id = uectx->conn_id;
215
216 if (rtp_ip == INADDR_NONE) {
217 LOGP(DIUCS, LOGL_DEBUG,
218 "Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP IP-Address\n",
219 conn_id, rab_id);
220 return -EINVAL;
221 }
222 if (rtp_port == 0) {
223 LOGP(DIUCS, LOGL_DEBUG,
224 "Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP Port\n",
225 conn_id, rab_id);
226 return -EINVAL;
227 }
228
229 use_x213_nsap =
230 (uectx->rab_assign_addr_enc == RANAP_NSAP_ADDR_ENC_X213);
231
232 LOGP(DIUCS, LOGL_DEBUG,
233 "Assigning RAB: conn_id=%u, rab_id=%d, rtp=%x:%u, use_x213_nsap=%d\n",
234 conn_id, rab_id, rtp_ip, rtp_port, use_x213_nsap);
235
236 msg = ranap_new_msg_rab_assign_voice(rab_id, rtp_ip, rtp_port,
237 use_x213_nsap);
238 msg->l2h = msg->data;
239
240 if (ranap_iu_rab_act(uectx, msg))
241 LOGP(DIUCS, LOGL_ERROR,
242 "Failed to send RAB Assignment: conn_id=%d rab_id=%d rtp=%x:%u\n",
243 conn_id, rab_id, rtp_ip, rtp_port);
244 return 0;
245}
246
Daniel Willmann6fbd3bf2018-02-15 10:33:21 +0100247uint32_t iu_get_conn_id(const struct ranap_ue_conn_ctx *ue)
248{
249 return ue->conn_id;
250}