blob: b243c863aa2a95657269241341eeccda6e82d43a [file] [log] [blame]
Andreas Eversbergc1a91a82011-10-28 11:05: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 * 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
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020065static void rp_timer_expired(void *data);
66
67/* init a new instance */
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010068void gsm411_smr_init(struct gsm411_smr_inst *inst, uint64_t id, int network,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020069 int (*rl_recv) (struct gsm411_smr_inst *inst, int msg_type,
70 struct msgb *msg),
71 int (*mn_send) (struct gsm411_smr_inst *inst, int msg_type,
72 struct msgb *msg))
73{
74 memset(inst, 0, sizeof(*inst));
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010075 inst->id = id;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020076 inst->network = network;
77 inst->rp_state = GSM411_RPS_IDLE;
78 inst->rl_recv = rl_recv;
79 inst->mn_send = mn_send;
80 inst->rp_timer.data = inst;
81 inst->rp_timer.cb = rp_timer_expired;
82
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010083 LOGP(DLSMS, LOGL_INFO,
Holger Hans Peter Freyther68f94472012-12-01 12:51:34 +010084 SMR_LOG_STR "instance created for %s.\n",
85 inst->id, inst->network ? "network" : "mobile");
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020086}
87
88/* clear instance */
89void gsm411_smr_clear(struct gsm411_smr_inst *inst)
90{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +010091 LOGP(DLSMS, LOGL_INFO,
92 SMR_LOG_STR "clearing SMR instance\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +020093
94 osmo_timer_del(&inst->rp_timer);
95}
96
97const char *smr_state_names[] = {
98 "IDLE",
99 "WAIT_FOR_RP_ACK",
100 "illegal state 2"
101 "WAIT_TO_TX_RP_ACK",
102 "WAIT_FOR_RETRANS_T",
103};
104
105const struct value_string gsm411_rp_cause_strs[] = {
106 { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" },
107 { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" },
108 { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" },
109 { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" },
110 { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" },
111 { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" },
112 { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" },
113 { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" },
114 { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" },
115 { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" },
116 { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" },
117 { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" },
118 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" },
119 { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" },
120 { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" },
121 /* valid only for MT */
122 { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" },
123 /* valid for both directions */
124 { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" },
125 { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
126 { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
127 { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" },
128 { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" },
129 { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" },
130 { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
131 { 0, NULL }
132};
133
134static void new_rp_state(struct gsm411_smr_inst *inst,
135 enum gsm411_rp_state state)
136{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100137 LOGP(DLSMS, LOGL_INFO,
138 SMR_LOG_STR "new RP state %s -> %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200139 smr_state_names[inst->rp_state], smr_state_names[state]);
140 inst->rp_state = state;
141
142 /* stop timer when going idle */
143 if (state == GSM411_RPS_IDLE)
144 osmo_timer_del(&inst->rp_timer);
145}
146
147/* Prefix msg with a RP-DATA header and send as CP-DATA */
148static int gsm411_rp_sendmsg(struct gsm411_smr_inst *inst, struct msgb *msg,
149 uint8_t rp_msg_type, uint8_t rp_msg_ref,
150 int mnsms_msg_type)
151{
152 struct gsm411_rp_hdr *rp;
153 uint8_t len = msg->len;
154
155 /* GSM 04.11 RP-DATA header */
156 rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp));
157 rp->len = len + 2;
158 rp->msg_type = rp_msg_type;
Holger Hans Peter Freytherf4f5a842014-02-08 15:14:53 +0100159 rp->msg_ref = rp_msg_ref;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200160
161 return inst->mn_send(inst, mnsms_msg_type, msg);
162}
163
164static int gsm411_send_rp_error(struct gsm411_smr_inst *inst,
165 uint8_t msg_ref, uint8_t cause)
166{
167 struct msgb *msg = gsm411_msgb_alloc();
168
169 msgb_tv_put(msg, 1, cause);
170
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100171 LOGP(DLSMS, LOGL_NOTICE,
172 SMR_LOG_STR "TX: SMS RP ERROR, cause %d (%s)\n", inst->id,
173 cause, get_value_string(gsm411_rp_cause_strs, cause));
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200174
175 return gsm411_rp_sendmsg(inst, msg,
176 (inst->network) ? GSM411_MT_RP_ERROR_MT : GSM411_MT_RP_ERROR_MO,
177 msg_ref, GSM411_MNSMS_DATA_REQ);
178}
179
180static int gsm411_send_release(struct gsm411_smr_inst *inst)
181{
182 struct msgb *msg = gsm411_msgb_alloc();
183
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100184 LOGP(DLSMS, LOGL_DEBUG,
185 SMR_LOG_STR "TX: MNSMS-REL-REQ\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200186
187 return inst->mn_send(inst, GSM411_MNSMS_REL_REQ, msg);
188}
189
190static int gsm411_send_abort(struct gsm411_smr_inst *inst)
191{
192 struct msgb *msg = gsm411_msgb_alloc();
193
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100194 LOGP(DLSMS, LOGL_DEBUG,
195 SMR_LOG_STR "TX: MNSMS-ABORT-REQ\n", inst->id);
196
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200197 msgb_tv_put(msg, 1, 111); //FIXME: better idea ? */
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200198
199 return inst->mn_send(inst, GSM411_MNSMS_ABORT_REQ, msg);
200}
201
202static int gsm411_send_report(struct gsm411_smr_inst *inst)
203{
204 struct msgb *msg = gsm411_msgb_alloc();
205
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100206 LOGP(DLSMS, LOGL_DEBUG,
207 SMR_LOG_STR "Sending empty SM_RL_REPORT_IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200208
209 return inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
210}
211
212static int gsm411_rl_data_req(struct gsm411_smr_inst *inst, struct msgb *msg)
213{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100214 LOGP(DLSMS, LOGL_DEBUG,
215 SMR_LOG_STR "TX SMS RP-DATA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200216 /* start TR1N and enter 'wait for RP-ACK state' */
217 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR1M);
218 new_rp_state(inst, GSM411_RPS_WAIT_FOR_RP_ACK);
219
220 return inst->mn_send(inst, GSM411_MNSMS_EST_REQ, msg);
221}
222
223static int gsm411_rl_report_req(struct gsm411_smr_inst *inst, struct msgb *msg)
224{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100225 LOGP(DLSMS, LOGL_DEBUG,
226 SMR_LOG_STR "TX SMS REPORT\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200227 new_rp_state(inst, GSM411_RPS_IDLE);
228
229 inst->mn_send(inst, GSM411_MNSMS_DATA_REQ, msg);
230 gsm411_send_release(inst);
231 return 0;
232}
233
234static int gsm411_mnsms_est_ind(struct gsm411_smr_inst *inst, struct msgb *msg)
235{
236 struct gsm48_hdr *gh = (struct gsm48_hdr*)msg->l3h;
237 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
238 uint8_t msg_type = rp_data->msg_type & 0x07;
239 int rc;
240
241 /* check direction */
242 if (inst->network == (msg_type & 1)) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100243 LOGP(DLSMS, LOGL_NOTICE,
244 SMR_LOG_STR "Invalid RP type 0x%02x\n",
245 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200246 gsm411_send_rp_error(inst, rp_data->msg_ref,
247 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
248 new_rp_state(inst, GSM411_RPS_IDLE);
249 gsm411_send_release(inst);
250 return -EINVAL;
251 }
252
253 switch (msg_type) {
254 case GSM411_MT_RP_DATA_MT:
255 case GSM411_MT_RP_DATA_MO:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100256 LOGP(DLSMS, LOGL_DEBUG,
257 SMR_LOG_STR "RX SMS RP-DATA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200258 /* start TR2N and enter 'wait to send RP-ACK state' */
259 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR2M);
260 new_rp_state(inst, GSM411_RPS_WAIT_TO_TX_RP_ACK);
261 rc = inst->rl_recv(inst, GSM411_SM_RL_DATA_IND, msg);
262 break;
263 case GSM411_MT_RP_SMMA_MO:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100264 LOGP(DLSMS, LOGL_DEBUG,
265 SMR_LOG_STR "RX SMS RP-SMMA\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200266 /* start TR2N and enter 'wait to send RP-ACK state' */
267 osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR2M);
268 new_rp_state(inst, GSM411_RPS_WAIT_TO_TX_RP_ACK);
269 rc = inst->rl_recv(inst, GSM411_SM_RL_DATA_IND, msg);
270 break;
271 default:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100272 LOGP(DLSMS, LOGL_NOTICE,
273 SMR_LOG_STR "invalid RP type 0x%02x\n",
274 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200275 gsm411_send_rp_error(inst, rp_data->msg_ref,
276 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
277 new_rp_state(inst, GSM411_RPS_IDLE);
278 rc = -EINVAL;
279 break;
280 }
281
282 return rc;
283}
284
285static int gsm411_mnsms_data_ind_tx(struct gsm411_smr_inst *inst,
286 struct msgb *msg)
287{
288 struct gsm48_hdr *gh = (struct gsm48_hdr*)msg->l3h;
289 struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
290 uint8_t msg_type = rp_data->msg_type & 0x07;
291 int rc;
292
293 /* check direction */
294 if (inst->network == (msg_type & 1)) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100295 LOGP(DLSMS, LOGL_NOTICE,
296 SMR_LOG_STR "invalid RP type 0x%02x\n",
297 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200298 gsm411_send_rp_error(inst, rp_data->msg_ref,
299 GSM411_RP_CAUSE_MSG_INCOMP_STATE);
300 new_rp_state(inst, GSM411_RPS_IDLE);
301 gsm411_send_release(inst);
302 return -EINVAL;
303 }
304
305 switch (msg_type) {
306 case GSM411_MT_RP_ACK_MO:
307 case GSM411_MT_RP_ACK_MT:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100308 LOGP(DLSMS, LOGL_DEBUG,
309 SMR_LOG_STR "RX SMS RP-ACK\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200310 new_rp_state(inst, GSM411_RPS_IDLE);
311 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
312 gsm411_send_release(inst);
313 return 0;
314 case GSM411_MT_RP_ERROR_MO:
315 case GSM411_MT_RP_ERROR_MT:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100316 LOGP(DLSMS, LOGL_DEBUG,
317 SMR_LOG_STR "RX SMS RP-ERROR\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200318 new_rp_state(inst, GSM411_RPS_IDLE);
319 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
320 gsm411_send_release(inst);
321 return 0;
322 default:
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100323 LOGP(DLSMS, LOGL_NOTICE,
324 SMR_LOG_STR "Invalid RP type 0x%02x\n",
325 inst->id, msg_type);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200326 gsm411_send_rp_error(inst, rp_data->msg_ref,
327 GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
328 new_rp_state(inst, GSM411_RPS_IDLE);
329 gsm411_send_release(inst);
330 return -EINVAL;
331 }
332
333 return rc;
334}
335
336static int gsm411_mnsms_error_ind_tx(struct gsm411_smr_inst *inst,
337 struct msgb *msg)
338{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100339 LOGP(DLSMS, LOGL_DEBUG,
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100340 SMR_LOG_STR "TX SMS MNSMS-ERROR-IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200341 new_rp_state(inst, GSM411_RPS_IDLE);
342 inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
343 gsm411_send_release(inst);
344 return 0;
345}
346
347static int gsm411_mnsms_error_ind_rx(struct gsm411_smr_inst *inst,
348 struct msgb *msg)
349{
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100350 LOGP(DLSMS, LOGL_DEBUG,
351 SMR_LOG_STR "RX SMS MNSMS-ERROR-IND\n", inst->id);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200352 new_rp_state(inst, GSM411_RPS_IDLE);
353 return inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg);
354}
355
356/* SMR TR1* is expired */
357static void rp_timer_expired(void *data)
358{
359 struct gsm411_smr_inst *inst = data;
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100360 const char *str;
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200361
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100362 str = inst->rp_state == GSM411_RPS_WAIT_TO_TX_RP_ACK
363 ? "TR2N" : "TR1N";
364
365 LOGP(DLSMS, LOGL_DEBUG,
366 SMR_LOG_STR "%s expired\n", inst->id, str);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200367 gsm411_send_report(inst);
368 gsm411_send_abort(inst);
369}
370
371/* statefull handling for SM-RL SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100372static const struct smrdownstate {
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200373 uint32_t states;
374 int type;
375 const char *name;
376 int (*rout) (struct gsm411_smr_inst *inst,
377 struct msgb *msg);
378} smrdownstatelist[] = {
379 /* data request */
380 {SBIT(GSM411_RPS_IDLE),
381 GSM411_SM_RL_DATA_REQ,
382 "SM-RL-DATA_REQ", gsm411_rl_data_req},
383
384 /* report request */
385 {SBIT(GSM411_RPS_WAIT_TO_TX_RP_ACK),
386 GSM411_SM_RL_REPORT_REQ,
387 "SM-RL-REPORT_REQ", gsm411_rl_report_req},
388};
389
390#define SMRDOWNSLLEN \
391 (sizeof(smrdownstatelist) / sizeof(struct smrdownstate))
392
393/* message from upper layer */
394int gsm411_smr_send(struct gsm411_smr_inst *inst, int msg_type,
395 struct msgb *msg)
396{
397 int i, rc;
398
399 /* find function for current state and message */
400 for (i = 0; i < SMRDOWNSLLEN; i++) {
401 if ((msg_type == smrdownstatelist[i].type)
402 && (SBIT(inst->rp_state) & smrdownstatelist[i].states))
403 break;
404 }
405 if (i == SMRDOWNSLLEN) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100406 LOGP(DLSMS, LOGL_NOTICE,
407 SMR_LOG_STR "message %u unhandled at this state "
408 "%s.\n", inst->id, msg_type,
409 smr_state_names[inst->rp_state]);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200410 msgb_free(msg);
411 return 0;
412 }
413
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100414 LOGP(DLSMS, LOGL_INFO,
415 SMR_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200416 smrdownstatelist[i].name, smr_state_names[inst->rp_state]);
417
418 rc = smrdownstatelist[i].rout(inst, msg);
419
420 return rc;
421}
422
423/* statefull handling for MMSMS SAP messages */
Holger Hans Peter Freyther9473c5d2012-11-22 10:50:52 +0100424static const struct smrdatastate {
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200425 uint32_t states;
426 int type;
427 const char *name;
428 int (*rout) (struct gsm411_smr_inst *inst,
429 struct msgb *msg);
430} smrdatastatelist[] = {
431 /* establish indication */
432 {SBIT(GSM411_RPS_IDLE),
433 GSM411_MNSMS_EST_IND,
434 "MNSMS-EST-IND", gsm411_mnsms_est_ind},
435
436 /* data indication */
437 {SBIT(GSM411_RPS_WAIT_FOR_RP_ACK),
438 GSM411_MNSMS_DATA_IND,
439 "MNSMS-DATA-IND", gsm411_mnsms_data_ind_tx},
440
441 /* error indication */
442 {SBIT(GSM411_RPS_WAIT_FOR_RP_ACK),
443 GSM411_MNSMS_ERROR_IND,
444 "MNSMS-ERROR-IND", gsm411_mnsms_error_ind_tx},
445
446 /* error indication */
447 {SBIT(GSM411_RPS_WAIT_TO_TX_RP_ACK),
448 GSM411_MNSMS_ERROR_IND,
449 "MNSMS-ERROR-IND", gsm411_mnsms_error_ind_rx},
450
451};
452
453#define SMRDATASLLEN \
454 (sizeof(smrdatastatelist) / sizeof(struct smrdatastate))
455
456/* message from lower layer
457 * WARNING: We must not free msg, since it will be performed by the
458 * lower layer. */
459int gsm411_smr_recv(struct gsm411_smr_inst *inst, int msg_type,
460 struct msgb *msg)
461{
462 int i, rc;
463
464 /* find function for current state and message */
465 for (i = 0; i < SMRDATASLLEN; i++) {
Holger Hans Peter Freyther1c4c3732012-11-22 00:33:52 +0100466 /* state must match, MM message must match
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200467 * CP msg must match only in case of MMSMS_DATA_IND
468 */
469 if ((msg_type == smrdatastatelist[i].type)
470 && (SBIT(inst->rp_state) & smrdatastatelist[i].states))
471 break;
472 }
473 if (i == SMRDATASLLEN) {
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100474 LOGP(DLSMS, LOGL_NOTICE,
475 SMR_LOG_STR "message %u unhandled at this state "
476 "%s.\n", inst->id, msg_type,
477 smr_state_names[inst->rp_state]);
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200478 return 0;
479 }
480
Holger Hans Peter Freytherbcf125c2012-11-14 06:07:47 +0100481 LOGP(DLSMS, LOGL_INFO,
482 SMR_LOG_STR "message %s received in state %s\n", inst->id,
Andreas Eversbergc1a91a82011-10-28 11:05:37 +0200483 smrdatastatelist[i].name, smr_state_names[inst->rp_state]);
484
485 rc = smrdatastatelist[i].rout(inst, msg);
486
487 return rc;
488}