blob: a7d5e11c298567a0da43daa9433d425f330aeda6 [file] [log] [blame]
Harald Welte55d724a2017-10-16 18:25:45 +02001/* Point-to-Point (PP) Short Message Service (SMS).
Andreas Eversbergbbf90342011-10-28 03:55:37 +02002 * Support on Mobile Radio Interface
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02003 * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0. */
4/*
5 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
Andreas Eversbergbbf90342011-10-28 03:55:37 +02006 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
7 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
8 * (C) 2010 by On-Waves
9 * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
10 *
11 * All Rights Reserved
12 *
Harald Weltee08da972017-11-13 01:00:26 +090013 * SPDX-License-Identifier: GPL-2.0+
14 *
Andreas Eversbergbbf90342011-10-28 03:55:37 +020015 * This program is free software; you can redistribute it and/or modify
Harald Welte388fb032014-10-26 20:42:49 +010016 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
Andreas Eversbergbbf90342011-10-28 03:55:37 +020018 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte388fb032014-10-26 20:42:49 +010023 * GNU General Public License for more details.
Andreas Eversbergbbf90342011-10-28 03:55:37 +020024 *
Harald Welte388fb032014-10-26 20:42:49 +010025 * You should have received a copy of the GNU General Public License
Andreas Eversbergbbf90342011-10-28 03:55:37 +020026 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *
28 */
29
30/* Notes on msg:
31 *
32 * Messages from lower layer are freed by lower layer.
33 *
34 * Messages to upper layer are freed after upper layer call returns, so upper
35 * layer cannot use data after returning. Upper layer must not free the msg.
36 *
37 * This implies: Lower layer messages can be forwarded to upper layer.
38 *
39 * Upper layer messages are freed by lower layer, so they must not be freed
40 * after calling lower layer.
41 *
42 *
43 * Notes on release:
44 *
45 * Whenever the process returns to IDLE, the MM connection is released using
46 * MMSMS-REL-REQ. It is allowed to destroy this process while processing
47 * this message.
48 *
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +010049 * There is an exception, if MMSMS-REL-IND is received from lower layer, the
Andreas Eversbergbbf90342011-10-28 03:55:37 +020050 * process returns to IDLE without sending MMSMS-REL-REQ.
51 *
52 */
53
Harald Welte701968f2020-07-30 21:33:48 +020054#include <sys/types.h>
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010055#include <inttypes.h>
Harald Welte701968f2020-07-30 21:33:48 +020056#include <string.h>
Andreas Eversbergbbf90342011-10-28 03:55:37 +020057#include <errno.h>
58#include <osmocom/core/msgb.h>
59#include <osmocom/core/logging.h>
60#include <osmocom/core/timer.h>
61
62#include <osmocom/gsm/gsm0411_utils.h>
63#include <osmocom/gsm/gsm0411_smc.h>
64#include <osmocom/gsm/protocol/gsm_04_08.h>
65
Harald Welte96e2a002017-06-12 21:44:18 +020066/*! \addtogroup sms
67 * @{
Harald Welte55d724a2017-10-16 18:25:45 +020068 * \file gsm0411_smc.c
Neels Hofmeyr87e45502017-06-20 00:17:59 +020069 * Point-to-Point (PP) Short Message Service (SMS) as per TS 04.11
Harald Welte96e2a002017-06-12 21:44:18 +020070 */
71
Andreas Eversbergbbf90342011-10-28 03:55:37 +020072static void cp_timer_expired(void *data);
73
Sylvain Munautcc90d492011-11-12 23:52:40 +010074#define MAX_SMS_RETRY 2
Andreas Eversbergbbf90342011-10-28 03:55:37 +020075
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010076#define SMC_LOG_STR "SMC(%" PRIu64 ") "
77
Andreas Eversbergbbf90342011-10-28 03:55:37 +020078/* init a new instance */
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010079void gsm411_smc_init(struct gsm411_smc_inst *inst, uint64_t id, int network,
Andreas Eversbergbbf90342011-10-28 03:55:37 +020080 int (*mn_recv) (struct gsm411_smc_inst *inst, int msg_type,
81 struct msgb *msg),
82 int (*mm_send) (struct gsm411_smc_inst *inst, int msg_type,
83 struct msgb *msg, int cp_msg_type))
84{
85 memset(inst, 0, sizeof(*inst));
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010086 inst->id = id;
Andreas Eversbergbbf90342011-10-28 03:55:37 +020087 inst->network = network;
88 inst->cp_max_retr = MAX_SMS_RETRY;
Sylvain Munaut0d9b8ec2011-11-12 23:52:20 +010089 inst->cp_tc1 = GSM411_TMR_TC1A_SEC / (inst->cp_max_retr + 1);
Andreas Eversbergbbf90342011-10-28 03:55:37 +020090 inst->cp_state = GSM411_CPS_IDLE;
91 inst->mn_recv = mn_recv;
92 inst->mm_send = mm_send;
93
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010094 LOGP(DLSMS, LOGL_INFO,
Holger Hans Peter Freyther68f94472012-12-01 12:51:34 +010095 SMC_LOG_STR "instance created for %s\n",
96 inst->id, inst->network ? "network" : "mobile");
Andreas Eversbergbbf90342011-10-28 03:55:37 +020097}
98
99/* clear instance */
100void gsm411_smc_clear(struct gsm411_smc_inst *inst)
101{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100102 LOGP(DLSMS, LOGL_INFO,
103 SMC_LOG_STR "clearing instance\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200104
105 osmo_timer_del(&inst->cp_timer);
106
107 /* free stored msg */
108 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100109 LOGP(DLSMS, LOGL_INFO,
110 SMC_LOG_STR "dropping pending message\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200111 msgb_free(inst->cp_msg);
112 inst->cp_msg = NULL;
113 }
114}
115
116const char *smc_state_names[] = {
117 "IDLE",
118 "MM_CONN_PENDING",
119 "WAIT_CP_ACK",
120 "MM_ESTABLISHED",
121};
122
123const struct value_string gsm411_cp_cause_strs[] = {
124 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
125 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
126 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
127 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
128 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
129 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
130 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
131 "Message incompatible with protocol state" },
132 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
133 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
134 { 0, 0 }
135};
136
137static void new_cp_state(struct gsm411_smc_inst *inst,
138 enum gsm411_cp_state state)
139{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100140 LOGP(DLSMS, LOGL_INFO,
141 SMC_LOG_STR "new CP state %s -> %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200142 smc_state_names[inst->cp_state], smc_state_names[state]);
143 inst->cp_state = state;
144}
145
146static int gsm411_tx_cp_error(struct gsm411_smc_inst *inst, uint8_t cause)
147{
148 struct msgb *nmsg = gsm411_msgb_alloc();
149 uint8_t *causep;
150
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100151 LOGP(DLSMS, LOGL_NOTICE,
152 SMC_LOG_STR "TX CP-ERROR, cause %d (%s)\n", inst->id, cause,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200153 get_value_string(gsm411_cp_cause_strs, cause));
154
155 causep = msgb_put(nmsg, 1);
156 *causep = cause;
157
158 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
159 GSM411_MT_CP_ERROR);
160}
161
Holger Hans Peter Freyther866fc912012-11-13 22:29:35 +0100162/* establish SMC connection */
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200163static int gsm411_mnsms_est_req(struct gsm411_smc_inst *inst, struct msgb *msg)
164{
165 struct msgb *nmsg;
166
167 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100168 LOGP(DLSMS, LOGL_FATAL,
169 SMC_LOG_STR "EST REQ, but we already have an "
170 "cp_msg. This should never happen, please fix!\n",
171 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200172 msgb_free(inst->cp_msg);
173 }
174
175 inst->cp_msg = msg;
176 new_cp_state(inst, GSM411_CPS_MM_CONN_PENDING);
177 /* clear stored release flag */
178 inst->cp_rel = 0;
179 /* send MMSMS_EST_REQ */
180 nmsg = gsm411_msgb_alloc();
181 return inst->mm_send(inst, GSM411_MMSMS_EST_REQ, nmsg, 0);
182}
183
184static int gsm411_mmsms_send_msg(struct gsm411_smc_inst *inst)
185{
186 struct msgb *nmsg;
187
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100188 LOGP(DLSMS, LOGL_INFO,
189 SMC_LOG_STR "send CP data\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200190 /* reset retry counter */
191 if (inst->cp_state != GSM411_CPS_WAIT_CP_ACK)
192 inst->cp_retx = 0;
193 /* 5.2.3.1.2: enter MO-wait for CP-ACK */
194 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
195 new_cp_state(inst, GSM411_CPS_WAIT_CP_ACK);
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200196 osmo_timer_setup(&inst->cp_timer, cp_timer_expired, inst);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200197 /* 5.3.2.1: Set Timer TC1A */
198 osmo_timer_schedule(&inst->cp_timer, inst->cp_tc1, 0);
199 /* clone cp_msg */
200 nmsg = gsm411_msgb_alloc();
201 memcpy(msgb_put(nmsg, inst->cp_msg->len), inst->cp_msg->data,
202 inst->cp_msg->len);
203 /* send MMSMS_DATA_REQ with CP-DATA */
204 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
205 GSM411_MT_CP_DATA);
206}
207
208static int gsm411_mmsms_est_cnf(struct gsm411_smc_inst *inst, struct msgb *msg)
209{
210 if (!inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100211 LOGP(DLSMS, LOGL_FATAL,
212 SMC_LOG_STR "EST CNF, but we have no cp_msg. This "
213 "should never happen, please fix!\n",
214 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200215 return -EINVAL;
216 }
217
218 return gsm411_mmsms_send_msg(inst);
219}
220
221/* SMC TC1* is expired */
222static void cp_timer_expired(void *data)
223{
224 struct gsm411_smc_inst *inst = data;
225 struct msgb *nmsg;
226
227 if (inst->cp_retx == inst->cp_max_retr) {
228
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100229 LOGP(DLSMS, LOGL_INFO,
230 SMC_LOG_STR "TC1* timeout, no more retries.\n",
231 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200232 /* 5.3.2.1: enter idle state */
233 new_cp_state(inst, GSM411_CPS_IDLE);
234 /* indicate error */
235 nmsg = gsm411_msgb_alloc();
236 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
237 msgb_free(nmsg);
238 /* free pending stored msg */
239 if (inst->cp_msg) {
240 msgb_free(inst->cp_msg);
241 inst->cp_msg = NULL;
242 }
243 /* release MM connection */
244 nmsg = gsm411_msgb_alloc();
245 inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
246 return;
247 }
248
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100249 LOGP(DLSMS, LOGL_INFO,
250 SMC_LOG_STR "TC1* timeout, retrying...\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200251 inst->cp_retx++;
252 gsm411_mmsms_est_cnf(inst, NULL);
253}
254
255static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg)
256{
257 /* free stored msg */
258 if (inst->cp_msg) {
259 msgb_free(inst->cp_msg);
260 inst->cp_msg = NULL;
261 }
262
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100263 LOGP(DLSMS, LOGL_INFO,
264 SMC_LOG_STR "received CP-ACK\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200265 /* 5.3.2.1 enter MM Connection established */
266 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
267 /* 5.3.2.1: Reset Timer TC1* */
268 osmo_timer_del(&inst->cp_timer);
269
270 /* pending release? */
271 if (inst->cp_rel) {
272 struct msgb *nmsg;
273
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100274 LOGP(DLSMS, LOGL_INFO,
275 SMC_LOG_STR "we have pending release.\n",
276 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200277 new_cp_state(inst, GSM411_CPS_IDLE);
278 /* release MM connection */
279 nmsg = gsm411_msgb_alloc();
280 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
281 }
282
283 return 0;
284}
285
286static int gsm411_mmsms_cp_data(struct gsm411_smc_inst *inst, struct msgb *msg)
287{
288 struct msgb *nmsg;
289 int mt = GSM411_MNSMS_DATA_IND;
290
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100291 LOGP(DLSMS, LOGL_INFO,
292 SMC_LOG_STR "received CP-DATA\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200293 /* 5.3.1 enter MM Connection established (if idle) */
294 if (inst->cp_state == GSM411_CPS_IDLE) {
295 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
296 mt = GSM411_MNSMS_EST_IND;
297 /* clear stored release flag */
298 inst->cp_rel = 0;
299 }
300 /* send MMSMS_DATA_REQ (CP ACK) */
301 nmsg = gsm411_msgb_alloc();
302 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, GSM411_MT_CP_ACK);
303 /* indicate data */
304 inst->mn_recv(inst, mt, msg);
305
306 return 0;
307}
308
309/* send CP DATA */
310static int gsm411_mnsms_data_req(struct gsm411_smc_inst *inst, struct msgb *msg)
311{
312 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100313 LOGP(DLSMS, LOGL_FATAL,
314 SMC_LOG_STR "DATA REQ, but we already have an "
315 "cp_msg. This should never happen, please fix!\n",
316 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200317 msgb_free(inst->cp_msg);
318 }
319
320 /* store and send */
321 inst->cp_msg = msg;
322 return gsm411_mmsms_send_msg(inst);
323}
324
325/* release SMC connection */
326static int gsm411_mnsms_rel_req(struct gsm411_smc_inst *inst, struct msgb *msg)
327{
328 struct msgb *nmsg;
329
330 msgb_free(msg);
331
332 /* discard silently */
333 if (inst->cp_state == GSM411_CPS_IDLE)
334 return 0;
335
336 /* store release, until established or released */
337 if (inst->cp_state != GSM411_CPS_MM_ESTABLISHED) {
Holger Hans Peter Freyther09161592012-11-11 10:09:24 +0100338 LOGP(DLSMS, LOGL_NOTICE,
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100339 SMC_LOG_STR "cannot release yet current state: %s\n",
340 inst->id, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200341 inst->cp_rel = 1;
342 return 0;
343 }
344
345 /* free stored msg */
346 if (inst->cp_msg) {
347 msgb_free(inst->cp_msg);
348 inst->cp_msg = NULL;
349 }
350
351 new_cp_state(inst, GSM411_CPS_IDLE);
352 /* release MM connection */
353 nmsg = gsm411_msgb_alloc();
354 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
355}
356
357static int gsm411_mmsms_cp_error(struct gsm411_smc_inst *inst, struct msgb *msg)
358{
359 struct msgb *nmsg;
360
361 /* free stored msg */
362 if (inst->cp_msg) {
363 msgb_free(inst->cp_msg);
364 inst->cp_msg = NULL;
365 }
366
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100367 LOGP(DLSMS, LOGL_INFO,
368 SMC_LOG_STR "received CP-ERROR\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200369 /* 5.3.4 enter idle */
370 new_cp_state(inst, GSM411_CPS_IDLE);
371 /* indicate error */
372 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, msg);
373 /* release MM connection */
374 nmsg = gsm411_msgb_alloc();
375 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
376}
377
378static int gsm411_mmsms_rel_ind(struct gsm411_smc_inst *inst, struct msgb *msg)
379{
380 struct msgb *nmsg;
381
382 /* free stored msg */
383 if (inst->cp_msg) {
384 msgb_free(inst->cp_msg);
385 inst->cp_msg = NULL;
386 }
387
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100388 LOGP(DLSMS, LOGL_INFO,
389 SMC_LOG_STR "MM layer is released\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200390 /* 5.3.4 enter idle */
391 new_cp_state(inst, GSM411_CPS_IDLE);
392 /* indicate error */
393 nmsg = gsm411_msgb_alloc();
394 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
395 msgb_free(nmsg);
396
397 return 0;
398}
399
400/* abort SMC connection */
401static int gsm411_mnsms_abort_req(struct gsm411_smc_inst *inst,
402 struct msgb *msg)
403{
404 struct msgb *nmsg;
405
406 /* free stored msg */
407 if (inst->cp_msg) {
408 msgb_free(inst->cp_msg);
409 inst->cp_msg = NULL;
410 }
411
412 /* 5.3.4 go idle */
413 new_cp_state(inst, GSM411_CPS_IDLE);
414 /* send MMSMS_DATA_REQ with CP-ERROR */
415 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, msg, GSM411_MT_CP_ERROR);
416 /* release MM connection */
417 nmsg = gsm411_msgb_alloc();
418 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
419}
420
421/* statefull handling for MNSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100422static const struct smcdownstate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200423 uint32_t states;
424 int type;
425 const char *name;
426 int (*rout) (struct gsm411_smc_inst *inst,
427 struct msgb *msg);
428} smcdownstatelist[] = {
429 /* establish request */
430 {SBIT(GSM411_CPS_IDLE),
431 GSM411_MNSMS_EST_REQ,
432 "MNSMS-EST-REQ", gsm411_mnsms_est_req},
433
434 /* release request */
435 {ALL_STATES,
436 GSM411_MNSMS_REL_REQ,
437 "MNSMS-REL-REQ", gsm411_mnsms_rel_req},
438
439 /* data request */
440 {SBIT(GSM411_CPS_MM_ESTABLISHED),
441 GSM411_MNSMS_DATA_REQ,
442 "MNSMS-DATA-REQ", gsm411_mnsms_data_req},
443
444 /* abort request */
445 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
446 GSM411_MNSMS_ABORT_REQ,
447 "MNSMS-ABORT-REQ", gsm411_mnsms_abort_req},
448};
449
450#define SMCDOWNSLLEN \
451 (sizeof(smcdownstatelist) / sizeof(struct smcdownstate))
452
453/* message from upper layer */
454int gsm411_smc_send(struct gsm411_smc_inst *inst, int msg_type,
455 struct msgb *msg)
456{
457 int i, rc;
458
459 /* find function for current state and message */
460 for (i = 0; i < SMCDOWNSLLEN; i++) {
461 if ((msg_type == smcdownstatelist[i].type)
462 && (SBIT(inst->cp_state) & smcdownstatelist[i].states))
463 break;
464 }
465 if (i == SMCDOWNSLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100466 LOGP(DLSMS, LOGL_NOTICE,
467 SMC_LOG_STR "message %u unhandled at this state %s.\n",
468 inst->id, msg_type, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200469 msgb_free(msg);
470 return 0;
471 }
472
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100473 LOGP(DLSMS, LOGL_INFO,
474 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200475 smcdownstatelist[i].name, smc_state_names[inst->cp_state]);
476
477 rc = smcdownstatelist[i].rout(inst, msg);
478
479 return rc;
480}
481
482/* statefull handling for MMSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100483static const struct smcdatastate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200484 uint32_t states;
485 int type, cp_type;
486 const char *name;
487 int (*rout) (struct gsm411_smc_inst *inst,
488 struct msgb *msg);
489} smcdatastatelist[] = {
490 /* establish confirm */
491 {SBIT(GSM411_CPS_MM_CONN_PENDING),
492 GSM411_MMSMS_EST_CNF, 0,
493 "MMSMS-EST-CNF", gsm411_mmsms_est_cnf},
494
495 /* establish indication (CP DATA) */
496 {SBIT(GSM411_CPS_IDLE),
497 GSM411_MMSMS_EST_IND, GSM411_MT_CP_DATA,
498 "MMSMS-EST-IND (CP DATA)", gsm411_mmsms_cp_data},
499
500 /* data indication (CP DATA) */
501 {SBIT(GSM411_CPS_MM_ESTABLISHED),
502 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_DATA,
503 "MMSMS-DATA-IND (CP DATA)", gsm411_mmsms_cp_data},
504
505 /* data indication (CP ACK) */
506 {SBIT(GSM411_CPS_WAIT_CP_ACK),
507 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ACK,
508 "MMSMS-DATA-IND (CP ACK)", gsm411_mmsms_cp_ack},
509
510 /* data indication (CP ERROR) */
511 {ALL_STATES,
512 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ERROR,
513 "MMSMS-DATA-IND (CP_ERROR)", gsm411_mmsms_cp_error},
514
515 /* release indication */
516 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
517 GSM411_MMSMS_REL_IND, 0,
518 "MMSMS-REL-IND", gsm411_mmsms_rel_ind},
519
520};
521
522#define SMCDATASLLEN \
523 (sizeof(smcdatastatelist) / sizeof(struct smcdatastate))
524
525/* message from lower layer
526 * WARNING: We must not free msg, since it will be performed by the
527 * lower layer. */
528int gsm411_smc_recv(struct gsm411_smc_inst *inst, int msg_type,
529 struct msgb *msg, int cp_msg_type)
530{
531 int i, rc;
532
533 /* find function for current state and message */
534 for (i = 0; i < SMCDATASLLEN; i++) {
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100535 /* state must match, MM message must match
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200536 * CP msg must match only in case of MMSMS_DATA_IND
537 */
538 if ((msg_type == smcdatastatelist[i].type)
539 && (SBIT(inst->cp_state) & smcdatastatelist[i].states)
540 && (msg_type != GSM411_MMSMS_DATA_IND
541 || cp_msg_type == smcdatastatelist[i].cp_type))
542 break;
543 }
544 if (i == SMCDATASLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100545 LOGP(DLSMS, LOGL_NOTICE,
546 SMC_LOG_STR "message 0x%x/%u unhandled at this "
547 "state %s.\n", inst->id, msg_type, cp_msg_type,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200548 smc_state_names[inst->cp_state]);
549 if (msg_type == GSM411_MMSMS_EST_IND
550 || msg_type == GSM411_MMSMS_DATA_IND) {
551 struct msgb *nmsg;
552
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100553 LOGP(DLSMS, LOGL_NOTICE,
554 SMC_LOG_STR "RX Unimplemented CP "
555 "msg_type: 0x%02x\n", inst->id, msg_type);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200556 /* 5.3.4 enter idle */
557 new_cp_state(inst, GSM411_CPS_IDLE);
558 /* indicate error */
559 gsm411_tx_cp_error(inst,
560 GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
561 /* send error indication to upper layer */
562 nmsg = gsm411_msgb_alloc();
563 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
564 msgb_free(nmsg);
565 /* release MM connection */
566 nmsg = gsm411_msgb_alloc();
567 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg,
568 0);
569 }
570 return 0;
571 }
572
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100573 LOGP(DLSMS, LOGL_INFO,
574 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200575 smcdatastatelist[i].name, smc_state_names[inst->cp_state]);
576
577 rc = smcdatastatelist[i].rout(inst, msg);
578
579 return rc;
580}
Harald Welte96e2a002017-06-12 21:44:18 +0200581
Harald Welted60e17a2018-01-24 16:50:11 +0100582const struct value_string gsm411_cp_state_names[] = {
583 { GSM411_CPS_IDLE, "IDLE" },
584 { GSM411_CPS_MM_CONN_PENDING, "MM_CONN_PENDING" },
585 { GSM411_CPS_WAIT_CP_ACK, "WAIT_CP_ACK" },
586 { GSM411_CPS_MM_ESTABLISHED, "ESTABLISHD" },
587 { 0, NULL }
588};
Harald Welte96e2a002017-06-12 21:44:18 +0200589/*! @} */