blob: 4c083659b8705e94085c82dc971a56c9f8e7aae8 [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
63static void cp_timer_expired(void *data);
64
Sylvain Munautcc90d492011-11-12 23:52:40 +010065#define MAX_SMS_RETRY 2
Andreas Eversbergbbf90342011-10-28 03:55:37 +020066
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010067#define SMC_LOG_STR "SMC(%" PRIu64 ") "
68
Andreas Eversbergbbf90342011-10-28 03:55:37 +020069/* init a new instance */
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010070void gsm411_smc_init(struct gsm411_smc_inst *inst, uint64_t id, int network,
Andreas Eversbergbbf90342011-10-28 03:55:37 +020071 int (*mn_recv) (struct gsm411_smc_inst *inst, int msg_type,
72 struct msgb *msg),
73 int (*mm_send) (struct gsm411_smc_inst *inst, int msg_type,
74 struct msgb *msg, int cp_msg_type))
75{
76 memset(inst, 0, sizeof(*inst));
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010077 inst->id = id;
Andreas Eversbergbbf90342011-10-28 03:55:37 +020078 inst->network = network;
79 inst->cp_max_retr = MAX_SMS_RETRY;
Sylvain Munaut0d9b8ec2011-11-12 23:52:20 +010080 inst->cp_tc1 = GSM411_TMR_TC1A_SEC / (inst->cp_max_retr + 1);
Andreas Eversbergbbf90342011-10-28 03:55:37 +020081 inst->cp_state = GSM411_CPS_IDLE;
82 inst->mn_recv = mn_recv;
83 inst->mm_send = mm_send;
84
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010085 LOGP(DLSMS, LOGL_INFO,
Holger Hans Peter Freyther68f94472012-12-01 12:51:34 +010086 SMC_LOG_STR "instance created for %s\n",
87 inst->id, inst->network ? "network" : "mobile");
Andreas Eversbergbbf90342011-10-28 03:55:37 +020088}
89
90/* clear instance */
91void gsm411_smc_clear(struct gsm411_smc_inst *inst)
92{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +010093 LOGP(DLSMS, LOGL_INFO,
94 SMC_LOG_STR "clearing instance\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +020095
96 osmo_timer_del(&inst->cp_timer);
97
98 /* free stored msg */
99 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100100 LOGP(DLSMS, LOGL_INFO,
101 SMC_LOG_STR "dropping pending message\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200102 msgb_free(inst->cp_msg);
103 inst->cp_msg = NULL;
104 }
105}
106
107const char *smc_state_names[] = {
108 "IDLE",
109 "MM_CONN_PENDING",
110 "WAIT_CP_ACK",
111 "MM_ESTABLISHED",
112};
113
114const struct value_string gsm411_cp_cause_strs[] = {
115 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
116 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
117 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
118 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
119 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
120 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
121 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
122 "Message incompatible with protocol state" },
123 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
124 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
125 { 0, 0 }
126};
127
128static void new_cp_state(struct gsm411_smc_inst *inst,
129 enum gsm411_cp_state state)
130{
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100131 LOGP(DLSMS, LOGL_INFO,
132 SMC_LOG_STR "new CP state %s -> %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200133 smc_state_names[inst->cp_state], smc_state_names[state]);
134 inst->cp_state = state;
135}
136
137static int gsm411_tx_cp_error(struct gsm411_smc_inst *inst, uint8_t cause)
138{
139 struct msgb *nmsg = gsm411_msgb_alloc();
140 uint8_t *causep;
141
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100142 LOGP(DLSMS, LOGL_NOTICE,
143 SMC_LOG_STR "TX CP-ERROR, cause %d (%s)\n", inst->id, cause,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200144 get_value_string(gsm411_cp_cause_strs, cause));
145
146 causep = msgb_put(nmsg, 1);
147 *causep = cause;
148
149 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
150 GSM411_MT_CP_ERROR);
151}
152
Holger Hans Peter Freyther866fc912012-11-13 22:29:35 +0100153/* establish SMC connection */
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200154static int gsm411_mnsms_est_req(struct gsm411_smc_inst *inst, struct msgb *msg)
155{
156 struct msgb *nmsg;
157
158 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100159 LOGP(DLSMS, LOGL_FATAL,
160 SMC_LOG_STR "EST REQ, but we already have an "
161 "cp_msg. This should never happen, please fix!\n",
162 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200163 msgb_free(inst->cp_msg);
164 }
165
166 inst->cp_msg = msg;
167 new_cp_state(inst, GSM411_CPS_MM_CONN_PENDING);
168 /* clear stored release flag */
169 inst->cp_rel = 0;
170 /* send MMSMS_EST_REQ */
171 nmsg = gsm411_msgb_alloc();
172 return inst->mm_send(inst, GSM411_MMSMS_EST_REQ, nmsg, 0);
173}
174
175static int gsm411_mmsms_send_msg(struct gsm411_smc_inst *inst)
176{
177 struct msgb *nmsg;
178
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100179 LOGP(DLSMS, LOGL_INFO,
180 SMC_LOG_STR "send CP data\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200181 /* reset retry counter */
182 if (inst->cp_state != GSM411_CPS_WAIT_CP_ACK)
183 inst->cp_retx = 0;
184 /* 5.2.3.1.2: enter MO-wait for CP-ACK */
185 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
186 new_cp_state(inst, GSM411_CPS_WAIT_CP_ACK);
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200187 osmo_timer_setup(&inst->cp_timer, cp_timer_expired, inst);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200188 /* 5.3.2.1: Set Timer TC1A */
189 osmo_timer_schedule(&inst->cp_timer, inst->cp_tc1, 0);
190 /* clone cp_msg */
191 nmsg = gsm411_msgb_alloc();
192 memcpy(msgb_put(nmsg, inst->cp_msg->len), inst->cp_msg->data,
193 inst->cp_msg->len);
194 /* send MMSMS_DATA_REQ with CP-DATA */
195 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
196 GSM411_MT_CP_DATA);
197}
198
199static int gsm411_mmsms_est_cnf(struct gsm411_smc_inst *inst, struct msgb *msg)
200{
201 if (!inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100202 LOGP(DLSMS, LOGL_FATAL,
203 SMC_LOG_STR "EST CNF, but we have no cp_msg. This "
204 "should never happen, please fix!\n",
205 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200206 return -EINVAL;
207 }
208
209 return gsm411_mmsms_send_msg(inst);
210}
211
212/* SMC TC1* is expired */
213static void cp_timer_expired(void *data)
214{
215 struct gsm411_smc_inst *inst = data;
216 struct msgb *nmsg;
217
218 if (inst->cp_retx == inst->cp_max_retr) {
219
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100220 LOGP(DLSMS, LOGL_INFO,
221 SMC_LOG_STR "TC1* timeout, no more retries.\n",
222 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200223 /* 5.3.2.1: enter idle state */
224 new_cp_state(inst, GSM411_CPS_IDLE);
225 /* indicate error */
226 nmsg = gsm411_msgb_alloc();
227 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
228 msgb_free(nmsg);
229 /* free pending stored msg */
230 if (inst->cp_msg) {
231 msgb_free(inst->cp_msg);
232 inst->cp_msg = NULL;
233 }
234 /* release MM connection */
235 nmsg = gsm411_msgb_alloc();
236 inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
237 return;
238 }
239
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100240 LOGP(DLSMS, LOGL_INFO,
241 SMC_LOG_STR "TC1* timeout, retrying...\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200242 inst->cp_retx++;
243 gsm411_mmsms_est_cnf(inst, NULL);
244}
245
246static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg)
247{
248 /* free stored msg */
249 if (inst->cp_msg) {
250 msgb_free(inst->cp_msg);
251 inst->cp_msg = NULL;
252 }
253
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100254 LOGP(DLSMS, LOGL_INFO,
255 SMC_LOG_STR "received CP-ACK\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200256 /* 5.3.2.1 enter MM Connection established */
257 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
258 /* 5.3.2.1: Reset Timer TC1* */
259 osmo_timer_del(&inst->cp_timer);
260
261 /* pending release? */
262 if (inst->cp_rel) {
263 struct msgb *nmsg;
264
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100265 LOGP(DLSMS, LOGL_INFO,
266 SMC_LOG_STR "we have pending release.\n",
267 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200268 new_cp_state(inst, GSM411_CPS_IDLE);
269 /* release MM connection */
270 nmsg = gsm411_msgb_alloc();
271 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
272 }
273
274 return 0;
275}
276
277static int gsm411_mmsms_cp_data(struct gsm411_smc_inst *inst, struct msgb *msg)
278{
279 struct msgb *nmsg;
280 int mt = GSM411_MNSMS_DATA_IND;
281
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100282 LOGP(DLSMS, LOGL_INFO,
283 SMC_LOG_STR "received CP-DATA\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200284 /* 5.3.1 enter MM Connection established (if idle) */
285 if (inst->cp_state == GSM411_CPS_IDLE) {
286 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
287 mt = GSM411_MNSMS_EST_IND;
288 /* clear stored release flag */
289 inst->cp_rel = 0;
290 }
291 /* send MMSMS_DATA_REQ (CP ACK) */
292 nmsg = gsm411_msgb_alloc();
293 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, GSM411_MT_CP_ACK);
294 /* indicate data */
295 inst->mn_recv(inst, mt, msg);
296
297 return 0;
298}
299
300/* send CP DATA */
301static int gsm411_mnsms_data_req(struct gsm411_smc_inst *inst, struct msgb *msg)
302{
303 if (inst->cp_msg) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100304 LOGP(DLSMS, LOGL_FATAL,
305 SMC_LOG_STR "DATA REQ, but we already have an "
306 "cp_msg. This should never happen, please fix!\n",
307 inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200308 msgb_free(inst->cp_msg);
309 }
310
311 /* store and send */
312 inst->cp_msg = msg;
313 return gsm411_mmsms_send_msg(inst);
314}
315
316/* release SMC connection */
317static int gsm411_mnsms_rel_req(struct gsm411_smc_inst *inst, struct msgb *msg)
318{
319 struct msgb *nmsg;
320
321 msgb_free(msg);
322
323 /* discard silently */
324 if (inst->cp_state == GSM411_CPS_IDLE)
325 return 0;
326
327 /* store release, until established or released */
328 if (inst->cp_state != GSM411_CPS_MM_ESTABLISHED) {
Holger Hans Peter Freyther09161592012-11-11 10:09:24 +0100329 LOGP(DLSMS, LOGL_NOTICE,
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100330 SMC_LOG_STR "cannot release yet current state: %s\n",
331 inst->id, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200332 inst->cp_rel = 1;
333 return 0;
334 }
335
336 /* free stored msg */
337 if (inst->cp_msg) {
338 msgb_free(inst->cp_msg);
339 inst->cp_msg = NULL;
340 }
341
342 new_cp_state(inst, GSM411_CPS_IDLE);
343 /* release MM connection */
344 nmsg = gsm411_msgb_alloc();
345 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
346}
347
348static int gsm411_mmsms_cp_error(struct gsm411_smc_inst *inst, struct msgb *msg)
349{
350 struct msgb *nmsg;
351
352 /* free stored msg */
353 if (inst->cp_msg) {
354 msgb_free(inst->cp_msg);
355 inst->cp_msg = NULL;
356 }
357
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100358 LOGP(DLSMS, LOGL_INFO,
359 SMC_LOG_STR "received CP-ERROR\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200360 /* 5.3.4 enter idle */
361 new_cp_state(inst, GSM411_CPS_IDLE);
362 /* indicate error */
363 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, msg);
364 /* release MM connection */
365 nmsg = gsm411_msgb_alloc();
366 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
367}
368
369static int gsm411_mmsms_rel_ind(struct gsm411_smc_inst *inst, struct msgb *msg)
370{
371 struct msgb *nmsg;
372
373 /* free stored msg */
374 if (inst->cp_msg) {
375 msgb_free(inst->cp_msg);
376 inst->cp_msg = NULL;
377 }
378
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100379 LOGP(DLSMS, LOGL_INFO,
380 SMC_LOG_STR "MM layer is released\n", inst->id);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200381 /* 5.3.4 enter idle */
382 new_cp_state(inst, GSM411_CPS_IDLE);
383 /* indicate error */
384 nmsg = gsm411_msgb_alloc();
385 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
386 msgb_free(nmsg);
387
388 return 0;
389}
390
391/* abort SMC connection */
392static int gsm411_mnsms_abort_req(struct gsm411_smc_inst *inst,
393 struct msgb *msg)
394{
395 struct msgb *nmsg;
396
397 /* free stored msg */
398 if (inst->cp_msg) {
399 msgb_free(inst->cp_msg);
400 inst->cp_msg = NULL;
401 }
402
403 /* 5.3.4 go idle */
404 new_cp_state(inst, GSM411_CPS_IDLE);
405 /* send MMSMS_DATA_REQ with CP-ERROR */
406 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, msg, GSM411_MT_CP_ERROR);
407 /* release MM connection */
408 nmsg = gsm411_msgb_alloc();
409 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
410}
411
412/* statefull handling for MNSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100413static const struct smcdownstate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200414 uint32_t states;
415 int type;
416 const char *name;
417 int (*rout) (struct gsm411_smc_inst *inst,
418 struct msgb *msg);
419} smcdownstatelist[] = {
420 /* establish request */
421 {SBIT(GSM411_CPS_IDLE),
422 GSM411_MNSMS_EST_REQ,
423 "MNSMS-EST-REQ", gsm411_mnsms_est_req},
424
425 /* release request */
426 {ALL_STATES,
427 GSM411_MNSMS_REL_REQ,
428 "MNSMS-REL-REQ", gsm411_mnsms_rel_req},
429
430 /* data request */
431 {SBIT(GSM411_CPS_MM_ESTABLISHED),
432 GSM411_MNSMS_DATA_REQ,
433 "MNSMS-DATA-REQ", gsm411_mnsms_data_req},
434
435 /* abort request */
436 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
437 GSM411_MNSMS_ABORT_REQ,
438 "MNSMS-ABORT-REQ", gsm411_mnsms_abort_req},
439};
440
441#define SMCDOWNSLLEN \
442 (sizeof(smcdownstatelist) / sizeof(struct smcdownstate))
443
444/* message from upper layer */
445int gsm411_smc_send(struct gsm411_smc_inst *inst, int msg_type,
446 struct msgb *msg)
447{
448 int i, rc;
449
450 /* find function for current state and message */
451 for (i = 0; i < SMCDOWNSLLEN; i++) {
452 if ((msg_type == smcdownstatelist[i].type)
453 && (SBIT(inst->cp_state) & smcdownstatelist[i].states))
454 break;
455 }
456 if (i == SMCDOWNSLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100457 LOGP(DLSMS, LOGL_NOTICE,
458 SMC_LOG_STR "message %u unhandled at this state %s.\n",
459 inst->id, msg_type, smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200460 msgb_free(msg);
461 return 0;
462 }
463
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100464 LOGP(DLSMS, LOGL_INFO,
465 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200466 smcdownstatelist[i].name, smc_state_names[inst->cp_state]);
467
468 rc = smcdownstatelist[i].rout(inst, msg);
469
470 return rc;
471}
472
473/* statefull handling for MMSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100474static const struct smcdatastate {
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200475 uint32_t states;
476 int type, cp_type;
477 const char *name;
478 int (*rout) (struct gsm411_smc_inst *inst,
479 struct msgb *msg);
480} smcdatastatelist[] = {
481 /* establish confirm */
482 {SBIT(GSM411_CPS_MM_CONN_PENDING),
483 GSM411_MMSMS_EST_CNF, 0,
484 "MMSMS-EST-CNF", gsm411_mmsms_est_cnf},
485
486 /* establish indication (CP DATA) */
487 {SBIT(GSM411_CPS_IDLE),
488 GSM411_MMSMS_EST_IND, GSM411_MT_CP_DATA,
489 "MMSMS-EST-IND (CP DATA)", gsm411_mmsms_cp_data},
490
491 /* data indication (CP DATA) */
492 {SBIT(GSM411_CPS_MM_ESTABLISHED),
493 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_DATA,
494 "MMSMS-DATA-IND (CP DATA)", gsm411_mmsms_cp_data},
495
496 /* data indication (CP ACK) */
497 {SBIT(GSM411_CPS_WAIT_CP_ACK),
498 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ACK,
499 "MMSMS-DATA-IND (CP ACK)", gsm411_mmsms_cp_ack},
500
501 /* data indication (CP ERROR) */
502 {ALL_STATES,
503 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ERROR,
504 "MMSMS-DATA-IND (CP_ERROR)", gsm411_mmsms_cp_error},
505
506 /* release indication */
507 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
508 GSM411_MMSMS_REL_IND, 0,
509 "MMSMS-REL-IND", gsm411_mmsms_rel_ind},
510
511};
512
513#define SMCDATASLLEN \
514 (sizeof(smcdatastatelist) / sizeof(struct smcdatastate))
515
516/* message from lower layer
517 * WARNING: We must not free msg, since it will be performed by the
518 * lower layer. */
519int gsm411_smc_recv(struct gsm411_smc_inst *inst, int msg_type,
520 struct msgb *msg, int cp_msg_type)
521{
522 int i, rc;
523
524 /* find function for current state and message */
525 for (i = 0; i < SMCDATASLLEN; i++) {
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100526 /* state must match, MM message must match
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200527 * CP msg must match only in case of MMSMS_DATA_IND
528 */
529 if ((msg_type == smcdatastatelist[i].type)
530 && (SBIT(inst->cp_state) & smcdatastatelist[i].states)
531 && (msg_type != GSM411_MMSMS_DATA_IND
532 || cp_msg_type == smcdatastatelist[i].cp_type))
533 break;
534 }
535 if (i == SMCDATASLLEN) {
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100536 LOGP(DLSMS, LOGL_NOTICE,
537 SMC_LOG_STR "message 0x%x/%u unhandled at this "
538 "state %s.\n", inst->id, msg_type, cp_msg_type,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200539 smc_state_names[inst->cp_state]);
540 if (msg_type == GSM411_MMSMS_EST_IND
541 || msg_type == GSM411_MMSMS_DATA_IND) {
542 struct msgb *nmsg;
543
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100544 LOGP(DLSMS, LOGL_NOTICE,
545 SMC_LOG_STR "RX Unimplemented CP "
546 "msg_type: 0x%02x\n", inst->id, msg_type);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200547 /* 5.3.4 enter idle */
548 new_cp_state(inst, GSM411_CPS_IDLE);
549 /* indicate error */
550 gsm411_tx_cp_error(inst,
551 GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
552 /* send error indication to upper layer */
553 nmsg = gsm411_msgb_alloc();
554 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
555 msgb_free(nmsg);
556 /* release MM connection */
557 nmsg = gsm411_msgb_alloc();
558 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg,
559 0);
560 }
561 return 0;
562 }
563
Holger Hans Peter Freyther33e8a872012-11-14 06:07:47 +0100564 LOGP(DLSMS, LOGL_INFO,
565 SMC_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200566 smcdatastatelist[i].name, smc_state_names[inst->cp_state]);
567
568 rc = smcdatastatelist[i].rout(inst, msg);
569
570 return rc;
571}