blob: 21d28c51612f3afe816788887d62e1a0f575fd3f [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 *
Harald Weltee08da972017-11-13 01:00:26 +090013 * SPDX-License-Identifier: GPL-2.0+
14 *
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020015 * This program is free software; you can redistribute it and/or modify
Harald Welte388fb032014-10-26 20:42:49 +010016 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020018 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte388fb032014-10-26 20:42:49 +010023 * GNU General Public License for more details.
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020024 *
Harald Welte388fb032014-10-26 20:42:49 +010025 * You should have received a copy of the GNU General Public License
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020026 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *
28 */
29
30/* Notes on msg:
31 *
32 * Messages from lower layer are freed by lower layer.
33 *
34 * Messages to upper layer are freed after upper layer call returns, so upper
35 * layer cannot use data after returning. Upper layer must not free the msg.
36 *
37 * This implies: Lower layer messages can be forwarded to upper layer.
38 *
39 * Upper layer messages are freed by lower layer, so they must not be freed
40 * after calling lower layer.
41 *
42 *
43 * Notes on release:
44 *
45 * Sending Abort/Release (MNSMS-ABORT-REQ or MNSMS-REL-REQ) may cause the
46 * lower layer to become IDLE. Then it is allowed to destroy this instance,
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +010047 * so sending this MUST be the last thing that is done.
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020048 *
49 */
50
51
52#include <string.h>
53#include <errno.h>
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010054#include <inttypes.h>
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020055#include <osmocom/core/msgb.h>
56#include <osmocom/core/logging.h>
57#include <osmocom/core/timer.h>
58#include <osmocom/gsm/tlv.h>
59
60#include <osmocom/gsm/gsm0411_utils.h>
61#include <osmocom/gsm/gsm0411_smc.h>
62#include <osmocom/gsm/gsm0411_smr.h>
63#include <osmocom/gsm/protocol/gsm_04_08.h>
64
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010065#define SMR_LOG_STR "SMR(%" PRIu64 ") "
66
Harald Welte96e2a002017-06-12 21:44:18 +020067/*! \addtogroup sms
68 * @{
Harald Welte55d724a2017-10-16 18:25:45 +020069 * \file gsm0411_smr.c
Harald Welte96e2a002017-06-12 21:44:18 +020070 */
71
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020072static void rp_timer_expired(void *data);
73
74/* init a new instance */
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010075void gsm411_smr_init(struct gsm411_smr_inst *inst, uint64_t id, int network,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020076 int (*rl_recv) (struct gsm411_smr_inst *inst, int msg_type,
77 struct msgb *msg),
78 int (*mn_send) (struct gsm411_smr_inst *inst, int msg_type,
79 struct msgb *msg))
80{
81 memset(inst, 0, sizeof(*inst));
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010082 inst->id = id;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020083 inst->network = network;
84 inst->rp_state = GSM411_RPS_IDLE;
85 inst->rl_recv = rl_recv;
86 inst->mn_send = mn_send;
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +020087 osmo_timer_setup(&inst->rp_timer, rp_timer_expired, inst);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020088
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010089 LOGP(DLSMS, LOGL_INFO,
Holger Hans Peter Freyther68f94472012-12-01 12:51:34 +010090 SMR_LOG_STR "instance created for %s.\n",
91 inst->id, inst->network ? "network" : "mobile");
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020092}
93
94/* clear instance */
95void gsm411_smr_clear(struct gsm411_smr_inst *inst)
96{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010097 LOGP(DLSMS, LOGL_INFO,
98 SMR_LOG_STR "clearing SMR instance\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020099
100 osmo_timer_del(&inst->rp_timer);
101}
102
Holger Hans Peter Freyther61d33922014-05-23 08:49:34 +0200103static const char *smr_state_names[] = {
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200104 "IDLE",
105 "WAIT_FOR_RP_ACK",
Holger Hans Peter Freytherda73aa62014-05-23 08:51:22 +0200106 "illegal state 2",
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200107 "WAIT_TO_TX_RP_ACK",
108 "WAIT_FOR_RETRANS_T",
109};
110
111const struct value_string gsm411_rp_cause_strs[] = {
112 { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" },
113 { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" },
114 { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" },
115 { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" },
116 { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" },
117 { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" },
118 { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" },
119 { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" },
120 { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" },
121 { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" },
122 { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" },
123 { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" },
124 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" },
125 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" },
126 { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" },
127 /* valid only for MT */
128 { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" },
129 /* valid for both directions */
130 { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" },
131 { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
132 { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
133 { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" },
134 { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" },
135 { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" },
136 { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
137 { 0, NULL }
138};
139
140static void new_rp_state(struct gsm411_smr_inst *inst,
141 enum gsm411_rp_state state)
142{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100143 LOGP(DLSMS, LOGL_INFO,
144 SMR_LOG_STR "new RP state %s -> %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200145 smr_state_names[inst->rp_state], smr_state_names[state]);
146 inst->rp_state = state;
147
148 /* stop timer when going idle */
149 if (state == GSM411_RPS_IDLE)
150 osmo_timer_del(&inst->rp_timer);
151}
152
153/* Prefix msg with a RP-DATA header and send as CP-DATA */
154static int gsm411_rp_sendmsg(struct gsm411_smr_inst *inst, struct msgb *msg,
155 uint8_t rp_msg_type, uint8_t rp_msg_ref,
156 int mnsms_msg_type)
157{
158 struct gsm411_rp_hdr *rp;
159 uint8_t len = msg->len;
160
161 /* GSM 04.11 RP-DATA header */
162 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
163 rp->len = len + 2;
164 rp->msg_type = rp_msg_type;
Holger Hans Peter Freytherf4f5a842014-02-08 15:14:53 +0100165 rp->msg_ref = rp_msg_ref;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200166
167 return inst->mn_send(inst, mnsms_msg_type, msg);
168}
169
170static int gsm411_send_rp_error(struct gsm411_smr_inst *inst,
171 uint8_t msg_ref, uint8_t cause)
172{
173 struct msgb *msg = gsm411_msgb_alloc();
174
175 msgb_tv_put(msg, 1, cause);
176
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100177 LOGP(DLSMS, LOGL_NOTICE,
178 SMR_LOG_STR "TX: SMS RP ERROR, cause %d (%s)\n", inst->id,
179 cause, get_value_string(gsm411_rp_cause_strs, cause));
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200180
181 return gsm411_rp_sendmsg(inst, msg,
182 (inst->network) ? GSM411_MT_RP_ERROR_MT : GSM411_MT_RP_ERROR_MO,
183 msg_ref, GSM411_MNSMS_DATA_REQ);
184}
185
186static int gsm411_send_release(struct gsm411_smr_inst *inst)
187{
188 struct msgb *msg = gsm411_msgb_alloc();
189
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100190 LOGP(DLSMS, LOGL_DEBUG,
191 SMR_LOG_STR "TX: MNSMS-REL-REQ\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200192
193 return inst->mn_send(inst, GSM411_MNSMS_REL_REQ, msg);
194}
195
196static int gsm411_send_abort(struct gsm411_smr_inst *inst)
197{
198 struct msgb *msg = gsm411_msgb_alloc();
199
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100200 LOGP(DLSMS, LOGL_DEBUG,
201 SMR_LOG_STR "TX: MNSMS-ABORT-REQ\n", inst->id);
202
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200203 msgb_tv_put(msg, 1, 111); //FIXME: better idea ? */
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200204
205 return inst->mn_send(inst, GSM411_MNSMS_ABORT_REQ, msg);
206}
207
208static int gsm411_send_report(struct gsm411_smr_inst *inst)
209{
210 struct msgb *msg = gsm411_msgb_alloc();
211
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100212 LOGP(DLSMS, LOGL_DEBUG,
213 SMR_LOG_STR "Sending empty SM_RL_REPORT_IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200214
215 return inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
216}
217
218static int gsm411_rl_data_req(struct gsm411_smr_inst *inst, struct msgb *msg)
219{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100220 LOGP(DLSMS, LOGL_DEBUG,
221 SMR_LOG_STR "TX SMS RP-DATA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200222 /* start TR1N and enter 'wait for RP-ACK state' */
223 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR1M);
224 new_rp_state(inst, GSM411_RPS_WAIT_FOR_RP_ACK);
225
226 return inst->mn_send(inst, GSM411_MNSMS_EST_REQ, msg);
227}
228
229static int gsm411_rl_report_req(struct gsm411_smr_inst *inst, struct msgb *msg)
230{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100231 LOGP(DLSMS, LOGL_DEBUG,
232 SMR_LOG_STR "TX SMS REPORT\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200233 new_rp_state(inst, GSM411_RPS_IDLE);
234
235 inst->mn_send(inst, GSM411_MNSMS_DATA_REQ, msg);
236 gsm411_send_release(inst);
237 return 0;
238}
239
240static int gsm411_mnsms_est_ind(struct gsm411_smr_inst *inst, struct msgb *msg)
241{
242 struct gsm48_hdr *gh = (struct gsm48_hdr*)msg->l3h;
243 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
244 uint8_t msg_type = rp_data->msg_type & 0x07;
245 int rc;
246
247 /* check direction */
248 if (inst->network == (msg_type & 1)) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100249 LOGP(DLSMS, LOGL_NOTICE,
250 SMR_LOG_STR "Invalid RP type 0x%02x\n",
251 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200252 gsm411_send_rp_error(inst, rp_data->msg_ref,
253 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
254 new_rp_state(inst, GSM411_RPS_IDLE);
255 gsm411_send_release(inst);
256 return -EINVAL;
257 }
258
259 switch (msg_type) {
260 case GSM411_MT_RP_DATA_MT:
261 case GSM411_MT_RP_DATA_MO:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100262 LOGP(DLSMS, LOGL_DEBUG,
263 SMR_LOG_STR "RX SMS RP-DATA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200264 /* start TR2N and enter 'wait to send RP-ACK state' */
265 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR2M);
266 new_rp_state(inst, GSM411_RPS_WAIT_TO_TX_RP_ACK);
267 rc = inst->rl_recv(inst, GSM411_SM_RL_DATA_IND, msg);
268 break;
269 case GSM411_MT_RP_SMMA_MO:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100270 LOGP(DLSMS, LOGL_DEBUG,
271 SMR_LOG_STR "RX SMS RP-SMMA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200272 /* start TR2N and enter 'wait to send RP-ACK state' */
273 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR2M);
274 new_rp_state(inst, GSM411_RPS_WAIT_TO_TX_RP_ACK);
275 rc = inst->rl_recv(inst, GSM411_SM_RL_DATA_IND, msg);
276 break;
277 default:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100278 LOGP(DLSMS, LOGL_NOTICE,
279 SMR_LOG_STR "invalid RP type 0x%02x\n",
280 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200281 gsm411_send_rp_error(inst, rp_data->msg_ref,
282 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
283 new_rp_state(inst, GSM411_RPS_IDLE);
284 rc = -EINVAL;
285 break;
286 }
287
288 return rc;
289}
290
291static int gsm411_mnsms_data_ind_tx(struct gsm411_smr_inst *inst,
292 struct msgb *msg)
293{
294 struct gsm48_hdr *gh = (struct gsm48_hdr*)msg->l3h;
295 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
296 uint8_t msg_type = rp_data->msg_type & 0x07;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200297
298 /* check direction */
299 if (inst->network == (msg_type & 1)) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100300 LOGP(DLSMS, LOGL_NOTICE,
301 SMR_LOG_STR "invalid RP type 0x%02x\n",
302 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200303 gsm411_send_rp_error(inst, rp_data->msg_ref,
304 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
305 new_rp_state(inst, GSM411_RPS_IDLE);
306 gsm411_send_release(inst);
307 return -EINVAL;
308 }
309
310 switch (msg_type) {
311 case GSM411_MT_RP_ACK_MO:
312 case GSM411_MT_RP_ACK_MT:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100313 LOGP(DLSMS, LOGL_DEBUG,
314 SMR_LOG_STR "RX SMS RP-ACK\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200315 new_rp_state(inst, GSM411_RPS_IDLE);
316 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
317 gsm411_send_release(inst);
318 return 0;
319 case GSM411_MT_RP_ERROR_MO:
320 case GSM411_MT_RP_ERROR_MT:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100321 LOGP(DLSMS, LOGL_DEBUG,
322 SMR_LOG_STR "RX SMS RP-ERROR\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200323 new_rp_state(inst, GSM411_RPS_IDLE);
324 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
325 gsm411_send_release(inst);
326 return 0;
327 default:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100328 LOGP(DLSMS, LOGL_NOTICE,
329 SMR_LOG_STR "Invalid RP type 0x%02x\n",
330 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200331 gsm411_send_rp_error(inst, rp_data->msg_ref,
332 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
333 new_rp_state(inst, GSM411_RPS_IDLE);
334 gsm411_send_release(inst);
335 return -EINVAL;
336 }
337
Vadim Yanitskiy4c3e4ea2017-05-15 21:32:43 +0300338 return 0;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200339}
340
341static int gsm411_mnsms_error_ind_tx(struct gsm411_smr_inst *inst,
342 struct msgb *msg)
343{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100344 LOGP(DLSMS, LOGL_DEBUG,
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100345 SMR_LOG_STR "TX SMS MNSMS-ERROR-IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200346 new_rp_state(inst, GSM411_RPS_IDLE);
347 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
348 gsm411_send_release(inst);
349 return 0;
350}
351
352static int gsm411_mnsms_error_ind_rx(struct gsm411_smr_inst *inst,
353 struct msgb *msg)
354{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100355 LOGP(DLSMS, LOGL_DEBUG,
356 SMR_LOG_STR "RX SMS MNSMS-ERROR-IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200357 new_rp_state(inst, GSM411_RPS_IDLE);
358 return inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
359}
360
361/* SMR TR1* is expired */
362static void rp_timer_expired(void *data)
363{
364 struct gsm411_smr_inst *inst = data;
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100365 const char *str;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200366
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100367 str = inst->rp_state == GSM411_RPS_WAIT_TO_TX_RP_ACK
368 ? "TR2N" : "TR1N";
369
370 LOGP(DLSMS, LOGL_DEBUG,
371 SMR_LOG_STR "%s expired\n", inst->id, str);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200372 gsm411_send_report(inst);
373 gsm411_send_abort(inst);
374}
375
376/* statefull handling for SM-RL SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100377static const struct smrdownstate {
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200378 uint32_t states;
379 int type;
380 const char *name;
381 int (*rout) (struct gsm411_smr_inst *inst,
382 struct msgb *msg);
383} smrdownstatelist[] = {
384 /* data request */
385 {SBIT(GSM411_RPS_IDLE),
386 GSM411_SM_RL_DATA_REQ,
387 "SM-RL-DATA_REQ", gsm411_rl_data_req},
388
389 /* report request */
390 {SBIT(GSM411_RPS_WAIT_TO_TX_RP_ACK),
391 GSM411_SM_RL_REPORT_REQ,
392 "SM-RL-REPORT_REQ", gsm411_rl_report_req},
393};
394
395#define SMRDOWNSLLEN \
396 (sizeof(smrdownstatelist) / sizeof(struct smrdownstate))
397
398/* message from upper layer */
399int gsm411_smr_send(struct gsm411_smr_inst *inst, int msg_type,
400 struct msgb *msg)
401{
402 int i, rc;
403
404 /* find function for current state and message */
405 for (i = 0; i < SMRDOWNSLLEN; i++) {
406 if ((msg_type == smrdownstatelist[i].type)
407 && (SBIT(inst->rp_state) & smrdownstatelist[i].states))
408 break;
409 }
410 if (i == SMRDOWNSLLEN) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100411 LOGP(DLSMS, LOGL_NOTICE,
412 SMR_LOG_STR "message %u unhandled at this state "
413 "%s.\n", inst->id, msg_type,
414 smr_state_names[inst->rp_state]);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200415 msgb_free(msg);
416 return 0;
417 }
418
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100419 LOGP(DLSMS, LOGL_INFO,
420 SMR_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200421 smrdownstatelist[i].name, smr_state_names[inst->rp_state]);
422
423 rc = smrdownstatelist[i].rout(inst, msg);
424
425 return rc;
426}
427
428/* statefull handling for MMSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100429static const struct smrdatastate {
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200430 uint32_t states;
431 int type;
432 const char *name;
433 int (*rout) (struct gsm411_smr_inst *inst,
434 struct msgb *msg);
435} smrdatastatelist[] = {
436 /* establish indication */
437 {SBIT(GSM411_RPS_IDLE),
438 GSM411_MNSMS_EST_IND,
439 "MNSMS-EST-IND", gsm411_mnsms_est_ind},
440
441 /* data indication */
442 {SBIT(GSM411_RPS_WAIT_FOR_RP_ACK),
443 GSM411_MNSMS_DATA_IND,
444 "MNSMS-DATA-IND", gsm411_mnsms_data_ind_tx},
445
446 /* error indication */
447 {SBIT(GSM411_RPS_WAIT_FOR_RP_ACK),
448 GSM411_MNSMS_ERROR_IND,
449 "MNSMS-ERROR-IND", gsm411_mnsms_error_ind_tx},
450
451 /* error indication */
452 {SBIT(GSM411_RPS_WAIT_TO_TX_RP_ACK),
453 GSM411_MNSMS_ERROR_IND,
454 "MNSMS-ERROR-IND", gsm411_mnsms_error_ind_rx},
455
456};
457
458#define SMRDATASLLEN \
459 (sizeof(smrdatastatelist) / sizeof(struct smrdatastate))
460
461/* message from lower layer
462 * WARNING: We must not free msg, since it will be performed by the
463 * lower layer. */
464int gsm411_smr_recv(struct gsm411_smr_inst *inst, int msg_type,
465 struct msgb *msg)
466{
467 int i, rc;
468
469 /* find function for current state and message */
470 for (i = 0; i < SMRDATASLLEN; i++) {
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100471 /* state must match, MM message must match
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200472 * CP msg must match only in case of MMSMS_DATA_IND
473 */
474 if ((msg_type == smrdatastatelist[i].type)
475 && (SBIT(inst->rp_state) & smrdatastatelist[i].states))
476 break;
477 }
478 if (i == SMRDATASLLEN) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100479 LOGP(DLSMS, LOGL_NOTICE,
480 SMR_LOG_STR "message %u unhandled at this state "
481 "%s.\n", inst->id, msg_type,
482 smr_state_names[inst->rp_state]);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200483 return 0;
484 }
485
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100486 LOGP(DLSMS, LOGL_INFO,
487 SMR_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200488 smrdatastatelist[i].name, smr_state_names[inst->rp_state]);
489
490 rc = smrdatastatelist[i].rout(inst, msg);
491
492 return rc;
493}
Harald Welte96e2a002017-06-12 21:44:18 +0200494
Harald Welted60e17a2018-01-24 16:50:11 +0100495const struct value_string gsm411_rp_state_names[] = {
496 { GSM411_RPS_IDLE, "IDLE" },
497 { GSM411_RPS_WAIT_FOR_RP_ACK, "WAIT_FOR_RP_ACK" },
498 { GSM411_RPS_WAIT_TO_TX_RP_ACK, "WAIT_TO_TX_RP_ACK" },
499 { GSM411_RPS_WAIT_FOR_RETRANS_T,"WAIT_FOR_RETRANS_T" },
500 { 0, NULL }
501};
Harald Welte96e2a002017-06-12 21:44:18 +0200502/*! @} */