blob: 5c72b4de9a635497aa602c6db5961bbeba95651c [file] [log] [blame]
Philipp Maiere190e032018-12-07 12:31:08 +01001/* (C) 2018 by sysmocom s.f.m.c. GmbH
2 * All Rights Reserved
3 *
4 * Author: Harald Welte, Philipp Maier
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
Harald Welte67211442018-10-07 20:10:57 +020023#include <osmocom/core/utils.h>
24#include <osmocom/gsm/tlv.h>
25
26#include <osmocom/gsm/protocol/gsm_29_118.h>
Philipp Maiere190e032018-12-07 12:31:08 +010027#include <osmocom/gsm/gsm29118.h>
28#include <osmocom/gsm/apn.h>
29#include <osmocom/gsm/gsm48.h>
Harald Welte67211442018-10-07 20:10:57 +020030
31const struct value_string sgsap_msg_type_names[] = {
32 { SGSAP_MSGT_PAGING_REQ, "PAGING-REQUEST" },
33 { SGSAP_MSGT_PAGING_REJ, "PAGING-REJECT" },
34 { SGSAP_MSGT_SERVICE_REQ, "SERVICE-REQUEST" },
35 { SGSAP_MSGT_DL_UD, "DOWNLINK-UNITDATA" },
36 { SGSAP_MSGT_UL_UD, "UPLINK-UNITDATA" },
37 { SGSAP_MSGT_LOC_UPD_REQ, "LOCATION-UPDATE-REQUEST" },
38 { SGSAP_MSGT_LOC_UPD_ACK, "LOCATION-UPDATE-ACCEPT" },
39 { SGSAP_MSGT_LOC_UPD_REJ, "LOCATION-UPDATE-REJECT" },
40 { SGSAP_MSGT_TMSI_REALL_CMPL, "TMSI-REALLOCATION-COMPLETE" },
41 { SGSAP_MSGT_ALERT_REQ, "ALERT-REQQUEST" },
42 { SGSAP_MSGT_ALERT_ACK, "ALERT-ACK" },
43 { SGSAP_MSGT_ALERT_REJ, "ALERT-REJECT" },
44 { SGSAP_MSGT_UE_ACT_IND, "UE-ACTIVITY-INDICATION" },
45 { SGSAP_MSGT_EPS_DET_IND, "EPS-DETACH-INDICATION" },
46 { SGSAP_MSGT_EPS_DET_ACK, "EPS-DETACH-ACK" },
47 { SGSAP_MSGT_IMSI_DET_IND, "IMSI-DETACH-INDICATION" },
48 { SGSAP_MSGT_IMSI_DET_ACK, "IMSI-DETACH-ACK" },
49 { SGSAP_MSGT_RESET_IND, "RESET-INDICATION" },
50 { SGSAP_MSGT_RESET_ACK, "RESET-ACK" },
51 { SGSAP_MSGT_SERVICE_ABORT_REQ, "SERVICE-ABORT-REQUEST" },
52 { SGSAP_MSGT_MO_CSFB_IND, "MO-CSFB-INDICATION" },
53 { SGSAP_MSGT_MM_INFO_REQ, "MM-INFO-REQUEST" },
54 { SGSAP_MSGT_RELEASE_REQ, "RELEASE-REQUEST" },
55 { SGSAP_MSGT_STATUS, "STATUS" },
56 { SGSAP_MSGT_UE_UNREACHABLE, "UE-UNREACHABLE" },
57 { 0, NULL }
58};
59
Philipp Maier086b3452018-11-15 15:04:29 +010060const struct value_string sgsap_iei_names[] = {
61 { SGSAP_IE_IMSI, "IMSI" },
62 { SGSAP_IE_VLR_NAME, "VLR-NAME" },
63 { SGSAP_IE_TMSI, "TMSI" },
64 { SGSAP_IE_LAI, "LAI" },
65 { SGSAP_IE_CHAN_NEEDED, "CHAN-NEEDED" },
66 { SGSAP_IE_EMLPP_PRIORITY, "EMLPP-PRIORITY" },
67 { SGSAP_IE_TMSI_STATUS, "TMSI-STATUS" },
68 { SGSAP_IE_SGS_CAUSE, "SGS-CAUSE" },
69 { SGSAP_IE_MME_NAME, "MME-NAME" },
70 { SGSAP_IE_EPS_LU_TYPE, "EPS-LU-TYPE" },
71 { SGSAP_IE_GLOBAL_CN_ID, "GLOBAL-CN-ID" },
72 { SGSAP_IE_MOBILE_ID, "MOBILE-ID" },
73 { SGSAP_IE_REJECT_CAUSE, "REJECT-CAUSE" },
74 { SGSAP_IE_IMSI_DET_EPS_TYPE, "IMSI-DET-EPS-TYPE" },
75 { SGSAP_IE_IMSI_DET_NONEPS_TYPE, "IMSI-DET-NONEPS-TYPE" },
76 { SGSAP_IE_IMEISV, "IMEISV" },
77 { SGSAP_IE_NAS_MSG_CONTAINER, "NAS-MSG-CONTAINER" },
78 { SGSAP_IE_MM_INFO, "MM-INFO" },
79 { SGSAP_IE_ERR_MSG, "ERR-MSG" },
80 { SGSAP_IE_CLI, "CLI" },
81 { SGSAP_IE_LCS_CLIENT_ID, "LCS-CLIENT-ID" },
82 { SGSAP_IE_LCS_INDICATOR, "LCS-INDICATOR" },
83 { SGSAP_IE_SS_CODE, "SS-CODE" },
84 { SGSAP_IE_SERVICE_INDICATOR, "SERVICE-INDICATOR" },
85 { SGSAP_IE_UE_TIMEZONE, "UE-TIMEZONE" },
86 { SGSAP_IE_MS_CLASSMARK2, "MS-CLASSMARK2" },
87 { SGSAP_IE_TAI, "TAI" },
88 { SGSAP_IE_EUTRAN_CGI, "EUTRAN-CGI" },
89 { SGSAP_IE_UE_EMM_MODE, "UE-EMM-MODE" },
90 { SGSAP_IE_ADDL_PAGING_INDICATORS, "ADDL-PAGING-INDICATORS" },
91 { SGSAP_IE_TMSI_BASED_NRI_CONT, "TMSI-BASED-NRI-CONT" },
Omar Ramadan76bbcbc2019-05-09 10:13:46 -070092 { SGSAP_IE_MO_FALLBACK_VALUE, "MO-FALLBACK-VALUE" },
Philipp Maier086b3452018-11-15 15:04:29 +010093 { 0, NULL }
94};
95
Harald Welte67211442018-10-07 20:10:57 +020096const struct value_string sgsap_eps_lu_type_names[] = {
97 { SGSAP_EPS_LUT_IMSI_ATTACH, "IMSI Attach" },
98 { SGSAP_EPS_LUT_NORMAL, "Normal" },
99 { 0, NULL }
100};
101
102const struct value_string sgsap_ismi_det_eps_type_names[] = {
103 { SGSAP_ID_EPS_T_NETWORK_INITIATED, "Network initiated IMSI detach from EPS" },
104 { SGSAP_ID_EPS_T_UE_INITIATED, "UE initiated IMSI detach from EPS" },
105 { SGSAP_ID_EPS_T_EPS_NOT_ALLOWED, "EPS not allowed" },
106 { 0, NULL }
107};
108
109const struct value_string sgsap_ismi_det_noneps_type_names[] = {
110 { SGSAP_ID_NONEPS_T_EXPLICIT_UE_NONEPS,
111 "Explicit UE initiated IMSI detach from non-EPS" },
112 { SGSAP_ID_NONEPS_T_COMBINED_UE_EPS_NONEPS,
113 "Combined UE initiated IMSI detach from EPS and non-EPS" },
114 { SGSAP_ID_NONEPS_T_IMPLICIT_UE_EPS_NONEPS,
115 "Implicit network initiated IMSI detach from EPS and non-EPS" },
116 { 0, NULL }
117};
118
119const struct value_string sgsap_service_ind_names[] = {
120 { SGSAP_SERV_IND_CS_CALL, "CS Call" },
121 { SGSAP_SERV_IND_SMS, "SMS" },
122 { 0, NULL }
123};
124
125const struct value_string sgsap_sgs_cause_names[] = {
126 { SGSAP_SGS_CAUSE_IMSI_DET_EPS, "IMSI detached for EPS" },
127 { SGSAP_SGS_CAUSE_IMSI_DET_EPS_NONEPS, "IMSI detached for EPS and non-EPS" },
128 { SGSAP_SGS_CAUSE_IMSI_UNKNOWN, "IMSI unknown" },
129 { SGSAP_SGS_CAUSE_IMSI_DET_NON_EPS, "IMSI detached for non-EPS" },
130 { SGSAP_SGS_CAUSE_IMSI_IMPL_DET_NON_EPS,"IMSI implicitly detached for non-EPS" },
131 { SGSAP_SGS_CAUSE_UE_UNREACHABLE, "UE unreachable" },
132 { SGSAP_SGS_CAUSE_MSG_INCOMP_STATE, "Message not compatible with protocol state" },
133 { SGSAP_SGS_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" },
134 { SGSAP_SGS_CAUSE_INVALID_MAND_IE, "Invalid mandatory IE" },
135 { SGSAP_SGS_CAUSE_COND_IE_ERROR, "Conditional IE error" },
136 { SGSAP_SGS_CAUSE_SEMANT_INCORR_MSG, "Semantically incorrect message" },
137 { SGSAP_SGS_CAUSE_MSG_UNKNOWN, "Message unknown" },
138 { SGSAP_SGS_CAUSE_MT_CSFB_REJ_USER, "MT CSFB call rejected by user" },
139 { SGSAP_SGS_CAUSE_UE_TEMP_UNREACHABLE, "UE temporarily unreachable" },
140 { 0, NULL }
141};
142
143
144const struct value_string sgsap_ue_emm_mode_names[] = {
145 { SGSAP_UE_EMM_MODE_IDLE, "EMM-IDLE" },
146 { SGSAP_UE_EMM_MODE_CONNECTED, "EMM-CONNECTED" },
147 { 0, NULL }
148};
149
150const struct tlv_definition sgsap_ie_tlvdef = {
151 .def = {
152 [SGSAP_IE_IMSI] = { TLV_TYPE_TLV },
153 [SGSAP_IE_VLR_NAME] = { TLV_TYPE_TLV },
154 [SGSAP_IE_TMSI] = { TLV_TYPE_TLV },
155 [SGSAP_IE_LAI] = { TLV_TYPE_TLV },
156 [SGSAP_IE_CHAN_NEEDED] = { TLV_TYPE_TLV },
157 [SGSAP_IE_EMLPP_PRIORITY] = { TLV_TYPE_TLV },
158 [SGSAP_IE_TMSI_STATUS] = { TLV_TYPE_TLV },
159 [SGSAP_IE_SGS_CAUSE] = { TLV_TYPE_TLV },
160 [SGSAP_IE_MME_NAME] = { TLV_TYPE_TLV },
161 [SGSAP_IE_EPS_LU_TYPE] = { TLV_TYPE_TLV },
162 [SGSAP_IE_GLOBAL_CN_ID] = { TLV_TYPE_TLV },
163 [SGSAP_IE_MOBILE_ID] = { TLV_TYPE_TLV },
164 [SGSAP_IE_REJECT_CAUSE] = { TLV_TYPE_TLV },
165 [SGSAP_IE_IMSI_DET_EPS_TYPE] = { TLV_TYPE_TLV },
166 [SGSAP_IE_IMSI_DET_NONEPS_TYPE] = { TLV_TYPE_TLV },
167 [SGSAP_IE_IMEISV] = { TLV_TYPE_TLV },
168 [SGSAP_IE_NAS_MSG_CONTAINER] = { TLV_TYPE_TLV },
169 [SGSAP_IE_MM_INFO] = { TLV_TYPE_TLV },
170 [SGSAP_IE_ERR_MSG] = { TLV_TYPE_TLV },
171 [SGSAP_IE_CLI] = { TLV_TYPE_TLV },
172 [SGSAP_IE_LCS_CLIENT_ID] = { TLV_TYPE_TLV },
173 [SGSAP_IE_LCS_INDICATOR] = { TLV_TYPE_TLV },
174 [SGSAP_IE_SS_CODE] = { TLV_TYPE_TLV },
175 [SGSAP_IE_SERVICE_INDICATOR] = { TLV_TYPE_TLV },
176 [SGSAP_IE_UE_TIMEZONE] = { TLV_TYPE_TLV },
177 [SGSAP_IE_MS_CLASSMARK2] = { TLV_TYPE_TLV },
178 [SGSAP_IE_TAI] = { TLV_TYPE_TLV },
179 [SGSAP_IE_EUTRAN_CGI] = { TLV_TYPE_TLV },
180 [SGSAP_IE_UE_EMM_MODE] = { TLV_TYPE_TLV },
181 [SGSAP_IE_ADDL_PAGING_INDICATORS]={ TLV_TYPE_TLV },
182 [SGSAP_IE_TMSI_BASED_NRI_CONT] = { TLV_TYPE_TLV },
Omar Ramadan76bbcbc2019-05-09 10:13:46 -0700183 [SGSAP_IE_MO_FALLBACK_VALUE] = { TLV_TYPE_TLV },
Harald Welte67211442018-10-07 20:10:57 +0200184 },
185};
Philipp Maiere190e032018-12-07 12:31:08 +0100186
187
188/* Allocate an empty message buffer, suitable to hold a complete SGsAP msg. */
189struct msgb *gsm29118_msgb_alloc(void)
190{
191 /* by far sufficient for the maximum size message of 298 bytes
192 * (9+7+5+3+10+253+10+1) SGsAP-UP-UD */
193 return msgb_alloc_headroom(1024, 512, "SGsAP");
194}
195
196/* Encode VLR/MME name from string and append to SGsAP msg */
197static int msgb_sgsap_name_put(struct msgb *msg, enum sgsap_iei iei, const char *name)
198{
199 uint8_t buf[APN_MAXLEN];
200 uint8_t len;
Philipp Maierd6ef6f12019-01-08 10:40:18 +0100201 int rc;
202
Philipp Maiere190e032018-12-07 12:31:08 +0100203 /* encoding is like DNS names, which is like APN fields */
204 memset(buf, 0, sizeof(buf));
Philipp Maierd6ef6f12019-01-08 10:40:18 +0100205 rc = osmo_apn_from_str(buf, sizeof(buf), name);
206 if (rc < 0)
207 return -1;
208 len = (uint8_t)rc;
Philipp Maiere190e032018-12-07 12:31:08 +0100209
210 /* Note: While the VLR-Name (see 3GPP TS 29.118, chapter 9.4.22) has
211 * a flexible length, the MME-Name has a fixed size of 55 octets. (see
212 * 3GPP TS 29.118, chapter 9.4.13). */
213 if (iei == SGSAP_IE_MME_NAME && len != SGS_MME_NAME_LEN)
214 return -1;
215 msgb_tlv_put(msg, iei, len, buf);
216 return 0;
217}
218
219/* Encode IMSI from string representation and append to SGSaAP msg */
220static void msgb_sgsap_imsi_put(struct msgb *msg, const char *imsi)
221{
Neels Hofmeyrd1ceca92020-05-26 02:45:23 +0200222 int rc;
223 struct osmo_mobile_identity mi = { .type = GSM_MI_TYPE_IMSI, };
224 uint8_t *l;
225 OSMO_STRLCPY_ARRAY(mi.imsi, imsi);
226 l = msgb_tl_put(msg, SGSAP_IE_IMSI);
227 rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);
228 /* This function fails to do error handling, so in case of error, leave the len == 0. */
229 *l = rc > 0? rc : 0;
Philipp Maiere190e032018-12-07 12:31:08 +0100230}
231
232/* Encode LAI from struct representation and append to SGSaAP msg */
233static void msgb_sgsap_lai_put(struct msgb *msg, const struct osmo_location_area_id *lai)
234{
235 struct gsm48_loc_area_id lai_enc;
236 gsm48_generate_lai2(&lai_enc, lai);
237 msgb_tlv_put(msg, SGSAP_IE_LAI, sizeof(lai_enc), (uint8_t *) & lai_enc);
238}
239
240/* Many messages consist only of a message type and an imsi */
241static struct msgb *create_simple_msg(enum sgsap_msg_type msg_type, const char *imsi)
242{
243 struct msgb *msg = gsm29118_msgb_alloc();
244 msgb_sgsap_imsi_put(msg, imsi);
245 msgb_push_u8(msg, msg_type);
246 return msg;
247}
248
249/* 8.3 SGsAP-ALERT-REQUEST.
250 * \param[in] imsi IMSI of the subscriber.
251 * \returns callee-allocated msgb with the encoded message.*/
252struct msgb *gsm29118_create_alert_req(const char *imsi)
253{
254 return create_simple_msg(SGSAP_MSGT_ALERT_REQ, imsi);
255}
256
257/* 8.4 SGsAP-DOWNLINK-UNITDATA.
258 * \param[in] imsi IMSI of the subscriber.
259 * \param[in] nas_msg user provided message buffer with L3 message.
260 * \returns callee-allocated msgb with the encoded message. */
261struct msgb *gsm29118_create_dl_ud(const char *imsi, struct msgb *nas_msg)
262{
263 struct msgb *msg = gsm29118_msgb_alloc();
264 msgb_sgsap_imsi_put(msg, imsi);
265 msgb_tlv_put(msg, SGSAP_IE_NAS_MSG_CONTAINER, nas_msg->len, nas_msg->data);
266 msgb_push_u8(msg, SGSAP_MSGT_DL_UD);
267 return msg;
268}
269
270/* 8.5 SGsAP-EPS-DETACH-ACK.
271 * \param[in] imsi IMSI of the subscriber.
272 * \returns callee-allocated msgb with the encoded message. */
273struct msgb *gsm29118_create_eps_det_ack(const char *imsi)
274{
275 return create_simple_msg(SGSAP_MSGT_EPS_DET_ACK, imsi);
276}
277
278/* 8.7 SGsAP-IMSI-DETACH-ACK.
279 * \param[in] imsi IMSI of the subscriber.
280 * \returns callee-allocated msgb with the encoded message. */
281struct msgb *gsm29118_create_imsi_det_ack(const char *imsi)
282{
283 return create_simple_msg(SGSAP_MSGT_IMSI_DET_ACK, imsi);
284}
285
286/*! 8.9 SGsAP-LOCATION-UPDATE-ACCEPT.
287 * \param[in] imsi IMSI of the subscriber.
288 * \param[in] lai Location Area Identity (optional, may be NULL).
289 * \param[in] new_id value part of new Mobile Identity (optional, may be NULL).
290 * \param[in] new_id_len length of \a new_id in octets.
291 * \returns callee-allocated msgb with the encoded message */
292struct msgb *gsm29118_create_lu_ack(const char *imsi, const struct osmo_location_area_id *lai, const uint8_t *new_id,
293 unsigned int new_id_len)
294{
295 struct msgb *msg = gsm29118_msgb_alloc();
296 msgb_sgsap_imsi_put(msg, imsi);
297 msgb_sgsap_lai_put(msg, lai);
298 if (new_id && new_id_len)
299 msgb_tlv_put(msg, SGSAP_IE_MOBILE_ID, new_id_len, new_id);
300 msgb_push_u8(msg, SGSAP_MSGT_LOC_UPD_ACK);
301 return msg;
302}
303
304/* 8.10 SGsAP-LOCATION-UPDATE-REJECT.
305 * \param[in] imsi IMSI of the subscriber.
306 * \param[in] rej_cause LU cause code, see also 3GPP TS 29.018, subclause 18.4.21.
307 * \param[in] lai location area identifier.
308 * \returns callee-allocated msgb with the encoded message */
309struct msgb *gsm29118_create_lu_rej(const char *imsi, uint8_t rej_cause, const struct osmo_location_area_id *lai)
310{
311 struct msgb *msg = gsm29118_msgb_alloc();
312 msgb_sgsap_imsi_put(msg, imsi);
313 msgb_tlv_put(msg, SGSAP_IE_REJECT_CAUSE, 1, &rej_cause);
314 if (lai)
315 msgb_sgsap_lai_put(msg, lai);
316 msgb_push_u8(msg, SGSAP_MSGT_LOC_UPD_REJ);
317 return msg;
318}
319
320/* 8.12 SGsAP-MM-INFORMATION-REQUEST.
321 * \param[in] imsi IMSI of the subscriber.
322 * \param[in] mm_info MM information, see also 3GPP TS 29.018, subclause 18.4.16.
323 * \param[in] mm_info_len length of \a mm_info in octets.
324 * \returns callee-allocated msgb with the encoded message. */
325struct msgb *gsm29118_create_mm_info_req(const char *imsi, const uint8_t *mm_info, uint8_t mm_info_len)
326{
327 struct msgb *msg = gsm29118_msgb_alloc();
328 msgb_sgsap_imsi_put(msg, imsi);
329 msgb_tlv_put(msg, SGSAP_IE_MM_INFO, mm_info_len, mm_info);
330 msgb_push_u8(msg, SGSAP_MSGT_MM_INFO_REQ);
331 return msg;
332}
333
334/* 8.14 SGsAP-PAGING-REQUEST.
335 * \param[in] params user provided memory with message contents to encode.
336 * \returns callee-allocated msgb with the encoded message or NULL on error. */
337struct msgb *gsm29118_create_paging_req(struct gsm29118_paging_req *params)
338{
339 int rc;
340 struct msgb *msg = gsm29118_msgb_alloc();
341 msgb_sgsap_imsi_put(msg, params->imsi);
342 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
343 if (rc < 0)
344 goto error;
345 msgb_tlv_put(msg, SGSAP_IE_SERVICE_INDICATOR, 1, &params->serv_ind);
346 if (params->lai_present)
347 msgb_sgsap_lai_put(msg, &params->lai);
348 msgb_push_u8(msg, SGSAP_MSGT_PAGING_REQ);
349 return msg;
350error:
351 msgb_free(msg);
352 return NULL;
353}
354
355/* 8.15 SGsAP-RESET-ACK.
356 * \param[in] params user provided memory with message contents to encode.
357 * \returns callee-allocated msgb with the encoded message or NULL on error. */
358struct msgb *gsm29118_create_reset_ack(struct gsm29118_reset_msg *params)
359{
360 int rc;
361 struct msgb *msg = gsm29118_msgb_alloc();
362 if (params->vlr_name_present && params->mme_name_present == false)
363 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
364 else if (params->mme_name_present && params->vlr_name_present == false)
365 rc = msgb_sgsap_name_put(msg, SGSAP_IE_MME_NAME, params->mme_name);
366 else
367 goto error;
368 if (rc < 0)
369 goto error;
370 msgb_push_u8(msg, SGSAP_MSGT_RESET_ACK);
371 return msg;
372error:
373 msgb_free(msg);
374 return NULL;
375}
376
377/* 8.16 SGsAP-RESET-INDICATION.
378 * \param[in] params user provided memory with message contents to encode.
379 * \returns callee-allocated msgb with the encoded message or NULL on error. */
380struct msgb *gsm29118_create_reset_ind(struct gsm29118_reset_msg *params)
381{
382 int rc;
383 struct msgb *msg = gsm29118_msgb_alloc();
384 if (params->vlr_name_present && params->mme_name_present == false)
385 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
386 else if (params->mme_name_present && params->vlr_name_present == false)
387 rc = msgb_sgsap_name_put(msg, SGSAP_IE_MME_NAME, params->mme_name);
388 else
389 goto error;
390 if (rc < 0)
391 goto error;
392 msgb_push_u8(msg, SGSAP_MSGT_RESET_IND);
393 return msg;
394error:
395 msgb_free(msg);
396 return NULL;
397}
398
399/* 8.18 SGsAP-STATUS.
400 * \param[in] imsi IMSI of the subscriber.
401 * \param[in] cause sgs related cause code.
402 * \param[in] err_msg user provided message buffer containing the errornous message.
403 * \returns callee-allocated msgb with the encoded message */
404struct msgb *gsm29118_create_status(const char *imsi, enum sgsap_sgs_cause cause, const struct msgb *err_msg)
405{
406 struct msgb *msg = gsm29118_msgb_alloc();
407 uint8_t c8 = cause;
408 unsigned int err_msg_len;
409 msgb_tlv_put(msg, SGSAP_IE_SGS_CAUSE, 1, &c8);
410 if (imsi)
411 msgb_sgsap_imsi_put(msg, imsi);
412 if (err_msg) {
413 err_msg_len = msgb_l2len(err_msg);
414 if (err_msg_len > 255)
415 err_msg_len = 255;
416 msgb_tlv_put(msg, SGSAP_IE_ERR_MSG, err_msg_len, msgb_l2(err_msg));
417 }
418 msgb_push_u8(msg, SGSAP_MSGT_STATUS);
419 return msg;
420}
421
422/* 8.23 SGsAP-RELEASE-REQUEST.
423 * \param[in] imsi IMSI of the subscriber.
424 * \param[in] cause sgs related cause code.
425 * \returns callee-allocated msgb with the encoded message. */
426struct msgb *gsm29118_create_release_req(const char *imsi, const uint8_t sgs_cause)
427{
428 struct msgb *msg = gsm29118_msgb_alloc();
429 msgb_sgsap_imsi_put(msg, imsi);
430 if (sgs_cause)
431 msgb_tlv_put(msg, SGSAP_IE_SGS_CAUSE, 1, &sgs_cause);
432 msgb_push_u8(msg, SGSAP_MSGT_RELEASE_REQ);
433 return msg;
434}
435
436/* 8.24 SGsAP-SERVICE-ABORT-REQUEST.
437 * \param[in] imsi IMSI of the subscriber.
438 * \returns callee-allocated msgb with the encoded message. */
439struct msgb *gsm29118_create_service_abort_req(const char *imsi)
440{
441 return create_simple_msg(SGSAP_MSGT_SERVICE_ABORT_REQ, imsi);
442}