blob: f7c536b6cd314a4abc715ad34355169a41de583d [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 *
13 * This program is free software; you can redistribute it and/or modify
Harald Welte388fb032014-10-26 20:42:49 +010014 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
Andreas Eversbergbbf90342011-10-28 03:55:37 +020016 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte388fb032014-10-26 20:42:49 +010021 * GNU General Public License for more details.
Andreas Eversbergbbf90342011-10-28 03:55:37 +020022 *
Harald Welte388fb032014-10-26 20:42:49 +010023 * You should have received a copy of the GNU General Public License
Andreas Eversbergbbf90342011-10-28 03:55:37 +020024 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 */
27
28/* Notes on msg:
29 *
30 * Messages from lower layer are freed by lower layer.
31 *
32 * Messages to upper layer are freed after upper layer call returns, so upper
33 * layer cannot use data after returning. Upper layer must not free the msg.
34 *
35 * This implies: Lower layer messages can be forwarded to upper layer.
36 *
37 * Upper layer messages are freed by lower layer, so they must not be freed
38 * after calling lower layer.
39 *
40 *
41 * Notes on release:
42 *
43 * Whenever the process returns to IDLE, the MM connection is released using
44 * MMSMS-REL-REQ. It is allowed to destroy this process while processing
45 * this message.
46 *
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +010047 * There is an exception, if MMSMS-REL-IND is received from lower layer, the
Andreas Eversbergbbf90342011-10-28 03:55:37 +020048 * process returns to IDLE without sending MMSMS-REL-REQ.
49 *
50 */
51
52#include <string.h>
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010053#include <inttypes.h>
Andreas Eversbergbbf90342011-10-28 03:55:37 +020054#include <errno.h>
55#include <osmocom/core/msgb.h>
56#include <osmocom/core/logging.h>
57#include <osmocom/core/timer.h>
58
59#include <osmocom/gsm/gsm0411_utils.h>
60#include <osmocom/gsm/gsm0411_smc.h>
61#include <osmocom/gsm/protocol/gsm_04_08.h>
62
Harald Welte96e2a002017-06-12 21:44:18 +020063/*! \addtogroup sms
64 * @{
Harald Welte55d724a2017-10-16 18:25:45 +020065 * \file gsm0411_smc.c
Neels Hofmeyr87e45502017-06-20 00:17:59 +020066 * Point-to-Point (PP) Short Message Service (SMS) as per TS 04.11
Harald Welte96e2a002017-06-12 21:44:18 +020067 */
68
Andreas Eversbergbbf90342011-10-28 03:55:37 +020069static void cp_timer_expired(void *data);
70
Sylvain Munautcc90d492011-11-12 23:52:40 +010071#define MAX_SMS_RETRY 2
Andreas Eversbergbbf90342011-10-28 03:55:37 +020072
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010073#define SMC_LOG_STR "SMC(%" PRIu64 ") "
74
Andreas Eversbergbbf90342011-10-28 03:55:37 +020075/* init a new instance */
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010076void gsm411_smc_init(struct gsm411_smc_inst *inst, uint64_t id, int network,
Andreas Eversbergbbf90342011-10-28 03:55:37 +020077 int (*mn_recv) (struct gsm411_smc_inst *inst, int msg_type,
78 struct msgb *msg),
79 int (*mm_send) (struct gsm411_smc_inst *inst, int msg_type,
80 struct msgb *msg, int cp_msg_type))
81{
82 memset(inst, 0, sizeof(*inst));
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010083 inst->id = id;
Andreas Eversbergbbf90342011-10-28 03:55:37 +020084 inst->network = network;
85 inst->cp_max_retr = MAX_SMS_RETRY;
Sylvain Munaut0d9b8ec2011-11-12 23:52:20 +010086 inst->cp_tc1 = GSM411_TMR_TC1A_SEC / (inst->cp_max_retr + 1);
Andreas Eversbergbbf90342011-10-28 03:55:37 +020087 inst->cp_state = GSM411_CPS_IDLE;
88 inst->mn_recv = mn_recv;
89 inst->mm_send = mm_send;
90
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010091 LOGP(DLSMS, LOGL_INFO,
Holger Hans Peter Freyther68f94472012-12-01 12:51:34 +010092 SMC_LOG_STR "instance created for %s\n",
93 inst->id, inst->network ? "network" : "mobile");
Andreas Eversbergbbf90342011-10-28 03:55:37 +020094}
95
96/* clear instance */
97void gsm411_smc_clear(struct gsm411_smc_inst *inst)
98{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010099 LOGP(DLSMS, LOGL_INFO,
100 SMC_LOG_STR "clearing instance\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200101
102 osmo_timer_del(&inst->cp_timer);
103
104 /* free stored msg */
105 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100106 LOGP(DLSMS, LOGL_INFO,
107 SMC_LOG_STR "dropping pending message\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200108 msgb_free(inst->cp_msg);
109 inst->cp_msg = NULL;
110 }
111}
112
113const char *smc_state_names[] = {
114 "IDLE",
115 "MM_CONN_PENDING",
116 "WAIT_CP_ACK",
117 "MM_ESTABLISHED",
118};
119
120const struct value_string gsm411_cp_cause_strs[] = {
121 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
122 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
123 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
124 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
125 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
126 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
127 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
128 "Message incompatible with protocol state" },
129 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
130 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
131 { 0, 0 }
132};
133
134static void new_cp_state(struct gsm411_smc_inst *inst,
135 enum gsm411_cp_state state)
136{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100137 LOGP(DLSMS, LOGL_INFO,
138 SMC_LOG_STR "new CP state %s -> %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200139 smc_state_names[inst->cp_state], smc_state_names[state]);
140 inst->cp_state = state;
141}
142
143static int gsm411_tx_cp_error(struct gsm411_smc_inst *inst, uint8_t cause)
144{
145 struct msgb *nmsg = gsm411_msgb_alloc();
146 uint8_t *causep;
147
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100148 LOGP(DLSMS, LOGL_NOTICE,
149 SMC_LOG_STR "TX CP-ERROR, cause %d (%s)\n", inst->id, cause,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200150 get_value_string(gsm411_cp_cause_strs, cause));
151
152 causep = msgb_put(nmsg, 1);
153 *causep = cause;
154
155 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
156 GSM411_MT_CP_ERROR);
157}
158
Holger Hans Peter Freyther866fc912012-11-13 22:29:35 +0100159/* establish SMC connection */
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200160static int gsm411_mnsms_est_req(struct gsm411_smc_inst *inst, struct msgb *msg)
161{
162 struct msgb *nmsg;
163
164 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100165 LOGP(DLSMS, LOGL_FATAL,
166 SMC_LOG_STR "EST REQ, but we already have an "
167 "cp_msg. This should never happen, please fix!\n",
168 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200169 msgb_free(inst->cp_msg);
170 }
171
172 inst->cp_msg = msg;
173 new_cp_state(inst, GSM411_CPS_MM_CONN_PENDING);
174 /* clear stored release flag */
175 inst->cp_rel = 0;
176 /* send MMSMS_EST_REQ */
177 nmsg = gsm411_msgb_alloc();
178 return inst->mm_send(inst, GSM411_MMSMS_EST_REQ, nmsg, 0);
179}
180
181static int gsm411_mmsms_send_msg(struct gsm411_smc_inst *inst)
182{
183 struct msgb *nmsg;
184
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100185 LOGP(DLSMS, LOGL_INFO,
186 SMC_LOG_STR "send CP data\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200187 /* reset retry counter */
188 if (inst->cp_state != GSM411_CPS_WAIT_CP_ACK)
189 inst->cp_retx = 0;
190 /* 5.2.3.1.2: enter MO-wait for CP-ACK */
191 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
192 new_cp_state(inst, GSM411_CPS_WAIT_CP_ACK);
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200193 osmo_timer_setup(&inst->cp_timer, cp_timer_expired, inst);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200194 /* 5.3.2.1: Set Timer TC1A */
195 osmo_timer_schedule(&inst->cp_timer, inst->cp_tc1, 0);
196 /* clone cp_msg */
197 nmsg = gsm411_msgb_alloc();
198 memcpy(msgb_put(nmsg, inst->cp_msg->len), inst->cp_msg->data,
199 inst->cp_msg->len);
200 /* send MMSMS_DATA_REQ with CP-DATA */
201 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
202 GSM411_MT_CP_DATA);
203}
204
205static int gsm411_mmsms_est_cnf(struct gsm411_smc_inst *inst, struct msgb *msg)
206{
207 if (!inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100208 LOGP(DLSMS, LOGL_FATAL,
209 SMC_LOG_STR "EST CNF, but we have no cp_msg. This "
210 "should never happen, please fix!\n",
211 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200212 return -EINVAL;
213 }
214
215 return gsm411_mmsms_send_msg(inst);
216}
217
218/* SMC TC1* is expired */
219static void cp_timer_expired(void *data)
220{
221 struct gsm411_smc_inst *inst = data;
222 struct msgb *nmsg;
223
224 if (inst->cp_retx == inst->cp_max_retr) {
225
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100226 LOGP(DLSMS, LOGL_INFO,
227 SMC_LOG_STR "TC1* timeout, no more retries.\n",
228 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200229 /* 5.3.2.1: enter idle state */
230 new_cp_state(inst, GSM411_CPS_IDLE);
231 /* indicate error */
232 nmsg = gsm411_msgb_alloc();
233 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
234 msgb_free(nmsg);
235 /* free pending stored msg */
236 if (inst->cp_msg) {
237 msgb_free(inst->cp_msg);
238 inst->cp_msg = NULL;
239 }
240 /* release MM connection */
241 nmsg = gsm411_msgb_alloc();
242 inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
243 return;
244 }
245
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100246 LOGP(DLSMS, LOGL_INFO,
247 SMC_LOG_STR "TC1* timeout, retrying...\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200248 inst->cp_retx++;
249 gsm411_mmsms_est_cnf(inst, NULL);
250}
251
252static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg)
253{
254 /* free stored msg */
255 if (inst->cp_msg) {
256 msgb_free(inst->cp_msg);
257 inst->cp_msg = NULL;
258 }
259
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100260 LOGP(DLSMS, LOGL_INFO,
261 SMC_LOG_STR "received CP-ACK\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200262 /* 5.3.2.1 enter MM Connection established */
263 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
264 /* 5.3.2.1: Reset Timer TC1* */
265 osmo_timer_del(&inst->cp_timer);
266
267 /* pending release? */
268 if (inst->cp_rel) {
269 struct msgb *nmsg;
270
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100271 LOGP(DLSMS, LOGL_INFO,
272 SMC_LOG_STR "we have pending release.\n",
273 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200274 new_cp_state(inst, GSM411_CPS_IDLE);
275 /* release MM connection */
276 nmsg = gsm411_msgb_alloc();
277 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
278 }
279
280 return 0;
281}
282
283static int gsm411_mmsms_cp_data(struct gsm411_smc_inst *inst, struct msgb *msg)
284{
285 struct msgb *nmsg;
286 int mt = GSM411_MNSMS_DATA_IND;
287
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100288 LOGP(DLSMS, LOGL_INFO,
289 SMC_LOG_STR "received CP-DATA\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200290 /* 5.3.1 enter MM Connection established (if idle) */
291 if (inst->cp_state == GSM411_CPS_IDLE) {
292 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
293 mt = GSM411_MNSMS_EST_IND;
294 /* clear stored release flag */
295 inst->cp_rel = 0;
296 }
297 /* send MMSMS_DATA_REQ (CP ACK) */
298 nmsg = gsm411_msgb_alloc();
299 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, GSM411_MT_CP_ACK);
300 /* indicate data */
301 inst->mn_recv(inst, mt, msg);
302
303 return 0;
304}
305
306/* send CP DATA */
307static int gsm411_mnsms_data_req(struct gsm411_smc_inst *inst, struct msgb *msg)
308{
309 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100310 LOGP(DLSMS, LOGL_FATAL,
311 SMC_LOG_STR "DATA REQ, but we already have an "
312 "cp_msg. This should never happen, please fix!\n",
313 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200314 msgb_free(inst->cp_msg);
315 }
316
317 /* store and send */
318 inst->cp_msg = msg;
319 return gsm411_mmsms_send_msg(inst);
320}
321
322/* release SMC connection */
323static int gsm411_mnsms_rel_req(struct gsm411_smc_inst *inst, struct msgb *msg)
324{
325 struct msgb *nmsg;
326
327 msgb_free(msg);
328
329 /* discard silently */
330 if (inst->cp_state == GSM411_CPS_IDLE)
331 return 0;
332
333 /* store release, until established or released */
334 if (inst->cp_state != GSM411_CPS_MM_ESTABLISHED) {
Holger Hans Peter Freyther09161592012-11-11 10:09:24 +0100335 LOGP(DLSMS, LOGL_NOTICE,
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100336 SMC_LOG_STR "cannot release yet current state: %s\n",
337 inst->id, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200338 inst->cp_rel = 1;
339 return 0;
340 }
341
342 /* free stored msg */
343 if (inst->cp_msg) {
344 msgb_free(inst->cp_msg);
345 inst->cp_msg = NULL;
346 }
347
348 new_cp_state(inst, GSM411_CPS_IDLE);
349 /* release MM connection */
350 nmsg = gsm411_msgb_alloc();
351 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
352}
353
354static int gsm411_mmsms_cp_error(struct gsm411_smc_inst *inst, struct msgb *msg)
355{
356 struct msgb *nmsg;
357
358 /* free stored msg */
359 if (inst->cp_msg) {
360 msgb_free(inst->cp_msg);
361 inst->cp_msg = NULL;
362 }
363
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100364 LOGP(DLSMS, LOGL_INFO,
365 SMC_LOG_STR "received CP-ERROR\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200366 /* 5.3.4 enter idle */
367 new_cp_state(inst, GSM411_CPS_IDLE);
368 /* indicate error */
369 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, msg);
370 /* release MM connection */
371 nmsg = gsm411_msgb_alloc();
372 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
373}
374
375static int gsm411_mmsms_rel_ind(struct gsm411_smc_inst *inst, struct msgb *msg)
376{
377 struct msgb *nmsg;
378
379 /* free stored msg */
380 if (inst->cp_msg) {
381 msgb_free(inst->cp_msg);
382 inst->cp_msg = NULL;
383 }
384
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100385 LOGP(DLSMS, LOGL_INFO,
386 SMC_LOG_STR "MM layer is released\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200387 /* 5.3.4 enter idle */
388 new_cp_state(inst, GSM411_CPS_IDLE);
389 /* indicate error */
390 nmsg = gsm411_msgb_alloc();
391 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
392 msgb_free(nmsg);
393
394 return 0;
395}
396
397/* abort SMC connection */
398static int gsm411_mnsms_abort_req(struct gsm411_smc_inst *inst,
399 struct msgb *msg)
400{
401 struct msgb *nmsg;
402
403 /* free stored msg */
404 if (inst->cp_msg) {
405 msgb_free(inst->cp_msg);
406 inst->cp_msg = NULL;
407 }
408
409 /* 5.3.4 go idle */
410 new_cp_state(inst, GSM411_CPS_IDLE);
411 /* send MMSMS_DATA_REQ with CP-ERROR */
412 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, msg, GSM411_MT_CP_ERROR);
413 /* release MM connection */
414 nmsg = gsm411_msgb_alloc();
415 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
416}
417
418/* statefull handling for MNSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100419static const struct smcdownstate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200420 uint32_t states;
421 int type;
422 const char *name;
423 int (*rout) (struct gsm411_smc_inst *inst,
424 struct msgb *msg);
425} smcdownstatelist[] = {
426 /* establish request */
427 {SBIT(GSM411_CPS_IDLE),
428 GSM411_MNSMS_EST_REQ,
429 "MNSMS-EST-REQ", gsm411_mnsms_est_req},
430
431 /* release request */
432 {ALL_STATES,
433 GSM411_MNSMS_REL_REQ,
434 "MNSMS-REL-REQ", gsm411_mnsms_rel_req},
435
436 /* data request */
437 {SBIT(GSM411_CPS_MM_ESTABLISHED),
438 GSM411_MNSMS_DATA_REQ,
439 "MNSMS-DATA-REQ", gsm411_mnsms_data_req},
440
441 /* abort request */
442 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
443 GSM411_MNSMS_ABORT_REQ,
444 "MNSMS-ABORT-REQ", gsm411_mnsms_abort_req},
445};
446
447#define SMCDOWNSLLEN \
448 (sizeof(smcdownstatelist) / sizeof(struct smcdownstate))
449
450/* message from upper layer */
451int gsm411_smc_send(struct gsm411_smc_inst *inst, int msg_type,
452 struct msgb *msg)
453{
454 int i, rc;
455
456 /* find function for current state and message */
457 for (i = 0; i < SMCDOWNSLLEN; i++) {
458 if ((msg_type == smcdownstatelist[i].type)
459 && (SBIT(inst->cp_state) & smcdownstatelist[i].states))
460 break;
461 }
462 if (i == SMCDOWNSLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100463 LOGP(DLSMS, LOGL_NOTICE,
464 SMC_LOG_STR "message %u unhandled at this state %s.\n",
465 inst->id, msg_type, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200466 msgb_free(msg);
467 return 0;
468 }
469
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100470 LOGP(DLSMS, LOGL_INFO,
471 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200472 smcdownstatelist[i].name, smc_state_names[inst->cp_state]);
473
474 rc = smcdownstatelist[i].rout(inst, msg);
475
476 return rc;
477}
478
479/* statefull handling for MMSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100480static const struct smcdatastate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200481 uint32_t states;
482 int type, cp_type;
483 const char *name;
484 int (*rout) (struct gsm411_smc_inst *inst,
485 struct msgb *msg);
486} smcdatastatelist[] = {
487 /* establish confirm */
488 {SBIT(GSM411_CPS_MM_CONN_PENDING),
489 GSM411_MMSMS_EST_CNF, 0,
490 "MMSMS-EST-CNF", gsm411_mmsms_est_cnf},
491
492 /* establish indication (CP DATA) */
493 {SBIT(GSM411_CPS_IDLE),
494 GSM411_MMSMS_EST_IND, GSM411_MT_CP_DATA,
495 "MMSMS-EST-IND (CP DATA)", gsm411_mmsms_cp_data},
496
497 /* data indication (CP DATA) */
498 {SBIT(GSM411_CPS_MM_ESTABLISHED),
499 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_DATA,
500 "MMSMS-DATA-IND (CP DATA)", gsm411_mmsms_cp_data},
501
502 /* data indication (CP ACK) */
503 {SBIT(GSM411_CPS_WAIT_CP_ACK),
504 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ACK,
505 "MMSMS-DATA-IND (CP ACK)", gsm411_mmsms_cp_ack},
506
507 /* data indication (CP ERROR) */
508 {ALL_STATES,
509 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ERROR,
510 "MMSMS-DATA-IND (CP_ERROR)", gsm411_mmsms_cp_error},
511
512 /* release indication */
513 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
514 GSM411_MMSMS_REL_IND, 0,
515 "MMSMS-REL-IND", gsm411_mmsms_rel_ind},
516
517};
518
519#define SMCDATASLLEN \
520 (sizeof(smcdatastatelist) / sizeof(struct smcdatastate))
521
522/* message from lower layer
523 * WARNING: We must not free msg, since it will be performed by the
524 * lower layer. */
525int gsm411_smc_recv(struct gsm411_smc_inst *inst, int msg_type,
526 struct msgb *msg, int cp_msg_type)
527{
528 int i, rc;
529
530 /* find function for current state and message */
531 for (i = 0; i < SMCDATASLLEN; i++) {
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100532 /* state must match, MM message must match
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200533 * CP msg must match only in case of MMSMS_DATA_IND
534 */
535 if ((msg_type == smcdatastatelist[i].type)
536 && (SBIT(inst->cp_state) & smcdatastatelist[i].states)
537 && (msg_type != GSM411_MMSMS_DATA_IND
538 || cp_msg_type == smcdatastatelist[i].cp_type))
539 break;
540 }
541 if (i == SMCDATASLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100542 LOGP(DLSMS, LOGL_NOTICE,
543 SMC_LOG_STR "message 0x%x/%u unhandled at this "
544 "state %s.\n", inst->id, msg_type, cp_msg_type,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200545 smc_state_names[inst->cp_state]);
546 if (msg_type == GSM411_MMSMS_EST_IND
547 || msg_type == GSM411_MMSMS_DATA_IND) {
548 struct msgb *nmsg;
549
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100550 LOGP(DLSMS, LOGL_NOTICE,
551 SMC_LOG_STR "RX Unimplemented CP "
552 "msg_type: 0x%02x\n", inst->id, msg_type);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200553 /* 5.3.4 enter idle */
554 new_cp_state(inst, GSM411_CPS_IDLE);
555 /* indicate error */
556 gsm411_tx_cp_error(inst,
557 GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
558 /* send error indication to upper layer */
559 nmsg = gsm411_msgb_alloc();
560 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
561 msgb_free(nmsg);
562 /* release MM connection */
563 nmsg = gsm411_msgb_alloc();
564 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg,
565 0);
566 }
567 return 0;
568 }
569
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100570 LOGP(DLSMS, LOGL_INFO,
571 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200572 smcdatastatelist[i].name, smc_state_names[inst->cp_state]);
573
574 rc = smcdatastatelist[i].rout(inst, msg);
575
576 return rc;
577}
Harald Welte96e2a002017-06-12 21:44:18 +0200578
579/*! @} */