blob: cd83b41025a78f894f8ddeb225dcdb657b337adc [file] [log] [blame]
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +07001/*
2 * (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com>
3 *
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
21#include <stdio.h>
22#include <errno.h>
23
24#include <osmocom/core/linuxlist.h>
25#include <osmocom/core/utils.h>
26#include <osmocom/core/msgb.h>
27
28#include <osmocom/gsupclient/gsup_client.h>
29#include <osmocom/msc/gsm_subscriber.h>
30#include <osmocom/msc/transaction.h>
31#include <osmocom/msc/msc_common.h>
32#include <osmocom/msc/debug.h>
33#include <osmocom/msc/vlr.h>
34
35/* Common helper for preparing to be encoded GSUP message */
36static void gsup_sm_msg_init(struct osmo_gsup_message *gsup_msg,
37 enum osmo_gsup_message_type msg_type, const char *imsi,
38 uint8_t *sm_rp_mr)
39{
40 /* Init a mew GSUP message */
41 memset(gsup_msg, 0x00, sizeof(*gsup_msg));
42 gsup_msg->message_type = msg_type;
43
44 /* SM-RP-MR (Message Reference) */
45 gsup_msg->sm_rp_mr = sm_rp_mr;
46
47 /* Fill in subscriber's IMSI */
48 OSMO_STRLCPY_ARRAY(gsup_msg->imsi, imsi);
49}
50
51int gsm411_gsup_mo_fwd_sm_req(struct gsm_trans *trans, struct msgb *msg,
52 uint8_t sm_rp_mr, uint8_t *sm_rp_da, uint8_t sm_rp_da_len)
53{
54 uint8_t bcd_buf[GSM48_MI_SIZE] = { 0 };
55 struct osmo_gsup_message gsup_msg;
56 size_t bcd_len;
57
58 /* Associate logging messages with this subscriber */
59 log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub);
60
Neels Hofmeyrff7074a2019-02-28 05:50:06 +010061 LOG_TRANS(trans, LOGL_DEBUG, "TX GSUP MO-forwardSM-Req\n");
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +070062
63 /* Assign SM-RP-MR to transaction state */
64 trans->sms.sm_rp_mr = sm_rp_mr;
65
66 /* Encode subscriber's MSISDN */
67 bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf),
68 0, trans->vsub->msisdn);
69 if (bcd_len <= 0 || bcd_len > sizeof(bcd_buf)) {
Neels Hofmeyrff7074a2019-02-28 05:50:06 +010070 LOG_TRANS(trans, LOGL_ERROR, "Failed to encode subscriber's MSISDN\n");
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +070071 return -EINVAL;
72 }
73
74 /* Initialize a new GSUP message */
75 gsup_sm_msg_init(&gsup_msg, OSMO_GSUP_MSGT_MO_FORWARD_SM_REQUEST,
76 trans->vsub->imsi, &sm_rp_mr);
77
78 /* According to 12.2.3, the MSISDN from VLR is inserted here */
79 gsup_msg.sm_rp_oa_type = OSMO_GSUP_SMS_SM_RP_ODA_MSISDN;
80 gsup_msg.sm_rp_oa_len = bcd_len;
81 gsup_msg.sm_rp_oa = bcd_buf;
82
83 /* SM-RP-DA should (already) contain SMSC address */
84 gsup_msg.sm_rp_da_type = OSMO_GSUP_SMS_SM_RP_ODA_SMSC_ADDR;
85 gsup_msg.sm_rp_da_len = sm_rp_da_len;
86 gsup_msg.sm_rp_da = sm_rp_da;
87
88 /* SM-RP-UI (TPDU) is pointed by msgb->l4h */
89 gsup_msg.sm_rp_ui_len = msgb_l4len(msg);
90 gsup_msg.sm_rp_ui = (uint8_t *) msgb_sms(msg);
91
92 return osmo_gsup_client_enc_send(trans->net->vlr->gsup_client, &gsup_msg);
93}
94
95int gsm411_gsup_mo_ready_for_sm_req(struct gsm_trans *trans, uint8_t sm_rp_mr)
96{
97 struct osmo_gsup_message gsup_msg;
98
99 /* Associate logging messages with this subscriber */
100 log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub);
101
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100102 LOG_TRANS(trans, LOGL_DEBUG, "TX GSUP READY-FOR-SM Req\n");
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +0700103
104 /* Assign SM-RP-MR to transaction state */
105 trans->sms.sm_rp_mr = sm_rp_mr;
106
107 /* Initialize a new GSUP message */
108 gsup_sm_msg_init(&gsup_msg, OSMO_GSUP_MSGT_READY_FOR_SM_REQUEST,
109 trans->vsub->imsi, &sm_rp_mr);
110
111 /* Indicate SMMA as the Alert Reason */
112 gsup_msg.sm_alert_rsn = OSMO_GSUP_SMS_SM_ALERT_RSN_MEM_AVAIL;
113
114 return osmo_gsup_client_enc_send(trans->net->vlr->gsup_client, &gsup_msg);
115}
116
117/* Triggers either RP-ACK or RP-ERROR on response from SMSC */
118int gsm411_gsup_mo_handler(struct vlr_subscr *vsub,
119 struct osmo_gsup_message *gsup_msg)
120{
121 struct vlr_instance *vlr;
122 struct gsm_network *net;
123 struct gsm_trans *trans;
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +0700124 const char *msg_name;
125 bool msg_is_err;
126
127 /* Obtain required pointers */
128 vlr = vsub->vlr;
129 net = (struct gsm_network *) vlr->user_ctx;
130
131 /* Associate logging messages with this subscriber */
132 log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
133
134 /* Determine the message type and name */
135 msg_is_err = OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type);
136 switch (gsup_msg->message_type) {
137 case OSMO_GSUP_MSGT_MO_FORWARD_SM_ERROR:
138 case OSMO_GSUP_MSGT_MO_FORWARD_SM_RESULT:
139 msg_name = "MO-forwardSM";
140 break;
141 case OSMO_GSUP_MSGT_READY_FOR_SM_ERROR:
142 case OSMO_GSUP_MSGT_READY_FOR_SM_RESULT:
143 msg_name = "MO-ReadyForSM";
144 break;
145 default:
146 /* Shall not happen */
147 OSMO_ASSERT(0);
148 }
149
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +0700150 /* Make sure that 'SMS over GSUP' is expected */
151 if (!net->sms_over_gsup) {
152 /* TODO: notify sender about that? */
153 LOGP(DLSMS, LOGL_NOTICE, "Unexpected MO SMS over GSUP, "
154 "ignoring message...\n");
155 return -EIO;
156 }
157
158 /* Verify GSUP message */
159 if (!gsup_msg->sm_rp_mr)
160 goto msg_error;
161 if (msg_is_err && !gsup_msg->sm_rp_cause)
162 goto msg_error;
163
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +0700164 /* Attempt to find DTAP-transaction */
Vadim Yanitskiy36c44b22019-01-23 21:22:27 +0700165 trans = trans_find_by_sm_rp_mr(net, vsub, *(gsup_msg->sm_rp_mr));
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +0700166 if (!trans) {
167 LOGP(DLSMS, LOGL_NOTICE, "No transaction found for %s, "
168 "ignoring %s-%s message...\n", vlr_subscr_name(vsub),
169 msg_name, msg_is_err ? "Err" : "Res");
170 return -EIO; /* TODO: notify sender about that? */
171 }
172
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100173 LOG_TRANS(trans, LOGL_DEBUG, "RX %s-%s\n", msg_name, msg_is_err ? "Err" : "Res");
174
Vadim Yanitskiy76ef72d2018-11-07 05:08:18 +0700175 /* Send either RP-ERROR, or RP-ACK */
176 if (msg_is_err) {
177 /* TODO: handle optional SM-RP-UI payload (requires API change) */
178 gsm411_send_rp_error(trans, *(gsup_msg->sm_rp_mr),
179 *(gsup_msg->sm_rp_cause));
180 } else {
181 gsm411_send_rp_ack(trans, *(gsup_msg->sm_rp_mr));
182 }
183
184 return 0;
185
186msg_error:
187 /* TODO: notify sender about that? */
188 LOGP(DLSMS, LOGL_NOTICE, "RX malformed %s-%s\n",
189 msg_name, msg_is_err ? "Err" : "Res");
190 return -EINVAL;
191}
Vadim Yanitskiy82cc8a52018-11-15 01:05:53 +0700192
193int gsm411_gsup_mt_fwd_sm_res(struct gsm_trans *trans, uint8_t sm_rp_mr)
194{
195 struct osmo_gsup_message gsup_msg;
196
197 /* Associate logging messages with this subscriber */
198 log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub);
199
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100200 LOG_TRANS(trans, LOGL_DEBUG, "TX MT-forwardSM-Res\n");
Vadim Yanitskiy82cc8a52018-11-15 01:05:53 +0700201
202 /* Initialize a new GSUP message */
203 gsup_sm_msg_init(&gsup_msg, OSMO_GSUP_MSGT_MT_FORWARD_SM_RESULT,
204 trans->vsub->imsi, &sm_rp_mr);
205
206 return osmo_gsup_client_enc_send(trans->net->vlr->gsup_client, &gsup_msg);
207}
208
209int gsm411_gsup_mt_fwd_sm_err(struct gsm_trans *trans,
210 uint8_t sm_rp_mr, uint8_t cause)
211{
212 struct osmo_gsup_message gsup_msg;
213
214 /* Associate logging messages with this subscriber */
215 log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub);
216
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100217 LOG_TRANS(trans, LOGL_DEBUG, "TX MT-forwardSM-Err\n");
Vadim Yanitskiy82cc8a52018-11-15 01:05:53 +0700218
219 /* Initialize a new GSUP message */
220 gsup_sm_msg_init(&gsup_msg, OSMO_GSUP_MSGT_MT_FORWARD_SM_ERROR,
221 trans->vsub->imsi, &sm_rp_mr);
222
223 /* SM-RP-Cause value */
224 gsup_msg.sm_rp_cause = &cause;
225
226 /* TODO: include optional SM-RP-UI field if present */
227 return osmo_gsup_client_enc_send(trans->net->vlr->gsup_client, &gsup_msg);
228}
229
230/* Handles MT SMS (and triggers Paging Request if required) */
231int gsm411_gsup_mt_handler(struct vlr_subscr *vsub,
232 struct osmo_gsup_message *gsup_msg)
233{
234 struct vlr_instance *vlr;
235 struct gsm_network *net;
236 int rc;
237
238 /* Obtain required pointers */
239 vlr = vsub->vlr;
240 net = (struct gsm_network *) vlr->user_ctx;
241
242 /* Associate logging messages with this subscriber */
243 log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
244
245 LOGP(DLSMS, LOGL_DEBUG, "RX MT-forwardSM-Req\n");
246
247 /* Make sure that 'SMS over GSUP' is expected */
248 if (!net->sms_over_gsup) {
249 LOGP(DLSMS, LOGL_NOTICE, "Unexpected MT SMS over GSUP, "
250 "ignoring message...\n");
251 /* TODO: notify sender about that? */
252 return -EIO;
253 }
254
255 /**
256 * Verify GSUP message
257 *
258 * FIXME: SM-RP-MR is not known yet (to be assigned by MSC)
259 * NOTE: SM-RP-DA is out of our interest
260 */
261 if (!gsup_msg->sm_rp_mr)
262 goto msg_error;
263 if (!gsup_msg->sm_rp_ui)
264 goto msg_error;
265
266 /* SM-RP-OA shall contain SMSC address */
267 if (gsup_msg->sm_rp_oa_type != OSMO_GSUP_SMS_SM_RP_ODA_SMSC_ADDR)
268 goto msg_error;
269
270 /* Send RP-DATA */
271 rc = gsm411_send_rp_data(net, vsub,
272 gsup_msg->sm_rp_oa_len, gsup_msg->sm_rp_oa,
273 gsup_msg->sm_rp_ui_len, gsup_msg->sm_rp_ui);
274 if (rc) {
275 LOGP(DLSMS, LOGL_NOTICE, "Failed to send MT SMS, "
276 "ignoring MT-forwardSM-Req message...\n");
277 /* TODO: notify sender about that? */
278 return rc;
279 }
280
281 return 0;
282
283msg_error:
284 /* TODO: notify sender about that? */
285 LOGP(DLSMS, LOGL_NOTICE, "RX malformed MT-forwardSM-Req\n");
286 return -EINVAL;
287}