blob: 9fecd7e670dc72ccdd8c64eb3826108c01dc6c07 [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
14 * it under the terms of the GNU Affero General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (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
21 * GNU Affero General Public License for more details.
22 *
23 * You should have received a copy of the GNU Affero General Public License
24 * 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 *
47 * There is expeption, if MMSMS-REL-IND is received from lower layer, the
48 * process returns to IDLE without sending MMSMS-REL-REQ.
49 *
50 */
51
52#include <string.h>
53#include <errno.h>
54#include <osmocom/core/msgb.h>
55#include <osmocom/core/logging.h>
56#include <osmocom/core/timer.h>
57
58#include <osmocom/gsm/gsm0411_utils.h>
59#include <osmocom/gsm/gsm0411_smc.h>
60#include <osmocom/gsm/protocol/gsm_04_08.h>
61
62static void cp_timer_expired(void *data);
63
Sylvain Munautcc90d492011-11-12 23:52:40 +010064#define MAX_SMS_RETRY 2
Andreas Eversbergbbf90342011-10-28 03:55:37 +020065
66/* init a new instance */
67void gsm411_smc_init(struct gsm411_smc_inst *inst, int network,
68 int (*mn_recv) (struct gsm411_smc_inst *inst, int msg_type,
69 struct msgb *msg),
70 int (*mm_send) (struct gsm411_smc_inst *inst, int msg_type,
71 struct msgb *msg, int cp_msg_type))
72{
73 memset(inst, 0, sizeof(*inst));
74 inst->network = network;
75 inst->cp_max_retr = MAX_SMS_RETRY;
Sylvain Munaut0d9b8ec2011-11-12 23:52:20 +010076 inst->cp_tc1 = GSM411_TMR_TC1A_SEC / (inst->cp_max_retr + 1);
Andreas Eversbergbbf90342011-10-28 03:55:37 +020077 inst->cp_state = GSM411_CPS_IDLE;
78 inst->mn_recv = mn_recv;
79 inst->mm_send = mm_send;
80
81 LOGP(DLSMS, LOGL_INFO, "New SMC instance created\n");
82}
83
84/* clear instance */
85void gsm411_smc_clear(struct gsm411_smc_inst *inst)
86{
87 LOGP(DLSMS, LOGL_INFO, "Clear SMC instance\n");
88
89 osmo_timer_del(&inst->cp_timer);
90
91 /* free stored msg */
92 if (inst->cp_msg) {
93 LOGP(DLSMS, LOGL_INFO, "Dropping pending message\n");
94 msgb_free(inst->cp_msg);
95 inst->cp_msg = NULL;
96 }
97}
98
99const char *smc_state_names[] = {
100 "IDLE",
101 "MM_CONN_PENDING",
102 "WAIT_CP_ACK",
103 "MM_ESTABLISHED",
104};
105
106const struct value_string gsm411_cp_cause_strs[] = {
107 { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" },
108 { GSM411_CP_CAUSE_CONGESTION, "Congestion" },
109 { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" },
110 { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
111 { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
112 { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
113 { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
114 "Message incompatible with protocol state" },
115 { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
116 { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
117 { 0, 0 }
118};
119
120static void new_cp_state(struct gsm411_smc_inst *inst,
121 enum gsm411_cp_state state)
122{
123 LOGP(DLSMS, LOGL_INFO, "New CP state %s -> %s\n",
124 smc_state_names[inst->cp_state], smc_state_names[state]);
125 inst->cp_state = state;
126}
127
128static int gsm411_tx_cp_error(struct gsm411_smc_inst *inst, uint8_t cause)
129{
130 struct msgb *nmsg = gsm411_msgb_alloc();
131 uint8_t *causep;
132
133 LOGP(DLSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause,
134 get_value_string(gsm411_cp_cause_strs, cause));
135
136 causep = msgb_put(nmsg, 1);
137 *causep = cause;
138
139 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
140 GSM411_MT_CP_ERROR);
141}
142
143/* etablish SMC connection */
144static int gsm411_mnsms_est_req(struct gsm411_smc_inst *inst, struct msgb *msg)
145{
146 struct msgb *nmsg;
147
148 if (inst->cp_msg) {
149 LOGP(DLSMS, LOGL_FATAL, "EST REQ, but we already have an "
150 "cp_msg. This should never happen, please fix!\n");
151 msgb_free(inst->cp_msg);
152 }
153
154 inst->cp_msg = msg;
155 new_cp_state(inst, GSM411_CPS_MM_CONN_PENDING);
156 /* clear stored release flag */
157 inst->cp_rel = 0;
158 /* send MMSMS_EST_REQ */
159 nmsg = gsm411_msgb_alloc();
160 return inst->mm_send(inst, GSM411_MMSMS_EST_REQ, nmsg, 0);
161}
162
163static int gsm411_mmsms_send_msg(struct gsm411_smc_inst *inst)
164{
165 struct msgb *nmsg;
166
167 LOGP(DLSMS, LOGL_INFO, "Send CP data\n");
168 /* reset retry counter */
169 if (inst->cp_state != GSM411_CPS_WAIT_CP_ACK)
170 inst->cp_retx = 0;
171 /* 5.2.3.1.2: enter MO-wait for CP-ACK */
172 /* 5.2.3.2.3: enter MT-wait for CP-ACK */
173 new_cp_state(inst, GSM411_CPS_WAIT_CP_ACK);
174 inst->cp_timer.data = inst;
175 inst->cp_timer.cb = cp_timer_expired;
176 /* 5.3.2.1: Set Timer TC1A */
177 osmo_timer_schedule(&inst->cp_timer, inst->cp_tc1, 0);
178 /* clone cp_msg */
179 nmsg = gsm411_msgb_alloc();
180 memcpy(msgb_put(nmsg, inst->cp_msg->len), inst->cp_msg->data,
181 inst->cp_msg->len);
182 /* send MMSMS_DATA_REQ with CP-DATA */
183 return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg,
184 GSM411_MT_CP_DATA);
185}
186
187static int gsm411_mmsms_est_cnf(struct gsm411_smc_inst *inst, struct msgb *msg)
188{
189 if (!inst->cp_msg) {
190 LOGP(DLSMS, LOGL_FATAL, "EST CNF, but we have no cp_msg. This "
191 "should never happen, please fix!\n");
192 return -EINVAL;
193 }
194
195 return gsm411_mmsms_send_msg(inst);
196}
197
198/* SMC TC1* is expired */
199static void cp_timer_expired(void *data)
200{
201 struct gsm411_smc_inst *inst = data;
202 struct msgb *nmsg;
203
204 if (inst->cp_retx == inst->cp_max_retr) {
205
206 LOGP(DLSMS, LOGL_INFO, "TC1* timeout, no more retries.\n");
207 /* 5.3.2.1: enter idle state */
208 new_cp_state(inst, GSM411_CPS_IDLE);
209 /* indicate error */
210 nmsg = gsm411_msgb_alloc();
211 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
212 msgb_free(nmsg);
213 /* free pending stored msg */
214 if (inst->cp_msg) {
215 msgb_free(inst->cp_msg);
216 inst->cp_msg = NULL;
217 }
218 /* release MM connection */
219 nmsg = gsm411_msgb_alloc();
220 inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
221 return;
222 }
223
224 LOGP(DLSMS, LOGL_INFO, "TC1* timeout, retrying...\n");
225 inst->cp_retx++;
226 gsm411_mmsms_est_cnf(inst, NULL);
227}
228
229static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg)
230{
231 /* free stored msg */
232 if (inst->cp_msg) {
233 msgb_free(inst->cp_msg);
234 inst->cp_msg = NULL;
235 }
236
237 LOGP(DLSMS, LOGL_INFO, "Received CP-ACK\n");
238 /* 5.3.2.1 enter MM Connection established */
239 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
240 /* 5.3.2.1: Reset Timer TC1* */
241 osmo_timer_del(&inst->cp_timer);
242
243 /* pending release? */
244 if (inst->cp_rel) {
245 struct msgb *nmsg;
246
247 LOGP(DLSMS, LOGL_INFO, "We have pending release.\n");
248 new_cp_state(inst, GSM411_CPS_IDLE);
249 /* release MM connection */
250 nmsg = gsm411_msgb_alloc();
251 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
252 }
253
254 return 0;
255}
256
257static int gsm411_mmsms_cp_data(struct gsm411_smc_inst *inst, struct msgb *msg)
258{
259 struct msgb *nmsg;
260 int mt = GSM411_MNSMS_DATA_IND;
261
262 LOGP(DLSMS, LOGL_INFO, "Received CP-DATA\n");
263 /* 5.3.1 enter MM Connection established (if idle) */
264 if (inst->cp_state == GSM411_CPS_IDLE) {
265 new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED);
266 mt = GSM411_MNSMS_EST_IND;
267 /* clear stored release flag */
268 inst->cp_rel = 0;
269 }
270 /* send MMSMS_DATA_REQ (CP ACK) */
271 nmsg = gsm411_msgb_alloc();
272 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, GSM411_MT_CP_ACK);
273 /* indicate data */
274 inst->mn_recv(inst, mt, msg);
275
276 return 0;
277}
278
279/* send CP DATA */
280static int gsm411_mnsms_data_req(struct gsm411_smc_inst *inst, struct msgb *msg)
281{
282 if (inst->cp_msg) {
283 LOGP(DLSMS, LOGL_FATAL, "DATA REQ, but we already have an "
284 "cp_msg. This should never happen, please fix!\n");
285 msgb_free(inst->cp_msg);
286 }
287
288 /* store and send */
289 inst->cp_msg = msg;
290 return gsm411_mmsms_send_msg(inst);
291}
292
293/* release SMC connection */
294static int gsm411_mnsms_rel_req(struct gsm411_smc_inst *inst, struct msgb *msg)
295{
296 struct msgb *nmsg;
297
298 msgb_free(msg);
299
300 /* discard silently */
301 if (inst->cp_state == GSM411_CPS_IDLE)
302 return 0;
303
304 /* store release, until established or released */
305 if (inst->cp_state != GSM411_CPS_MM_ESTABLISHED) {
Holger Hans Peter Freyther09161592012-11-11 10:09:24 +0100306 LOGP(DLSMS, LOGL_NOTICE,
307 "Cannot release yet current state: %s\n",
308 smc_state_names[inst->cp_state]);
Andreas Eversbergbbf90342011-10-28 03:55:37 +0200309 inst->cp_rel = 1;
310 return 0;
311 }
312
313 /* free stored msg */
314 if (inst->cp_msg) {
315 msgb_free(inst->cp_msg);
316 inst->cp_msg = NULL;
317 }
318
319 new_cp_state(inst, GSM411_CPS_IDLE);
320 /* release MM connection */
321 nmsg = gsm411_msgb_alloc();
322 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
323}
324
325static int gsm411_mmsms_cp_error(struct gsm411_smc_inst *inst, struct msgb *msg)
326{
327 struct msgb *nmsg;
328
329 /* free stored msg */
330 if (inst->cp_msg) {
331 msgb_free(inst->cp_msg);
332 inst->cp_msg = NULL;
333 }
334
335 LOGP(DLSMS, LOGL_INFO, "Received CP-ERROR\n");
336 /* 5.3.4 enter idle */
337 new_cp_state(inst, GSM411_CPS_IDLE);
338 /* indicate error */
339 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, msg);
340 /* release MM connection */
341 nmsg = gsm411_msgb_alloc();
342 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
343}
344
345static int gsm411_mmsms_rel_ind(struct gsm411_smc_inst *inst, struct msgb *msg)
346{
347 struct msgb *nmsg;
348
349 /* free stored msg */
350 if (inst->cp_msg) {
351 msgb_free(inst->cp_msg);
352 inst->cp_msg = NULL;
353 }
354
355 LOGP(DLSMS, LOGL_INFO, "MM layer is released\n");
356 /* 5.3.4 enter idle */
357 new_cp_state(inst, GSM411_CPS_IDLE);
358 /* indicate error */
359 nmsg = gsm411_msgb_alloc();
360 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
361 msgb_free(nmsg);
362
363 return 0;
364}
365
366/* abort SMC connection */
367static int gsm411_mnsms_abort_req(struct gsm411_smc_inst *inst,
368 struct msgb *msg)
369{
370 struct msgb *nmsg;
371
372 /* free stored msg */
373 if (inst->cp_msg) {
374 msgb_free(inst->cp_msg);
375 inst->cp_msg = NULL;
376 }
377
378 /* 5.3.4 go idle */
379 new_cp_state(inst, GSM411_CPS_IDLE);
380 /* send MMSMS_DATA_REQ with CP-ERROR */
381 inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, msg, GSM411_MT_CP_ERROR);
382 /* release MM connection */
383 nmsg = gsm411_msgb_alloc();
384 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0);
385}
386
387/* statefull handling for MNSMS SAP messages */
388static struct smcdownstate {
389 uint32_t states;
390 int type;
391 const char *name;
392 int (*rout) (struct gsm411_smc_inst *inst,
393 struct msgb *msg);
394} smcdownstatelist[] = {
395 /* establish request */
396 {SBIT(GSM411_CPS_IDLE),
397 GSM411_MNSMS_EST_REQ,
398 "MNSMS-EST-REQ", gsm411_mnsms_est_req},
399
400 /* release request */
401 {ALL_STATES,
402 GSM411_MNSMS_REL_REQ,
403 "MNSMS-REL-REQ", gsm411_mnsms_rel_req},
404
405 /* data request */
406 {SBIT(GSM411_CPS_MM_ESTABLISHED),
407 GSM411_MNSMS_DATA_REQ,
408 "MNSMS-DATA-REQ", gsm411_mnsms_data_req},
409
410 /* abort request */
411 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
412 GSM411_MNSMS_ABORT_REQ,
413 "MNSMS-ABORT-REQ", gsm411_mnsms_abort_req},
414};
415
416#define SMCDOWNSLLEN \
417 (sizeof(smcdownstatelist) / sizeof(struct smcdownstate))
418
419/* message from upper layer */
420int gsm411_smc_send(struct gsm411_smc_inst *inst, int msg_type,
421 struct msgb *msg)
422{
423 int i, rc;
424
425 /* find function for current state and message */
426 for (i = 0; i < SMCDOWNSLLEN; i++) {
427 if ((msg_type == smcdownstatelist[i].type)
428 && (SBIT(inst->cp_state) & smcdownstatelist[i].states))
429 break;
430 }
431 if (i == SMCDOWNSLLEN) {
432 LOGP(DLSMS, LOGL_NOTICE, "Message %u unhandled at this state "
433 "%s.\n", msg_type, smc_state_names[inst->cp_state]);
434 msgb_free(msg);
435 return 0;
436 }
437
438 LOGP(DLSMS, LOGL_INFO, "Message %s received in state %s\n",
439 smcdownstatelist[i].name, smc_state_names[inst->cp_state]);
440
441 rc = smcdownstatelist[i].rout(inst, msg);
442
443 return rc;
444}
445
446/* statefull handling for MMSMS SAP messages */
447static struct smcdatastate {
448 uint32_t states;
449 int type, cp_type;
450 const char *name;
451 int (*rout) (struct gsm411_smc_inst *inst,
452 struct msgb *msg);
453} smcdatastatelist[] = {
454 /* establish confirm */
455 {SBIT(GSM411_CPS_MM_CONN_PENDING),
456 GSM411_MMSMS_EST_CNF, 0,
457 "MMSMS-EST-CNF", gsm411_mmsms_est_cnf},
458
459 /* establish indication (CP DATA) */
460 {SBIT(GSM411_CPS_IDLE),
461 GSM411_MMSMS_EST_IND, GSM411_MT_CP_DATA,
462 "MMSMS-EST-IND (CP DATA)", gsm411_mmsms_cp_data},
463
464 /* data indication (CP DATA) */
465 {SBIT(GSM411_CPS_MM_ESTABLISHED),
466 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_DATA,
467 "MMSMS-DATA-IND (CP DATA)", gsm411_mmsms_cp_data},
468
469 /* data indication (CP ACK) */
470 {SBIT(GSM411_CPS_WAIT_CP_ACK),
471 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ACK,
472 "MMSMS-DATA-IND (CP ACK)", gsm411_mmsms_cp_ack},
473
474 /* data indication (CP ERROR) */
475 {ALL_STATES,
476 GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ERROR,
477 "MMSMS-DATA-IND (CP_ERROR)", gsm411_mmsms_cp_error},
478
479 /* release indication */
480 {ALL_STATES - SBIT(GSM411_CPS_IDLE),
481 GSM411_MMSMS_REL_IND, 0,
482 "MMSMS-REL-IND", gsm411_mmsms_rel_ind},
483
484};
485
486#define SMCDATASLLEN \
487 (sizeof(smcdatastatelist) / sizeof(struct smcdatastate))
488
489/* message from lower layer
490 * WARNING: We must not free msg, since it will be performed by the
491 * lower layer. */
492int gsm411_smc_recv(struct gsm411_smc_inst *inst, int msg_type,
493 struct msgb *msg, int cp_msg_type)
494{
495 int i, rc;
496
497 /* find function for current state and message */
498 for (i = 0; i < SMCDATASLLEN; i++) {
499 /* state must machtch, MM message must match
500 * CP msg must match only in case of MMSMS_DATA_IND
501 */
502 if ((msg_type == smcdatastatelist[i].type)
503 && (SBIT(inst->cp_state) & smcdatastatelist[i].states)
504 && (msg_type != GSM411_MMSMS_DATA_IND
505 || cp_msg_type == smcdatastatelist[i].cp_type))
506 break;
507 }
508 if (i == SMCDATASLLEN) {
509 LOGP(DLSMS, LOGL_NOTICE, "Message 0x%x/%u unhandled at this "
510 "state %s.\n", msg_type, cp_msg_type,
511 smc_state_names[inst->cp_state]);
512 if (msg_type == GSM411_MMSMS_EST_IND
513 || msg_type == GSM411_MMSMS_DATA_IND) {
514 struct msgb *nmsg;
515
516 LOGP(DLSMS, LOGL_NOTICE, "RX Unimplemented CP "
517 "msg_type: 0x%02x\n", msg_type);
518 /* 5.3.4 enter idle */
519 new_cp_state(inst, GSM411_CPS_IDLE);
520 /* indicate error */
521 gsm411_tx_cp_error(inst,
522 GSM411_CP_CAUSE_MSGTYPE_NOTEXIST);
523 /* send error indication to upper layer */
524 nmsg = gsm411_msgb_alloc();
525 inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg);
526 msgb_free(nmsg);
527 /* release MM connection */
528 nmsg = gsm411_msgb_alloc();
529 return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg,
530 0);
531 }
532 return 0;
533 }
534
535 LOGP(DLSMS, LOGL_INFO, "Message %s received in state %s\n",
536 smcdatastatelist[i].name, smc_state_names[inst->cp_state]);
537
538 rc = smcdatastatelist[i].rout(inst, msg);
539
540 return rc;
541}