blob: 50d0f3ec1f336b363de9362c06580fc89d2ecc91 [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
54#include <string.h>
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010055#include <inttypes.h>
Andreas Eversbergbbf90342011-10-28 03:55:37 +020056#include <errno.h>
57#include <osmocom/core/msgb.h>
58#include <osmocom/core/logging.h>
59#include <osmocom/core/timer.h>
60
61#include <osmocom/gsm/gsm0411_utils.h>
62#include <osmocom/gsm/gsm0411_smc.h>
63#include <osmocom/gsm/protocol/gsm_04_08.h>
64
Harald Welte96e2a002017-06-12 21:44:18 +020065/*! \addtogroup sms
66 * @{
Harald Welte55d724a2017-10-16 18:25:45 +020067 * \file gsm0411_smc.c
Neels Hofmeyr87e45502017-06-20 00:17:59 +020068 * Point-to-Point (PP) Short Message Service (SMS) as per TS 04.11
Harald Welte96e2a002017-06-12 21:44:18 +020069 */
70
Andreas Eversbergbbf90342011-10-28 03:55:37 +020071static void cp_timer_expired(void *data);
72
Sylvain Munautcc90d492011-11-12 23:52:40 +010073#define MAX_SMS_RETRY 2
Andreas Eversbergbbf90342011-10-28 03:55:37 +020074
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010075#define SMC_LOG_STR "SMC(%" PRIu64 ") "
76
Andreas Eversbergbbf90342011-10-28 03:55:37 +020077/* init a new instance */
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010078void gsm411_smc_init(struct gsm411_smc_inst *inst, uint64_t id, int network,
Andreas Eversbergbbf90342011-10-28 03:55:37 +020079 int (*mn_recv) (struct gsm411_smc_inst *inst, int msg_type,
80 struct msgb *msg),
81 int (*mm_send) (struct gsm411_smc_inst *inst, int msg_type,
82 struct msgb *msg, int cp_msg_type))
83{
84 memset(inst, 0, sizeof(*inst));
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010085 inst->id = id;
Andreas Eversbergbbf90342011-10-28 03:55:37 +020086 inst->network = network;
87 inst->cp_max_retr = MAX_SMS_RETRY;
Sylvain Munaut0d9b8ec2011-11-12 23:52:20 +010088 inst->cp_tc1 = GSM411_TMR_TC1A_SEC / (inst->cp_max_retr + 1);
Andreas Eversbergbbf90342011-10-28 03:55:37 +020089 inst->cp_state = GSM411_CPS_IDLE;
90 inst->mn_recv = mn_recv;
91 inst->mm_send = mm_send;
92
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010093 LOGP(DLSMS, LOGL_INFO,
Holger Hans Peter Freyther68f94472012-12-01 12:51:34 +010094 SMC_LOG_STR "instance created for %s\n",
95 inst->id, inst->network ? "network" : "mobile");
Andreas Eversbergbbf90342011-10-28 03:55:37 +020096}
97
98/* clear instance */
99void gsm411_smc_clear(struct gsm411_smc_inst *inst)
100{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100101 LOGP(DLSMS, LOGL_INFO,
102 SMC_LOG_STR "clearing instance\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200103
104 osmo_timer_del(&inst->cp_timer);
105
106 /* free stored msg */
107 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100108 LOGP(DLSMS, LOGL_INFO,
109 SMC_LOG_STR "dropping pending message\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200110 msgb_free(inst->cp_msg);
111 inst->cp_msg = NULL;
112 }
113}
114
115const char *smc_state_names[] = {
116 "IDLE",
117 "MM_CONN_PENDING",
118 "WAIT_CP_ACK",
119 "MM_ESTABLISHED",
120};
121
122const struct value_string gsm411_cp_cause_strs[] = {
123 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
124 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
125 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
126 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
127 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
128 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
129 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
130 "Message incompatible with protocol state" },
131 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
132 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
133 { 0, 0 }
134};
135
136static void new_cp_state(struct gsm411_smc_inst *inst,
137 enum gsm411_cp_state state)
138{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100139 LOGP(DLSMS, LOGL_INFO,
140 SMC_LOG_STR "new CP state %s -> %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200141 smc_state_names[inst->cp_state], smc_state_names[state]);
142 inst->cp_state = state;
143}
144
145static int gsm411_tx_cp_error(struct gsm411_smc_inst *inst, uint8_t cause)
146{
147 struct msgb *nmsg = gsm411_msgb_alloc();
148 uint8_t *causep;
149
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100150 LOGP(DLSMS, LOGL_NOTICE,
151 SMC_LOG_STR "TX CP-ERROR, cause %d (%s)\n", inst->id, cause,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200152 get_value_string(gsm411_cp_cause_strs, cause));
153
154 causep = msgb_put(nmsg, 1);
155 *causep = cause;
156
157 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
158 GSM411_MT_CP_ERROR);
159}
160
Holger Hans Peter Freyther866fc912012-11-13 22:29:35 +0100161/* establish SMC connection */
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200162static int gsm411_mnsms_est_req(struct gsm411_smc_inst *inst, struct msgb *msg)
163{
164 struct msgb *nmsg;
165
166 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100167 LOGP(DLSMS, LOGL_FATAL,
168 SMC_LOG_STR "EST REQ, but we already have an "
169 "cp_msg. This should never happen, please fix!\n",
170 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200171 msgb_free(inst->cp_msg);
172 }
173
174 inst->cp_msg = msg;
175 new_cp_state(inst, GSM411_CPS_MM_CONN_PENDING);
176 /* clear stored release flag */
177 inst->cp_rel = 0;
178 /* send MMSMS_EST_REQ */
179 nmsg = gsm411_msgb_alloc();
180 return inst->mm_send(inst, GSM411_MMSMS_EST_REQ, nmsg, 0);
181}
182
183static int gsm411_mmsms_send_msg(struct gsm411_smc_inst *inst)
184{
185 struct msgb *nmsg;
186
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100187 LOGP(DLSMS, LOGL_INFO,
188 SMC_LOG_STR "send CP data\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200189 /* reset retry counter */
190 if (inst->cp_state != GSM411_CPS_WAIT_CP_ACK)
191 inst->cp_retx = 0;
192 /* 5.2.3.1.2: enter MO-wait for CP-ACK */
193 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
194 new_cp_state(inst, GSM411_CPS_WAIT_CP_ACK);
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200195 osmo_timer_setup(&inst->cp_timer, cp_timer_expired, inst);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200196 /* 5.3.2.1: Set Timer TC1A */
197 osmo_timer_schedule(&inst->cp_timer, inst->cp_tc1, 0);
198 /* clone cp_msg */
199 nmsg = gsm411_msgb_alloc();
200 memcpy(msgb_put(nmsg, inst->cp_msg->len), inst->cp_msg->data,
201 inst->cp_msg->len);
202 /* send MMSMS_DATA_REQ with CP-DATA */
203 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
204 GSM411_MT_CP_DATA);
205}
206
207static int gsm411_mmsms_est_cnf(struct gsm411_smc_inst *inst, struct msgb *msg)
208{
209 if (!inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100210 LOGP(DLSMS, LOGL_FATAL,
211 SMC_LOG_STR "EST CNF, but we have no cp_msg. This "
212 "should never happen, please fix!\n",
213 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200214 return -EINVAL;
215 }
216
217 return gsm411_mmsms_send_msg(inst);
218}
219
220/* SMC TC1* is expired */
221static void cp_timer_expired(void *data)
222{
223 struct gsm411_smc_inst *inst = data;
224 struct msgb *nmsg;
225
226 if (inst->cp_retx == inst->cp_max_retr) {
227
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100228 LOGP(DLSMS, LOGL_INFO,
229 SMC_LOG_STR "TC1* timeout, no more retries.\n",
230 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200231 /* 5.3.2.1: enter idle state */
232 new_cp_state(inst, GSM411_CPS_IDLE);
233 /* indicate error */
234 nmsg = gsm411_msgb_alloc();
235 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
236 msgb_free(nmsg);
237 /* free pending stored msg */
238 if (inst->cp_msg) {
239 msgb_free(inst->cp_msg);
240 inst->cp_msg = NULL;
241 }
242 /* release MM connection */
243 nmsg = gsm411_msgb_alloc();
244 inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
245 return;
246 }
247
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100248 LOGP(DLSMS, LOGL_INFO,
249 SMC_LOG_STR "TC1* timeout, retrying...\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200250 inst->cp_retx++;
251 gsm411_mmsms_est_cnf(inst, NULL);
252}
253
254static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg)
255{
256 /* free stored msg */
257 if (inst->cp_msg) {
258 msgb_free(inst->cp_msg);
259 inst->cp_msg = NULL;
260 }
261
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100262 LOGP(DLSMS, LOGL_INFO,
263 SMC_LOG_STR "received CP-ACK\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200264 /* 5.3.2.1 enter MM Connection established */
265 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
266 /* 5.3.2.1: Reset Timer TC1* */
267 osmo_timer_del(&inst->cp_timer);
268
269 /* pending release? */
270 if (inst->cp_rel) {
271 struct msgb *nmsg;
272
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100273 LOGP(DLSMS, LOGL_INFO,
274 SMC_LOG_STR "we have pending release.\n",
275 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200276 new_cp_state(inst, GSM411_CPS_IDLE);
277 /* release MM connection */
278 nmsg = gsm411_msgb_alloc();
279 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
280 }
281
282 return 0;
283}
284
285static int gsm411_mmsms_cp_data(struct gsm411_smc_inst *inst, struct msgb *msg)
286{
287 struct msgb *nmsg;
288 int mt = GSM411_MNSMS_DATA_IND;
289
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100290 LOGP(DLSMS, LOGL_INFO,
291 SMC_LOG_STR "received CP-DATA\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200292 /* 5.3.1 enter MM Connection established (if idle) */
293 if (inst->cp_state == GSM411_CPS_IDLE) {
294 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
295 mt = GSM411_MNSMS_EST_IND;
296 /* clear stored release flag */
297 inst->cp_rel = 0;
298 }
299 /* send MMSMS_DATA_REQ (CP ACK) */
300 nmsg = gsm411_msgb_alloc();
301 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, GSM411_MT_CP_ACK);
302 /* indicate data */
303 inst->mn_recv(inst, mt, msg);
304
305 return 0;
306}
307
308/* send CP DATA */
309static int gsm411_mnsms_data_req(struct gsm411_smc_inst *inst, struct msgb *msg)
310{
311 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100312 LOGP(DLSMS, LOGL_FATAL,
313 SMC_LOG_STR "DATA REQ, but we already have an "
314 "cp_msg. This should never happen, please fix!\n",
315 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200316 msgb_free(inst->cp_msg);
317 }
318
319 /* store and send */
320 inst->cp_msg = msg;
321 return gsm411_mmsms_send_msg(inst);
322}
323
324/* release SMC connection */
325static int gsm411_mnsms_rel_req(struct gsm411_smc_inst *inst, struct msgb *msg)
326{
327 struct msgb *nmsg;
328
329 msgb_free(msg);
330
331 /* discard silently */
332 if (inst->cp_state == GSM411_CPS_IDLE)
333 return 0;
334
335 /* store release, until established or released */
336 if (inst->cp_state != GSM411_CPS_MM_ESTABLISHED) {
Holger Hans Peter Freyther09161592012-11-11 10:09:24 +0100337 LOGP(DLSMS, LOGL_NOTICE,
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100338 SMC_LOG_STR "cannot release yet current state: %s\n",
339 inst->id, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200340 inst->cp_rel = 1;
341 return 0;
342 }
343
344 /* free stored msg */
345 if (inst->cp_msg) {
346 msgb_free(inst->cp_msg);
347 inst->cp_msg = NULL;
348 }
349
350 new_cp_state(inst, GSM411_CPS_IDLE);
351 /* release MM connection */
352 nmsg = gsm411_msgb_alloc();
353 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
354}
355
356static int gsm411_mmsms_cp_error(struct gsm411_smc_inst *inst, struct msgb *msg)
357{
358 struct msgb *nmsg;
359
360 /* free stored msg */
361 if (inst->cp_msg) {
362 msgb_free(inst->cp_msg);
363 inst->cp_msg = NULL;
364 }
365
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100366 LOGP(DLSMS, LOGL_INFO,
367 SMC_LOG_STR "received CP-ERROR\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200368 /* 5.3.4 enter idle */
369 new_cp_state(inst, GSM411_CPS_IDLE);
370 /* indicate error */
371 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, msg);
372 /* release MM connection */
373 nmsg = gsm411_msgb_alloc();
374 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
375}
376
377static int gsm411_mmsms_rel_ind(struct gsm411_smc_inst *inst, struct msgb *msg)
378{
379 struct msgb *nmsg;
380
381 /* free stored msg */
382 if (inst->cp_msg) {
383 msgb_free(inst->cp_msg);
384 inst->cp_msg = NULL;
385 }
386
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100387 LOGP(DLSMS, LOGL_INFO,
388 SMC_LOG_STR "MM layer is released\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200389 /* 5.3.4 enter idle */
390 new_cp_state(inst, GSM411_CPS_IDLE);
391 /* indicate error */
392 nmsg = gsm411_msgb_alloc();
393 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
394 msgb_free(nmsg);
395
396 return 0;
397}
398
399/* abort SMC connection */
400static int gsm411_mnsms_abort_req(struct gsm411_smc_inst *inst,
401 struct msgb *msg)
402{
403 struct msgb *nmsg;
404
405 /* free stored msg */
406 if (inst->cp_msg) {
407 msgb_free(inst->cp_msg);
408 inst->cp_msg = NULL;
409 }
410
411 /* 5.3.4 go idle */
412 new_cp_state(inst, GSM411_CPS_IDLE);
413 /* send MMSMS_DATA_REQ with CP-ERROR */
414 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, msg, GSM411_MT_CP_ERROR);
415 /* release MM connection */
416 nmsg = gsm411_msgb_alloc();
417 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
418}
419
420/* statefull handling for MNSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100421static const struct smcdownstate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200422 uint32_t states;
423 int type;
424 const char *name;
425 int (*rout) (struct gsm411_smc_inst *inst,
426 struct msgb *msg);
427} smcdownstatelist[] = {
428 /* establish request */
429 {SBIT(GSM411_CPS_IDLE),
430 GSM411_MNSMS_EST_REQ,
431 "MNSMS-EST-REQ", gsm411_mnsms_est_req},
432
433 /* release request */
434 {ALL_STATES,
435 GSM411_MNSMS_REL_REQ,
436 "MNSMS-REL-REQ", gsm411_mnsms_rel_req},
437
438 /* data request */
439 {SBIT(GSM411_CPS_MM_ESTABLISHED),
440 GSM411_MNSMS_DATA_REQ,
441 "MNSMS-DATA-REQ", gsm411_mnsms_data_req},
442
443 /* abort request */
444 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
445 GSM411_MNSMS_ABORT_REQ,
446 "MNSMS-ABORT-REQ", gsm411_mnsms_abort_req},
447};
448
449#define SMCDOWNSLLEN \
450 (sizeof(smcdownstatelist) / sizeof(struct smcdownstate))
451
452/* message from upper layer */
453int gsm411_smc_send(struct gsm411_smc_inst *inst, int msg_type,
454 struct msgb *msg)
455{
456 int i, rc;
457
458 /* find function for current state and message */
459 for (i = 0; i < SMCDOWNSLLEN; i++) {
460 if ((msg_type == smcdownstatelist[i].type)
461 && (SBIT(inst->cp_state) & smcdownstatelist[i].states))
462 break;
463 }
464 if (i == SMCDOWNSLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100465 LOGP(DLSMS, LOGL_NOTICE,
466 SMC_LOG_STR "message %u unhandled at this state %s.\n",
467 inst->id, msg_type, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200468 msgb_free(msg);
469 return 0;
470 }
471
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100472 LOGP(DLSMS, LOGL_INFO,
473 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200474 smcdownstatelist[i].name, smc_state_names[inst->cp_state]);
475
476 rc = smcdownstatelist[i].rout(inst, msg);
477
478 return rc;
479}
480
481/* statefull handling for MMSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100482static const struct smcdatastate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200483 uint32_t states;
484 int type, cp_type;
485 const char *name;
486 int (*rout) (struct gsm411_smc_inst *inst,
487 struct msgb *msg);
488} smcdatastatelist[] = {
489 /* establish confirm */
490 {SBIT(GSM411_CPS_MM_CONN_PENDING),
491 GSM411_MMSMS_EST_CNF, 0,
492 "MMSMS-EST-CNF", gsm411_mmsms_est_cnf},
493
494 /* establish indication (CP DATA) */
495 {SBIT(GSM411_CPS_IDLE),
496 GSM411_MMSMS_EST_IND, GSM411_MT_CP_DATA,
497 "MMSMS-EST-IND (CP DATA)", gsm411_mmsms_cp_data},
498
499 /* data indication (CP DATA) */
500 {SBIT(GSM411_CPS_MM_ESTABLISHED),
501 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_DATA,
502 "MMSMS-DATA-IND (CP DATA)", gsm411_mmsms_cp_data},
503
504 /* data indication (CP ACK) */
505 {SBIT(GSM411_CPS_WAIT_CP_ACK),
506 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ACK,
507 "MMSMS-DATA-IND (CP ACK)", gsm411_mmsms_cp_ack},
508
509 /* data indication (CP ERROR) */
510 {ALL_STATES,
511 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ERROR,
512 "MMSMS-DATA-IND (CP_ERROR)", gsm411_mmsms_cp_error},
513
514 /* release indication */
515 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
516 GSM411_MMSMS_REL_IND, 0,
517 "MMSMS-REL-IND", gsm411_mmsms_rel_ind},
518
519};
520
521#define SMCDATASLLEN \
522 (sizeof(smcdatastatelist) / sizeof(struct smcdatastate))
523
524/* message from lower layer
525 * WARNING: We must not free msg, since it will be performed by the
526 * lower layer. */
527int gsm411_smc_recv(struct gsm411_smc_inst *inst, int msg_type,
528 struct msgb *msg, int cp_msg_type)
529{
530 int i, rc;
531
532 /* find function for current state and message */
533 for (i = 0; i < SMCDATASLLEN; i++) {
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100534 /* state must match, MM message must match
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200535 * CP msg must match only in case of MMSMS_DATA_IND
536 */
537 if ((msg_type == smcdatastatelist[i].type)
538 && (SBIT(inst->cp_state) & smcdatastatelist[i].states)
539 && (msg_type != GSM411_MMSMS_DATA_IND
540 || cp_msg_type == smcdatastatelist[i].cp_type))
541 break;
542 }
543 if (i == SMCDATASLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100544 LOGP(DLSMS, LOGL_NOTICE,
545 SMC_LOG_STR "message 0x%x/%u unhandled at this "
546 "state %s.\n", inst->id, msg_type, cp_msg_type,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200547 smc_state_names[inst->cp_state]);
548 if (msg_type == GSM411_MMSMS_EST_IND
549 || msg_type == GSM411_MMSMS_DATA_IND) {
550 struct msgb *nmsg;
551
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100552 LOGP(DLSMS, LOGL_NOTICE,
553 SMC_LOG_STR "RX Unimplemented CP "
554 "msg_type: 0x%02x\n", inst->id, msg_type);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200555 /* 5.3.4 enter idle */
556 new_cp_state(inst, GSM411_CPS_IDLE);
557 /* indicate error */
558 gsm411_tx_cp_error(inst,
559 GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
560 /* send error indication to upper layer */
561 nmsg = gsm411_msgb_alloc();
562 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
563 msgb_free(nmsg);
564 /* release MM connection */
565 nmsg = gsm411_msgb_alloc();
566 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg,
567 0);
568 }
569 return 0;
570 }
571
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100572 LOGP(DLSMS, LOGL_INFO,
573 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200574 smcdatastatelist[i].name, smc_state_names[inst->cp_state]);
575
576 rc = smcdatastatelist[i].rout(inst, msg);
577
578 return rc;
579}
Harald Welte96e2a002017-06-12 21:44:18 +0200580
Harald Welted60e17a2018-01-24 16:50:11 +0100581const struct value_string gsm411_cp_state_names[] = {
582 { GSM411_CPS_IDLE, "IDLE" },
583 { GSM411_CPS_MM_CONN_PENDING, "MM_CONN_PENDING" },
584 { GSM411_CPS_WAIT_CP_ACK, "WAIT_CP_ACK" },
585 { GSM411_CPS_MM_ESTABLISHED, "ESTABLISHD" },
586 { 0, NULL }
587};
Harald Welte96e2a002017-06-12 21:44:18 +0200588/*! @} */