blob: d6da1f7952759d8084c9821c5c9b21c253c87cc7 [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
60 conn = talloc_zero(network, struct gsm_subscriber_connection);
61 if (!conn)
62 return NULL;
63
64 conn->network = network;
65 conn->via_ran = RAN_UTRAN_IU;
66 conn->iu.ue_ctx = ue;
67 conn->iu.ue_ctx->rab_assign_addr_enc = network->iu.rab_assign_addr_enc;
68 conn->lac = lac;
69
70 llist_add_tail(&conn->entry, &network->subscr_conns);
71 return conn;
72}
73
Neels Hofmeyr00e82d62017-07-05 15:19:52 +020074static int same_ue_conn(struct ranap_ue_conn_ctx *a, struct ranap_ue_conn_ctx *b)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020075{
76 if (a == b)
77 return 1;
Philipp Maierfbf66102017-04-09 12:32:51 +020078 return (a->conn_id == b->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020079}
80
81static inline void log_subscribers(struct gsm_network *network)
82{
83 if (!log_check_level(DIUCS, LOGL_DEBUG))
84 return;
85
86 struct gsm_subscriber_connection *conn;
87 int i = 0;
88 llist_for_each_entry(conn, &network->subscr_conns, entry) {
89 DEBUGP(DIUCS, "%3d: %s", i, vlr_subscr_name(conn->vsub));
90 switch (conn->via_ran) {
91 case RAN_UTRAN_IU:
92 DEBUGPC(DIUCS, " Iu");
93 if (conn->iu.ue_ctx) {
Philipp Maierfbf66102017-04-09 12:32:51 +020094 DEBUGPC(DIUCS, " conn_id %d",
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020095 conn->iu.ue_ctx->conn_id
96 );
97 }
98 break;
99 case RAN_GERAN_A:
100 DEBUGPC(DIUCS, " A");
101 /* TODO log A-interface connection details */
102 break;
103 case RAN_UNKNOWN:
104 DEBUGPC(DIUCS, " ?");
105 break;
106 default:
107 DEBUGPC(DIUCS, " invalid");
108 break;
109 }
110 DEBUGPC(DIUCS, "\n");
111 i++;
112 }
113 DEBUGP(DIUCS, "subscribers registered: %d\n", i);
114}
115
Philipp Maierfbf66102017-04-09 12:32:51 +0200116/* Return an existing IuCS subscriber connection record for the given
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200117 * connection IDs, or return NULL if not found. */
118struct gsm_subscriber_connection *subscr_conn_lookup_iu(
119 struct gsm_network *network,
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200120 struct ranap_ue_conn_ctx *ue)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200121{
122 struct gsm_subscriber_connection *conn;
123
Philipp Maierfbf66102017-04-09 12:32:51 +0200124 DEBUGP(DIUCS, "Looking for IuCS subscriber: conn_id %" PRIx32 "\n",
125 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200126 log_subscribers(network);
127
128 llist_for_each_entry(conn, &network->subscr_conns, entry) {
129 if (conn->via_ran != RAN_UTRAN_IU)
130 continue;
131 if (!same_ue_conn(conn->iu.ue_ctx, ue))
132 continue;
Philipp Maierfbf66102017-04-09 12:32:51 +0200133 DEBUGP(DIUCS, "Found IuCS subscriber for conn_id %" PRIx32 "\n",
134 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200135 return conn;
136 }
Philipp Maierfbf66102017-04-09 12:32:51 +0200137 DEBUGP(DIUCS, "No IuCS subscriber found for conn_id %" PRIx32 "\n",
138 ue->conn_id);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200139 return NULL;
140}
141
142/* Receive MM/CC/... message from IuCS (SCCP user SAP).
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200143 * msg->dst must reference a struct ranap_ue_conn_ctx, which identifies the peer that
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200144 * sent the msg.
145 *
146 * For A-interface see libbsc/bsc_api.c gsm0408_rcvmsg(). */
147int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
148 uint16_t *lac)
149{
150 int rc;
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200151 struct ranap_ue_conn_ctx *ue_ctx;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200152 struct gsm_subscriber_connection *conn;
153
Neels Hofmeyr00e82d62017-07-05 15:19:52 +0200154 ue_ctx = (struct ranap_ue_conn_ctx*)msg->dst;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200155
156 /* TODO: are there message types that could allow us to skip this
157 * search? */
158 conn = subscr_conn_lookup_iu(network, ue_ctx);
159
160 if (conn && lac && (conn->lac != *lac)) {
161 LOGP(DIUCS, LOGL_ERROR, "IuCS subscriber has changed LAC"
162 " within the same connection, discarding connection:"
163 " %s from LAC %d to %d\n",
164 vlr_subscr_name(conn->vsub), conn->lac, *lac);
165 /* Deallocate conn with previous LAC */
166 msc_subscr_conn_close(conn, GSM_CAUSE_INV_MAND_INFO);
167 /* At this point we could be tolerant and allocate a new
168 * connection, but changing the LAC within the same connection
169 * is shifty. Rather cancel everything. */
170 return -1;
171 }
172
173 if (conn) {
174 /* Make sure we don't receive RR over IuCS; otherwise all
175 * messages handled by gsm0408_dispatch() are of interest (CC,
176 * MM, SMS, NS_SS, maybe even MM_GPRS and SM_GPRS). */
177 struct gsm48_hdr *gh = msgb_l3(msg);
178 uint8_t pdisc = gh->proto_discr & 0x0f;
179 OSMO_ASSERT(pdisc != GSM48_PDISC_RR);
180
181 msc_dtap(conn, ue_ctx->conn_id, msg);
182 rc = 0;
183 } else {
184 /* allocate a new connection */
185
186 if (!lac) {
187 LOGP(DIUCS, LOGL_ERROR, "New IuCS subscriber"
188 " but no LAC available. Expecting an InitialUE"
189 " message containing a LAI IE."
190 " Dropping connection.\n");
191 return -1;
192 }
193
194 conn = subscr_conn_allocate_iu(network, ue_ctx, *lac);
195 if (!conn)
196 abort();
197
198 /* ownership of conn hereby goes to the MSC: */
199 rc = msc_compl_l3(conn, msg, 0);
200 }
201
202 return rc;
203}
Philipp Maier621ba032017-11-07 17:19:25 +0100204
205int iu_rab_act_cs(struct gsm_trans *trans)
206{
207 struct gsm_subscriber_connection *conn;
208 struct msgb *msg;
209 bool use_x213_nsap;
210 uint32_t conn_id;
211 struct ranap_ue_conn_ctx *uectx;
212 uint8_t rab_id;
213 uint32_t rtp_ip;
214 uint16_t rtp_port;
215
216 conn = trans->conn;
217 uectx = conn->iu.ue_ctx;
218 rab_id = conn->iu.rab_id;
219 rtp_ip = osmo_htonl(inet_addr(conn->rtp.local_addr_ran));
220 rtp_port = conn->rtp.local_port_ran;
221 conn_id = uectx->conn_id;
222
223 if (rtp_ip == INADDR_NONE) {
224 LOGP(DIUCS, LOGL_DEBUG,
225 "Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP IP-Address\n",
226 conn_id, rab_id);
227 return -EINVAL;
228 }
229 if (rtp_port == 0) {
230 LOGP(DIUCS, LOGL_DEBUG,
231 "Assigning RAB: conn_id=%u, rab_id=%d, invalid RTP Port\n",
232 conn_id, rab_id);
233 return -EINVAL;
234 }
235
236 use_x213_nsap =
237 (uectx->rab_assign_addr_enc == RANAP_NSAP_ADDR_ENC_X213);
238
239 LOGP(DIUCS, LOGL_DEBUG,
240 "Assigning RAB: conn_id=%u, rab_id=%d, rtp=%x:%u, use_x213_nsap=%d\n",
241 conn_id, rab_id, rtp_ip, rtp_port, use_x213_nsap);
242
243 msg = ranap_new_msg_rab_assign_voice(rab_id, rtp_ip, rtp_port,
244 use_x213_nsap);
245 msg->l2h = msg->data;
246
247 if (ranap_iu_rab_act(uectx, msg))
248 LOGP(DIUCS, LOGL_ERROR,
249 "Failed to send RAB Assignment: conn_id=%d rab_id=%d rtp=%x:%u\n",
250 conn_id, rab_id, rtp_ip, rtp_port);
251 return 0;
252}
253
Daniel Willmann6fbd3bf2018-02-15 10:33:21 +0100254uint32_t iu_get_conn_id(const struct ranap_ue_conn_ctx *ue)
255{
256 return ue->conn_id;
257}