blob: dab83ebd2b472dc63e2d7c710365024c2d7d22c7 [file] [log] [blame]
Andreas Eversbergbbf90342011-10-28 03:55:37 +02001/* Point-to-Point (PP) Short Message Service (SMS)
2 * Support on Mobile Radio Interface
3 * 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>
6 * (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 * @{
Neels Hofmeyr87e45502017-06-20 00:17:59 +020065 * Point-to-Point (PP) Short Message Service (SMS) as per TS 04.11
Harald Welte96e2a002017-06-12 21:44:18 +020066 */
67
Andreas Eversbergbbf90342011-10-28 03:55:37 +020068static void cp_timer_expired(void *data);
69
Sylvain Munautcc90d492011-11-12 23:52:40 +010070#define MAX_SMS_RETRY 2
Andreas Eversbergbbf90342011-10-28 03:55:37 +020071
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010072#define SMC_LOG_STR "SMC(%" PRIu64 ") "
73
Andreas Eversbergbbf90342011-10-28 03:55:37 +020074/* init a new instance */
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010075void gsm411_smc_init(struct gsm411_smc_inst *inst, uint64_t id, int network,
Andreas Eversbergbbf90342011-10-28 03:55:37 +020076 int (*mn_recv) (struct gsm411_smc_inst *inst, int msg_type,
77 struct msgb *msg),
78 int (*mm_send) (struct gsm411_smc_inst *inst, int msg_type,
79 struct msgb *msg, int cp_msg_type))
80{
81 memset(inst, 0, sizeof(*inst));
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010082 inst->id = id;
Andreas Eversbergbbf90342011-10-28 03:55:37 +020083 inst->network = network;
84 inst->cp_max_retr = MAX_SMS_RETRY;
Sylvain Munaut0d9b8ec2011-11-12 23:52:20 +010085 inst->cp_tc1 = GSM411_TMR_TC1A_SEC / (inst->cp_max_retr + 1);
Andreas Eversbergbbf90342011-10-28 03:55:37 +020086 inst->cp_state = GSM411_CPS_IDLE;
87 inst->mn_recv = mn_recv;
88 inst->mm_send = mm_send;
89
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010090 LOGP(DLSMS, LOGL_INFO,
Holger Hans Peter Freyther68f94472012-12-01 12:51:34 +010091 SMC_LOG_STR "instance created for %s\n",
92 inst->id, inst->network ? "network" : "mobile");
Andreas Eversbergbbf90342011-10-28 03:55:37 +020093}
94
95/* clear instance */
96void gsm411_smc_clear(struct gsm411_smc_inst *inst)
97{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010098 LOGP(DLSMS, LOGL_INFO,
99 SMC_LOG_STR "clearing instance\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200100
101 osmo_timer_del(&inst->cp_timer);
102
103 /* free stored msg */
104 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100105 LOGP(DLSMS, LOGL_INFO,
106 SMC_LOG_STR "dropping pending message\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200107 msgb_free(inst->cp_msg);
108 inst->cp_msg = NULL;
109 }
110}
111
112const char *smc_state_names[] = {
113 "IDLE",
114 "MM_CONN_PENDING",
115 "WAIT_CP_ACK",
116 "MM_ESTABLISHED",
117};
118
119const struct value_string gsm411_cp_cause_strs[] = {
120 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
121 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
122 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
123 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
124 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
125 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
126 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
127 "Message incompatible with protocol state" },
128 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
129 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
130 { 0, 0 }
131};
132
133static void new_cp_state(struct gsm411_smc_inst *inst,
134 enum gsm411_cp_state state)
135{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100136 LOGP(DLSMS, LOGL_INFO,
137 SMC_LOG_STR "new CP state %s -> %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200138 smc_state_names[inst->cp_state], smc_state_names[state]);
139 inst->cp_state = state;
140}
141
142static int gsm411_tx_cp_error(struct gsm411_smc_inst *inst, uint8_t cause)
143{
144 struct msgb *nmsg = gsm411_msgb_alloc();
145 uint8_t *causep;
146
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100147 LOGP(DLSMS, LOGL_NOTICE,
148 SMC_LOG_STR "TX CP-ERROR, cause %d (%s)\n", inst->id, cause,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200149 get_value_string(gsm411_cp_cause_strs, cause));
150
151 causep = msgb_put(nmsg, 1);
152 *causep = cause;
153
154 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
155 GSM411_MT_CP_ERROR);
156}
157
Holger Hans Peter Freyther866fc912012-11-13 22:29:35 +0100158/* establish SMC connection */
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200159static int gsm411_mnsms_est_req(struct gsm411_smc_inst *inst, struct msgb *msg)
160{
161 struct msgb *nmsg;
162
163 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100164 LOGP(DLSMS, LOGL_FATAL,
165 SMC_LOG_STR "EST REQ, but we already have an "
166 "cp_msg. This should never happen, please fix!\n",
167 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200168 msgb_free(inst->cp_msg);
169 }
170
171 inst->cp_msg = msg;
172 new_cp_state(inst, GSM411_CPS_MM_CONN_PENDING);
173 /* clear stored release flag */
174 inst->cp_rel = 0;
175 /* send MMSMS_EST_REQ */
176 nmsg = gsm411_msgb_alloc();
177 return inst->mm_send(inst, GSM411_MMSMS_EST_REQ, nmsg, 0);
178}
179
180static int gsm411_mmsms_send_msg(struct gsm411_smc_inst *inst)
181{
182 struct msgb *nmsg;
183
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100184 LOGP(DLSMS, LOGL_INFO,
185 SMC_LOG_STR "send CP data\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200186 /* reset retry counter */
187 if (inst->cp_state != GSM411_CPS_WAIT_CP_ACK)
188 inst->cp_retx = 0;
189 /* 5.2.3.1.2: enter MO-wait for CP-ACK */
190 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
191 new_cp_state(inst, GSM411_CPS_WAIT_CP_ACK);
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200192 osmo_timer_setup(&inst->cp_timer, cp_timer_expired, inst);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200193 /* 5.3.2.1: Set Timer TC1A */
194 osmo_timer_schedule(&inst->cp_timer, inst->cp_tc1, 0);
195 /* clone cp_msg */
196 nmsg = gsm411_msgb_alloc();
197 memcpy(msgb_put(nmsg, inst->cp_msg->len), inst->cp_msg->data,
198 inst->cp_msg->len);
199 /* send MMSMS_DATA_REQ with CP-DATA */
200 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
201 GSM411_MT_CP_DATA);
202}
203
204static int gsm411_mmsms_est_cnf(struct gsm411_smc_inst *inst, struct msgb *msg)
205{
206 if (!inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100207 LOGP(DLSMS, LOGL_FATAL,
208 SMC_LOG_STR "EST CNF, but we have no cp_msg. This "
209 "should never happen, please fix!\n",
210 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200211 return -EINVAL;
212 }
213
214 return gsm411_mmsms_send_msg(inst);
215}
216
217/* SMC TC1* is expired */
218static void cp_timer_expired(void *data)
219{
220 struct gsm411_smc_inst *inst = data;
221 struct msgb *nmsg;
222
223 if (inst->cp_retx == inst->cp_max_retr) {
224
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100225 LOGP(DLSMS, LOGL_INFO,
226 SMC_LOG_STR "TC1* timeout, no more retries.\n",
227 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200228 /* 5.3.2.1: enter idle state */
229 new_cp_state(inst, GSM411_CPS_IDLE);
230 /* indicate error */
231 nmsg = gsm411_msgb_alloc();
232 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
233 msgb_free(nmsg);
234 /* free pending stored msg */
235 if (inst->cp_msg) {
236 msgb_free(inst->cp_msg);
237 inst->cp_msg = NULL;
238 }
239 /* release MM connection */
240 nmsg = gsm411_msgb_alloc();
241 inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
242 return;
243 }
244
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100245 LOGP(DLSMS, LOGL_INFO,
246 SMC_LOG_STR "TC1* timeout, retrying...\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200247 inst->cp_retx++;
248 gsm411_mmsms_est_cnf(inst, NULL);
249}
250
251static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg)
252{
253 /* free stored msg */
254 if (inst->cp_msg) {
255 msgb_free(inst->cp_msg);
256 inst->cp_msg = NULL;
257 }
258
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100259 LOGP(DLSMS, LOGL_INFO,
260 SMC_LOG_STR "received CP-ACK\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200261 /* 5.3.2.1 enter MM Connection established */
262 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
263 /* 5.3.2.1: Reset Timer TC1* */
264 osmo_timer_del(&inst->cp_timer);
265
266 /* pending release? */
267 if (inst->cp_rel) {
268 struct msgb *nmsg;
269
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100270 LOGP(DLSMS, LOGL_INFO,
271 SMC_LOG_STR "we have pending release.\n",
272 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200273 new_cp_state(inst, GSM411_CPS_IDLE);
274 /* release MM connection */
275 nmsg = gsm411_msgb_alloc();
276 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
277 }
278
279 return 0;
280}
281
282static int gsm411_mmsms_cp_data(struct gsm411_smc_inst *inst, struct msgb *msg)
283{
284 struct msgb *nmsg;
285 int mt = GSM411_MNSMS_DATA_IND;
286
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100287 LOGP(DLSMS, LOGL_INFO,
288 SMC_LOG_STR "received CP-DATA\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200289 /* 5.3.1 enter MM Connection established (if idle) */
290 if (inst->cp_state == GSM411_CPS_IDLE) {
291 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
292 mt = GSM411_MNSMS_EST_IND;
293 /* clear stored release flag */
294 inst->cp_rel = 0;
295 }
296 /* send MMSMS_DATA_REQ (CP ACK) */
297 nmsg = gsm411_msgb_alloc();
298 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, GSM411_MT_CP_ACK);
299 /* indicate data */
300 inst->mn_recv(inst, mt, msg);
301
302 return 0;
303}
304
305/* send CP DATA */
306static int gsm411_mnsms_data_req(struct gsm411_smc_inst *inst, struct msgb *msg)
307{
308 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100309 LOGP(DLSMS, LOGL_FATAL,
310 SMC_LOG_STR "DATA REQ, but we already have an "
311 "cp_msg. This should never happen, please fix!\n",
312 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200313 msgb_free(inst->cp_msg);
314 }
315
316 /* store and send */
317 inst->cp_msg = msg;
318 return gsm411_mmsms_send_msg(inst);
319}
320
321/* release SMC connection */
322static int gsm411_mnsms_rel_req(struct gsm411_smc_inst *inst, struct msgb *msg)
323{
324 struct msgb *nmsg;
325
326 msgb_free(msg);
327
328 /* discard silently */
329 if (inst->cp_state == GSM411_CPS_IDLE)
330 return 0;
331
332 /* store release, until established or released */
333 if (inst->cp_state != GSM411_CPS_MM_ESTABLISHED) {
Holger Hans Peter Freyther09161592012-11-11 10:09:24 +0100334 LOGP(DLSMS, LOGL_NOTICE,
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100335 SMC_LOG_STR "cannot release yet current state: %s\n",
336 inst->id, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200337 inst->cp_rel = 1;
338 return 0;
339 }
340
341 /* free stored msg */
342 if (inst->cp_msg) {
343 msgb_free(inst->cp_msg);
344 inst->cp_msg = NULL;
345 }
346
347 new_cp_state(inst, GSM411_CPS_IDLE);
348 /* release MM connection */
349 nmsg = gsm411_msgb_alloc();
350 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
351}
352
353static int gsm411_mmsms_cp_error(struct gsm411_smc_inst *inst, struct msgb *msg)
354{
355 struct msgb *nmsg;
356
357 /* free stored msg */
358 if (inst->cp_msg) {
359 msgb_free(inst->cp_msg);
360 inst->cp_msg = NULL;
361 }
362
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100363 LOGP(DLSMS, LOGL_INFO,
364 SMC_LOG_STR "received CP-ERROR\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200365 /* 5.3.4 enter idle */
366 new_cp_state(inst, GSM411_CPS_IDLE);
367 /* indicate error */
368 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, msg);
369 /* release MM connection */
370 nmsg = gsm411_msgb_alloc();
371 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
372}
373
374static int gsm411_mmsms_rel_ind(struct gsm411_smc_inst *inst, struct msgb *msg)
375{
376 struct msgb *nmsg;
377
378 /* free stored msg */
379 if (inst->cp_msg) {
380 msgb_free(inst->cp_msg);
381 inst->cp_msg = NULL;
382 }
383
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100384 LOGP(DLSMS, LOGL_INFO,
385 SMC_LOG_STR "MM layer is released\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200386 /* 5.3.4 enter idle */
387 new_cp_state(inst, GSM411_CPS_IDLE);
388 /* indicate error */
389 nmsg = gsm411_msgb_alloc();
390 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
391 msgb_free(nmsg);
392
393 return 0;
394}
395
396/* abort SMC connection */
397static int gsm411_mnsms_abort_req(struct gsm411_smc_inst *inst,
398 struct msgb *msg)
399{
400 struct msgb *nmsg;
401
402 /* free stored msg */
403 if (inst->cp_msg) {
404 msgb_free(inst->cp_msg);
405 inst->cp_msg = NULL;
406 }
407
408 /* 5.3.4 go idle */
409 new_cp_state(inst, GSM411_CPS_IDLE);
410 /* send MMSMS_DATA_REQ with CP-ERROR */
411 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, msg, GSM411_MT_CP_ERROR);
412 /* release MM connection */
413 nmsg = gsm411_msgb_alloc();
414 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
415}
416
417/* statefull handling for MNSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100418static const struct smcdownstate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200419 uint32_t states;
420 int type;
421 const char *name;
422 int (*rout) (struct gsm411_smc_inst *inst,
423 struct msgb *msg);
424} smcdownstatelist[] = {
425 /* establish request */
426 {SBIT(GSM411_CPS_IDLE),
427 GSM411_MNSMS_EST_REQ,
428 "MNSMS-EST-REQ", gsm411_mnsms_est_req},
429
430 /* release request */
431 {ALL_STATES,
432 GSM411_MNSMS_REL_REQ,
433 "MNSMS-REL-REQ", gsm411_mnsms_rel_req},
434
435 /* data request */
436 {SBIT(GSM411_CPS_MM_ESTABLISHED),
437 GSM411_MNSMS_DATA_REQ,
438 "MNSMS-DATA-REQ", gsm411_mnsms_data_req},
439
440 /* abort request */
441 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
442 GSM411_MNSMS_ABORT_REQ,
443 "MNSMS-ABORT-REQ", gsm411_mnsms_abort_req},
444};
445
446#define SMCDOWNSLLEN \
447 (sizeof(smcdownstatelist) / sizeof(struct smcdownstate))
448
449/* message from upper layer */
450int gsm411_smc_send(struct gsm411_smc_inst *inst, int msg_type,
451 struct msgb *msg)
452{
453 int i, rc;
454
455 /* find function for current state and message */
456 for (i = 0; i < SMCDOWNSLLEN; i++) {
457 if ((msg_type == smcdownstatelist[i].type)
458 && (SBIT(inst->cp_state) & smcdownstatelist[i].states))
459 break;
460 }
461 if (i == SMCDOWNSLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100462 LOGP(DLSMS, LOGL_NOTICE,
463 SMC_LOG_STR "message %u unhandled at this state %s.\n",
464 inst->id, msg_type, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200465 msgb_free(msg);
466 return 0;
467 }
468
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100469 LOGP(DLSMS, LOGL_INFO,
470 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200471 smcdownstatelist[i].name, smc_state_names[inst->cp_state]);
472
473 rc = smcdownstatelist[i].rout(inst, msg);
474
475 return rc;
476}
477
478/* statefull handling for MMSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100479static const struct smcdatastate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200480 uint32_t states;
481 int type, cp_type;
482 const char *name;
483 int (*rout) (struct gsm411_smc_inst *inst,
484 struct msgb *msg);
485} smcdatastatelist[] = {
486 /* establish confirm */
487 {SBIT(GSM411_CPS_MM_CONN_PENDING),
488 GSM411_MMSMS_EST_CNF, 0,
489 "MMSMS-EST-CNF", gsm411_mmsms_est_cnf},
490
491 /* establish indication (CP DATA) */
492 {SBIT(GSM411_CPS_IDLE),
493 GSM411_MMSMS_EST_IND, GSM411_MT_CP_DATA,
494 "MMSMS-EST-IND (CP DATA)", gsm411_mmsms_cp_data},
495
496 /* data indication (CP DATA) */
497 {SBIT(GSM411_CPS_MM_ESTABLISHED),
498 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_DATA,
499 "MMSMS-DATA-IND (CP DATA)", gsm411_mmsms_cp_data},
500
501 /* data indication (CP ACK) */
502 {SBIT(GSM411_CPS_WAIT_CP_ACK),
503 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ACK,
504 "MMSMS-DATA-IND (CP ACK)", gsm411_mmsms_cp_ack},
505
506 /* data indication (CP ERROR) */
507 {ALL_STATES,
508 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ERROR,
509 "MMSMS-DATA-IND (CP_ERROR)", gsm411_mmsms_cp_error},
510
511 /* release indication */
512 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
513 GSM411_MMSMS_REL_IND, 0,
514 "MMSMS-REL-IND", gsm411_mmsms_rel_ind},
515
516};
517
518#define SMCDATASLLEN \
519 (sizeof(smcdatastatelist) / sizeof(struct smcdatastate))
520
521/* message from lower layer
522 * WARNING: We must not free msg, since it will be performed by the
523 * lower layer. */
524int gsm411_smc_recv(struct gsm411_smc_inst *inst, int msg_type,
525 struct msgb *msg, int cp_msg_type)
526{
527 int i, rc;
528
529 /* find function for current state and message */
530 for (i = 0; i < SMCDATASLLEN; i++) {
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100531 /* state must match, MM message must match
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200532 * CP msg must match only in case of MMSMS_DATA_IND
533 */
534 if ((msg_type == smcdatastatelist[i].type)
535 && (SBIT(inst->cp_state) & smcdatastatelist[i].states)
536 && (msg_type != GSM411_MMSMS_DATA_IND
537 || cp_msg_type == smcdatastatelist[i].cp_type))
538 break;
539 }
540 if (i == SMCDATASLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100541 LOGP(DLSMS, LOGL_NOTICE,
542 SMC_LOG_STR "message 0x%x/%u unhandled at this "
543 "state %s.\n", inst->id, msg_type, cp_msg_type,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200544 smc_state_names[inst->cp_state]);
545 if (msg_type == GSM411_MMSMS_EST_IND
546 || msg_type == GSM411_MMSMS_DATA_IND) {
547 struct msgb *nmsg;
548
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100549 LOGP(DLSMS, LOGL_NOTICE,
550 SMC_LOG_STR "RX Unimplemented CP "
551 "msg_type: 0x%02x\n", inst->id, msg_type);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200552 /* 5.3.4 enter idle */
553 new_cp_state(inst, GSM411_CPS_IDLE);
554 /* indicate error */
555 gsm411_tx_cp_error(inst,
556 GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
557 /* send error indication to upper layer */
558 nmsg = gsm411_msgb_alloc();
559 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
560 msgb_free(nmsg);
561 /* release MM connection */
562 nmsg = gsm411_msgb_alloc();
563 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg,
564 0);
565 }
566 return 0;
567 }
568
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100569 LOGP(DLSMS, LOGL_INFO,
570 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200571 smcdatastatelist[i].name, smc_state_names[inst->cp_state]);
572
573 rc = smcdatastatelist[i].rout(inst, msg);
574
575 return rc;
576}
Harald Welte96e2a002017-06-12 21:44:18 +0200577
578/*! @} */