blob: a3092f86eea63122bb527c1cb44855d8d7df755d [file] [log] [blame]
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001/* Code to manage MSC subscriber connections over IuCS interface */
2
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() */
51static struct gsm_subscriber_connection *subscr_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{
55 struct gsm_subscriber_connection *conn;
56
Philipp Maierfbf66102017-04-09 12:32:51 +020057 DEBUGP(DIUCS, "Allocating IuCS subscriber conn: lac %d, conn_id %" PRIx32 "\n",
58 lac, ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020059
Neels Hofmeyr93c74632018-04-02 23:10:28 +020060 conn = msc_subscr_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
81 struct gsm_subscriber_connection *conn;
82 int i = 0;
83 llist_for_each_entry(conn, &network->subscr_conns, entry) {
84 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
Philipp Maierfbf66102017-04-09 12:32:51 +0200111/* Return an existing IuCS subscriber connection record for the given
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200112 * connection IDs, or return NULL if not found. */
113struct gsm_subscriber_connection *subscr_conn_lookup_iu(
114 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{
117 struct gsm_subscriber_connection *conn;
118
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
123 llist_for_each_entry(conn, &network->subscr_conns, entry) {
124 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{
145 int rc;
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200146 struct ranap_ue_conn_ctx *ue_ctx;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200147 struct gsm_subscriber_connection *conn;
148
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200149 ue_ctx = (struct ranap_ue_conn_ctx*)msg->dst;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200150
151 /* TODO: are there message types that could allow us to skip this
152 * search? */
153 conn = subscr_conn_lookup_iu(network, ue_ctx);
154
155 if (conn && lac && (conn->lac != *lac)) {
156 LOGP(DIUCS, LOGL_ERROR, "IuCS subscriber has changed LAC"
157 " within the same connection, discarding connection:"
158 " %s from LAC %d to %d\n",
159 vlr_subscr_name(conn->vsub), conn->lac, *lac);
160 /* Deallocate conn with previous LAC */
161 msc_subscr_conn_close(conn, GSM_CAUSE_INV_MAND_INFO);
162 /* At this point we could be tolerant and allocate a new
163 * connection, but changing the LAC within the same connection
164 * is shifty. Rather cancel everything. */
165 return -1;
166 }
167
168 if (conn) {
169 /* Make sure we don't receive RR over IuCS; otherwise all
170 * messages handled by gsm0408_dispatch() are of interest (CC,
171 * MM, SMS, NS_SS, maybe even MM_GPRS and SM_GPRS). */
172 struct gsm48_hdr *gh = msgb_l3(msg);
173 uint8_t pdisc = gh->proto_discr & 0x0f;
174 OSMO_ASSERT(pdisc != GSM48_PDISC_RR);
175
176 msc_dtap(conn, ue_ctx->conn_id, msg);
177 rc = 0;
178 } else {
179 /* allocate a new connection */
180
181 if (!lac) {
182 LOGP(DIUCS, LOGL_ERROR, "New IuCS subscriber"
183 " but no LAC available. Expecting an InitialUE"
184 " message containing a LAI IE."
185 " Dropping connection.\n");
186 return -1;
187 }
188
189 conn = subscr_conn_allocate_iu(network, ue_ctx, *lac);
190 if (!conn)
191 abort();
192
193 /* ownership of conn hereby goes to the MSC: */
194 rc = msc_compl_l3(conn, msg, 0);
195 }
196
197 return rc;
198}
Philipp Maier621ba032017-11-07 17:19:25 +0100199
200int iu_rab_act_cs(struct gsm_trans *trans)
201{
202 struct gsm_subscriber_connection *conn;
203 struct msgb *msg;
204 bool use_x213_nsap;
205 uint32_t conn_id;
206 struct ranap_ue_conn_ctx *uectx;
207 uint8_t rab_id;
208 uint32_t rtp_ip;
209 uint16_t rtp_port;
210
211 conn = trans->conn;
212 uectx = conn->iu.ue_ctx;
213 rab_id = conn->iu.rab_id;
214 rtp_ip = osmo_htonl(inet_addr(conn->rtp.local_addr_ran));
215 rtp_port = conn->rtp.local_port_ran;
216 conn_id = uectx->conn_id;
217
218 if (rtp_ip == INADDR_NONE) {
219 LOGP(DIUCS, LOGL_DEBUG,
220 "Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP IP-Address\n",
221 conn_id, rab_id);
222 return -EINVAL;
223 }
224 if (rtp_port == 0) {
225 LOGP(DIUCS, LOGL_DEBUG,
226 "Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP Port\n",
227 conn_id, rab_id);
228 return -EINVAL;
229 }
230
231 use_x213_nsap =
232 (uectx->rab_assign_addr_enc == RANAP_NSAP_ADDR_ENC_X213);
233
234 LOGP(DIUCS, LOGL_DEBUG,
235 "Assigning RAB: conn_id=%u, rab_id=%d, rtp=%x:%u, use_x213_nsap=%d\n",
236 conn_id, rab_id, rtp_ip, rtp_port, use_x213_nsap);
237
238 msg = ranap_new_msg_rab_assign_voice(rab_id, rtp_ip, rtp_port,
239 use_x213_nsap);
240 msg->l2h = msg->data;
241
242 if (ranap_iu_rab_act(uectx, msg))
243 LOGP(DIUCS, LOGL_ERROR,
244 "Failed to send RAB Assignment: conn_id=%d rab_id=%d rtp=%x:%u\n",
245 conn_id, rab_id, rtp_ip, rtp_port);
246 return 0;
247}
248
Daniel Willmann6fbd3bf2018-02-15 10:33:21 +0100249uint32_t iu_get_conn_id(const struct ranap_ue_conn_ctx *ue)
250{
251 return ue->conn_id;
252}