blob: 0a25c7c4ef3b585e1a7f3d9b4566d9604d79dd88 [file] [log] [blame]
Harald Welte55d724a2017-10-16 18:25:45 +02001/* Point-to-Point (PP) Short Message Service (SMS).
Andreas Eversbergc1a91a82011-10-28 11:05:37 +02002 * Support on Mobile Radio Interface
3 * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02004/*
5 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
Andreas Eversbergc1a91a82011-10-28 11:05: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 Eversbergc1a91a82011-10-28 11:05: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 Eversbergc1a91a82011-10-28 11:05:37 +020022 *
Harald Welte388fb032014-10-26 20:42:49 +010023 * You should have received a copy of the GNU General Public License
Andreas Eversbergc1a91a82011-10-28 11:05: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 * Sending Abort/Release (MNSMS-ABORT-REQ or MNSMS-REL-REQ) may cause the
44 * lower layer to become IDLE. Then it is allowed to destroy this instance,
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +010045 * so sending this MUST be the last thing that is done.
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020046 *
47 */
48
49
50#include <string.h>
51#include <errno.h>
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010052#include <inttypes.h>
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020053#include <osmocom/core/msgb.h>
54#include <osmocom/core/logging.h>
55#include <osmocom/core/timer.h>
56#include <osmocom/gsm/tlv.h>
57
58#include <osmocom/gsm/gsm0411_utils.h>
59#include <osmocom/gsm/gsm0411_smc.h>
60#include <osmocom/gsm/gsm0411_smr.h>
61#include <osmocom/gsm/protocol/gsm_04_08.h>
62
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010063#define SMR_LOG_STR "SMR(%" PRIu64 ") "
64
Harald Welte96e2a002017-06-12 21:44:18 +020065/*! \addtogroup sms
66 * @{
Harald Welte55d724a2017-10-16 18:25:45 +020067 * \file gsm0411_smr.c
Harald Welte96e2a002017-06-12 21:44:18 +020068 */
69
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020070static void rp_timer_expired(void *data);
71
72/* init a new instance */
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010073void gsm411_smr_init(struct gsm411_smr_inst *inst, uint64_t id, int network,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020074 int (*rl_recv) (struct gsm411_smr_inst *inst, int msg_type,
75 struct msgb *msg),
76 int (*mn_send) (struct gsm411_smr_inst *inst, int msg_type,
77 struct msgb *msg))
78{
79 memset(inst, 0, sizeof(*inst));
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010080 inst->id = id;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020081 inst->network = network;
82 inst->rp_state = GSM411_RPS_IDLE;
83 inst->rl_recv = rl_recv;
84 inst->mn_send = mn_send;
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +020085 osmo_timer_setup(&inst->rp_timer, rp_timer_expired, inst);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020086
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010087 LOGP(DLSMS, LOGL_INFO,
Holger Hans Peter Freyther68f94472012-12-01 12:51:34 +010088 SMR_LOG_STR "instance created for %s.\n",
89 inst->id, inst->network ? "network" : "mobile");
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020090}
91
92/* clear instance */
93void gsm411_smr_clear(struct gsm411_smr_inst *inst)
94{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010095 LOGP(DLSMS, LOGL_INFO,
96 SMR_LOG_STR "clearing SMR instance\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020097
98 osmo_timer_del(&inst->rp_timer);
99}
100
Holger Hans Peter Freyther61d33922014-05-23 08:49:34 +0200101static const char *smr_state_names[] = {
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200102 "IDLE",
103 "WAIT_FOR_RP_ACK",
Holger Hans Peter Freytherda73aa62014-05-23 08:51:22 +0200104 "illegal state 2",
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200105 "WAIT_TO_TX_RP_ACK",
106 "WAIT_FOR_RETRANS_T",
107};
108
109const struct value_string gsm411_rp_cause_strs[] = {
110 { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" },
111 { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" },
112 { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" },
113 { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" },
114 { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" },
115 { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" },
116 { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" },
117 { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" },
118 { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" },
119 { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" },
120 { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" },
121 { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" },
122 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" },
123 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" },
124 { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" },
125 /* valid only for MT */
126 { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" },
127 /* valid for both directions */
128 { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" },
129 { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
130 { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
131 { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" },
132 { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" },
133 { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" },
134 { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
135 { 0, NULL }
136};
137
138static void new_rp_state(struct gsm411_smr_inst *inst,
139 enum gsm411_rp_state state)
140{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100141 LOGP(DLSMS, LOGL_INFO,
142 SMR_LOG_STR "new RP state %s -> %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200143 smr_state_names[inst->rp_state], smr_state_names[state]);
144 inst->rp_state = state;
145
146 /* stop timer when going idle */
147 if (state == GSM411_RPS_IDLE)
148 osmo_timer_del(&inst->rp_timer);
149}
150
151/* Prefix msg with a RP-DATA header and send as CP-DATA */
152static int gsm411_rp_sendmsg(struct gsm411_smr_inst *inst, struct msgb *msg,
153 uint8_t rp_msg_type, uint8_t rp_msg_ref,
154 int mnsms_msg_type)
155{
156 struct gsm411_rp_hdr *rp;
157 uint8_t len = msg->len;
158
159 /* GSM 04.11 RP-DATA header */
160 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
161 rp->len = len + 2;
162 rp->msg_type = rp_msg_type;
Holger Hans Peter Freytherf4f5a842014-02-08 15:14:53 +0100163 rp->msg_ref = rp_msg_ref;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200164
165 return inst->mn_send(inst, mnsms_msg_type, msg);
166}
167
168static int gsm411_send_rp_error(struct gsm411_smr_inst *inst,
169 uint8_t msg_ref, uint8_t cause)
170{
171 struct msgb *msg = gsm411_msgb_alloc();
172
173 msgb_tv_put(msg, 1, cause);
174
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100175 LOGP(DLSMS, LOGL_NOTICE,
176 SMR_LOG_STR "TX: SMS RP ERROR, cause %d (%s)\n", inst->id,
177 cause, get_value_string(gsm411_rp_cause_strs, cause));
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200178
179 return gsm411_rp_sendmsg(inst, msg,
180 (inst->network) ? GSM411_MT_RP_ERROR_MT : GSM411_MT_RP_ERROR_MO,
181 msg_ref, GSM411_MNSMS_DATA_REQ);
182}
183
184static int gsm411_send_release(struct gsm411_smr_inst *inst)
185{
186 struct msgb *msg = gsm411_msgb_alloc();
187
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100188 LOGP(DLSMS, LOGL_DEBUG,
189 SMR_LOG_STR "TX: MNSMS-REL-REQ\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200190
191 return inst->mn_send(inst, GSM411_MNSMS_REL_REQ, msg);
192}
193
194static int gsm411_send_abort(struct gsm411_smr_inst *inst)
195{
196 struct msgb *msg = gsm411_msgb_alloc();
197
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100198 LOGP(DLSMS, LOGL_DEBUG,
199 SMR_LOG_STR "TX: MNSMS-ABORT-REQ\n", inst->id);
200
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200201 msgb_tv_put(msg, 1, 111); //FIXME: better idea ? */
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200202
203 return inst->mn_send(inst, GSM411_MNSMS_ABORT_REQ, msg);
204}
205
206static int gsm411_send_report(struct gsm411_smr_inst *inst)
207{
208 struct msgb *msg = gsm411_msgb_alloc();
209
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100210 LOGP(DLSMS, LOGL_DEBUG,
211 SMR_LOG_STR "Sending empty SM_RL_REPORT_IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200212
213 return inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
214}
215
216static int gsm411_rl_data_req(struct gsm411_smr_inst *inst, struct msgb *msg)
217{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100218 LOGP(DLSMS, LOGL_DEBUG,
219 SMR_LOG_STR "TX SMS RP-DATA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200220 /* start TR1N and enter 'wait for RP-ACK state' */
221 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR1M);
222 new_rp_state(inst, GSM411_RPS_WAIT_FOR_RP_ACK);
223
224 return inst->mn_send(inst, GSM411_MNSMS_EST_REQ, msg);
225}
226
227static int gsm411_rl_report_req(struct gsm411_smr_inst *inst, struct msgb *msg)
228{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100229 LOGP(DLSMS, LOGL_DEBUG,
230 SMR_LOG_STR "TX SMS REPORT\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200231 new_rp_state(inst, GSM411_RPS_IDLE);
232
233 inst->mn_send(inst, GSM411_MNSMS_DATA_REQ, msg);
234 gsm411_send_release(inst);
235 return 0;
236}
237
238static int gsm411_mnsms_est_ind(struct gsm411_smr_inst *inst, struct msgb *msg)
239{
240 struct gsm48_hdr *gh = (struct gsm48_hdr*)msg->l3h;
241 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
242 uint8_t msg_type = rp_data->msg_type & 0x07;
243 int rc;
244
245 /* check direction */
246 if (inst->network == (msg_type & 1)) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100247 LOGP(DLSMS, LOGL_NOTICE,
248 SMR_LOG_STR "Invalid RP type 0x%02x\n",
249 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200250 gsm411_send_rp_error(inst, rp_data->msg_ref,
251 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
252 new_rp_state(inst, GSM411_RPS_IDLE);
253 gsm411_send_release(inst);
254 return -EINVAL;
255 }
256
257 switch (msg_type) {
258 case GSM411_MT_RP_DATA_MT:
259 case GSM411_MT_RP_DATA_MO:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100260 LOGP(DLSMS, LOGL_DEBUG,
261 SMR_LOG_STR "RX SMS RP-DATA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200262 /* start TR2N and enter 'wait to send RP-ACK state' */
263 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR2M);
264 new_rp_state(inst, GSM411_RPS_WAIT_TO_TX_RP_ACK);
265 rc = inst->rl_recv(inst, GSM411_SM_RL_DATA_IND, msg);
266 break;
267 case GSM411_MT_RP_SMMA_MO:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100268 LOGP(DLSMS, LOGL_DEBUG,
269 SMR_LOG_STR "RX SMS RP-SMMA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200270 /* start TR2N and enter 'wait to send RP-ACK state' */
271 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR2M);
272 new_rp_state(inst, GSM411_RPS_WAIT_TO_TX_RP_ACK);
273 rc = inst->rl_recv(inst, GSM411_SM_RL_DATA_IND, msg);
274 break;
275 default:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100276 LOGP(DLSMS, LOGL_NOTICE,
277 SMR_LOG_STR "invalid RP type 0x%02x\n",
278 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200279 gsm411_send_rp_error(inst, rp_data->msg_ref,
280 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
281 new_rp_state(inst, GSM411_RPS_IDLE);
282 rc = -EINVAL;
283 break;
284 }
285
286 return rc;
287}
288
289static int gsm411_mnsms_data_ind_tx(struct gsm411_smr_inst *inst,
290 struct msgb *msg)
291{
292 struct gsm48_hdr *gh = (struct gsm48_hdr*)msg->l3h;
293 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
294 uint8_t msg_type = rp_data->msg_type & 0x07;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200295
296 /* check direction */
297 if (inst->network == (msg_type & 1)) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100298 LOGP(DLSMS, LOGL_NOTICE,
299 SMR_LOG_STR "invalid RP type 0x%02x\n",
300 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200301 gsm411_send_rp_error(inst, rp_data->msg_ref,
302 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
303 new_rp_state(inst, GSM411_RPS_IDLE);
304 gsm411_send_release(inst);
305 return -EINVAL;
306 }
307
308 switch (msg_type) {
309 case GSM411_MT_RP_ACK_MO:
310 case GSM411_MT_RP_ACK_MT:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100311 LOGP(DLSMS, LOGL_DEBUG,
312 SMR_LOG_STR "RX SMS RP-ACK\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200313 new_rp_state(inst, GSM411_RPS_IDLE);
314 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
315 gsm411_send_release(inst);
316 return 0;
317 case GSM411_MT_RP_ERROR_MO:
318 case GSM411_MT_RP_ERROR_MT:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100319 LOGP(DLSMS, LOGL_DEBUG,
320 SMR_LOG_STR "RX SMS RP-ERROR\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200321 new_rp_state(inst, GSM411_RPS_IDLE);
322 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
323 gsm411_send_release(inst);
324 return 0;
325 default:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100326 LOGP(DLSMS, LOGL_NOTICE,
327 SMR_LOG_STR "Invalid RP type 0x%02x\n",
328 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200329 gsm411_send_rp_error(inst, rp_data->msg_ref,
330 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
331 new_rp_state(inst, GSM411_RPS_IDLE);
332 gsm411_send_release(inst);
333 return -EINVAL;
334 }
335
Vadim Yanitskiy4c3e4ea2017-05-15 21:32:43 +0300336 return 0;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200337}
338
339static int gsm411_mnsms_error_ind_tx(struct gsm411_smr_inst *inst,
340 struct msgb *msg)
341{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100342 LOGP(DLSMS, LOGL_DEBUG,
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100343 SMR_LOG_STR "TX SMS MNSMS-ERROR-IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200344 new_rp_state(inst, GSM411_RPS_IDLE);
345 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
346 gsm411_send_release(inst);
347 return 0;
348}
349
350static int gsm411_mnsms_error_ind_rx(struct gsm411_smr_inst *inst,
351 struct msgb *msg)
352{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100353 LOGP(DLSMS, LOGL_DEBUG,
354 SMR_LOG_STR "RX SMS MNSMS-ERROR-IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200355 new_rp_state(inst, GSM411_RPS_IDLE);
356 return inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
357}
358
359/* SMR TR1* is expired */
360static void rp_timer_expired(void *data)
361{
362 struct gsm411_smr_inst *inst = data;
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100363 const char *str;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200364
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100365 str = inst->rp_state == GSM411_RPS_WAIT_TO_TX_RP_ACK
366 ? "TR2N" : "TR1N";
367
368 LOGP(DLSMS, LOGL_DEBUG,
369 SMR_LOG_STR "%s expired\n", inst->id, str);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200370 gsm411_send_report(inst);
371 gsm411_send_abort(inst);
372}
373
374/* statefull handling for SM-RL SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100375static const struct smrdownstate {
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200376 uint32_t states;
377 int type;
378 const char *name;
379 int (*rout) (struct gsm411_smr_inst *inst,
380 struct msgb *msg);
381} smrdownstatelist[] = {
382 /* data request */
383 {SBIT(GSM411_RPS_IDLE),
384 GSM411_SM_RL_DATA_REQ,
385 "SM-RL-DATA_REQ", gsm411_rl_data_req},
386
387 /* report request */
388 {SBIT(GSM411_RPS_WAIT_TO_TX_RP_ACK),
389 GSM411_SM_RL_REPORT_REQ,
390 "SM-RL-REPORT_REQ", gsm411_rl_report_req},
391};
392
393#define SMRDOWNSLLEN \
394 (sizeof(smrdownstatelist) / sizeof(struct smrdownstate))
395
396/* message from upper layer */
397int gsm411_smr_send(struct gsm411_smr_inst *inst, int msg_type,
398 struct msgb *msg)
399{
400 int i, rc;
401
402 /* find function for current state and message */
403 for (i = 0; i < SMRDOWNSLLEN; i++) {
404 if ((msg_type == smrdownstatelist[i].type)
405 && (SBIT(inst->rp_state) & smrdownstatelist[i].states))
406 break;
407 }
408 if (i == SMRDOWNSLLEN) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100409 LOGP(DLSMS, LOGL_NOTICE,
410 SMR_LOG_STR "message %u unhandled at this state "
411 "%s.\n", inst->id, msg_type,
412 smr_state_names[inst->rp_state]);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200413 msgb_free(msg);
414 return 0;
415 }
416
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100417 LOGP(DLSMS, LOGL_INFO,
418 SMR_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200419 smrdownstatelist[i].name, smr_state_names[inst->rp_state]);
420
421 rc = smrdownstatelist[i].rout(inst, msg);
422
423 return rc;
424}
425
426/* statefull handling for MMSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100427static const struct smrdatastate {
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200428 uint32_t states;
429 int type;
430 const char *name;
431 int (*rout) (struct gsm411_smr_inst *inst,
432 struct msgb *msg);
433} smrdatastatelist[] = {
434 /* establish indication */
435 {SBIT(GSM411_RPS_IDLE),
436 GSM411_MNSMS_EST_IND,
437 "MNSMS-EST-IND", gsm411_mnsms_est_ind},
438
439 /* data indication */
440 {SBIT(GSM411_RPS_WAIT_FOR_RP_ACK),
441 GSM411_MNSMS_DATA_IND,
442 "MNSMS-DATA-IND", gsm411_mnsms_data_ind_tx},
443
444 /* error indication */
445 {SBIT(GSM411_RPS_WAIT_FOR_RP_ACK),
446 GSM411_MNSMS_ERROR_IND,
447 "MNSMS-ERROR-IND", gsm411_mnsms_error_ind_tx},
448
449 /* error indication */
450 {SBIT(GSM411_RPS_WAIT_TO_TX_RP_ACK),
451 GSM411_MNSMS_ERROR_IND,
452 "MNSMS-ERROR-IND", gsm411_mnsms_error_ind_rx},
453
454};
455
456#define SMRDATASLLEN \
457 (sizeof(smrdatastatelist) / sizeof(struct smrdatastate))
458
459/* message from lower layer
460 * WARNING: We must not free msg, since it will be performed by the
461 * lower layer. */
462int gsm411_smr_recv(struct gsm411_smr_inst *inst, int msg_type,
463 struct msgb *msg)
464{
465 int i, rc;
466
467 /* find function for current state and message */
468 for (i = 0; i < SMRDATASLLEN; i++) {
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100469 /* state must match, MM message must match
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200470 * CP msg must match only in case of MMSMS_DATA_IND
471 */
472 if ((msg_type == smrdatastatelist[i].type)
473 && (SBIT(inst->rp_state) & smrdatastatelist[i].states))
474 break;
475 }
476 if (i == SMRDATASLLEN) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100477 LOGP(DLSMS, LOGL_NOTICE,
478 SMR_LOG_STR "message %u unhandled at this state "
479 "%s.\n", inst->id, msg_type,
480 smr_state_names[inst->rp_state]);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200481 return 0;
482 }
483
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100484 LOGP(DLSMS, LOGL_INFO,
485 SMR_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200486 smrdatastatelist[i].name, smr_state_names[inst->rp_state]);
487
488 rc = smrdatastatelist[i].rout(inst, msg);
489
490 return rc;
491}
Harald Welte96e2a002017-06-12 21:44:18 +0200492
493/*! @} */