blob: ca210fbf01df2572c8b2343d74986da904c16510 [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" },
92 { 0, NULL }
93};
94
Harald Welte67211442018-10-07 20:10:57 +020095const struct value_string sgsap_eps_lu_type_names[] = {
96 { SGSAP_EPS_LUT_IMSI_ATTACH, "IMSI Attach" },
97 { SGSAP_EPS_LUT_NORMAL, "Normal" },
98 { 0, NULL }
99};
100
101const struct value_string sgsap_ismi_det_eps_type_names[] = {
102 { SGSAP_ID_EPS_T_NETWORK_INITIATED, "Network initiated IMSI detach from EPS" },
103 { SGSAP_ID_EPS_T_UE_INITIATED, "UE initiated IMSI detach from EPS" },
104 { SGSAP_ID_EPS_T_EPS_NOT_ALLOWED, "EPS not allowed" },
105 { 0, NULL }
106};
107
108const struct value_string sgsap_ismi_det_noneps_type_names[] = {
109 { SGSAP_ID_NONEPS_T_EXPLICIT_UE_NONEPS,
110 "Explicit UE initiated IMSI detach from non-EPS" },
111 { SGSAP_ID_NONEPS_T_COMBINED_UE_EPS_NONEPS,
112 "Combined UE initiated IMSI detach from EPS and non-EPS" },
113 { SGSAP_ID_NONEPS_T_IMPLICIT_UE_EPS_NONEPS,
114 "Implicit network initiated IMSI detach from EPS and non-EPS" },
115 { 0, NULL }
116};
117
118const struct value_string sgsap_service_ind_names[] = {
119 { SGSAP_SERV_IND_CS_CALL, "CS Call" },
120 { SGSAP_SERV_IND_SMS, "SMS" },
121 { 0, NULL }
122};
123
124const struct value_string sgsap_sgs_cause_names[] = {
125 { SGSAP_SGS_CAUSE_IMSI_DET_EPS, "IMSI detached for EPS" },
126 { SGSAP_SGS_CAUSE_IMSI_DET_EPS_NONEPS, "IMSI detached for EPS and non-EPS" },
127 { SGSAP_SGS_CAUSE_IMSI_UNKNOWN, "IMSI unknown" },
128 { SGSAP_SGS_CAUSE_IMSI_DET_NON_EPS, "IMSI detached for non-EPS" },
129 { SGSAP_SGS_CAUSE_IMSI_IMPL_DET_NON_EPS,"IMSI implicitly detached for non-EPS" },
130 { SGSAP_SGS_CAUSE_UE_UNREACHABLE, "UE unreachable" },
131 { SGSAP_SGS_CAUSE_MSG_INCOMP_STATE, "Message not compatible with protocol state" },
132 { SGSAP_SGS_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" },
133 { SGSAP_SGS_CAUSE_INVALID_MAND_IE, "Invalid mandatory IE" },
134 { SGSAP_SGS_CAUSE_COND_IE_ERROR, "Conditional IE error" },
135 { SGSAP_SGS_CAUSE_SEMANT_INCORR_MSG, "Semantically incorrect message" },
136 { SGSAP_SGS_CAUSE_MSG_UNKNOWN, "Message unknown" },
137 { SGSAP_SGS_CAUSE_MT_CSFB_REJ_USER, "MT CSFB call rejected by user" },
138 { SGSAP_SGS_CAUSE_UE_TEMP_UNREACHABLE, "UE temporarily unreachable" },
139 { 0, NULL }
140};
141
142
143const struct value_string sgsap_ue_emm_mode_names[] = {
144 { SGSAP_UE_EMM_MODE_IDLE, "EMM-IDLE" },
145 { SGSAP_UE_EMM_MODE_CONNECTED, "EMM-CONNECTED" },
146 { 0, NULL }
147};
148
149const struct tlv_definition sgsap_ie_tlvdef = {
150 .def = {
151 [SGSAP_IE_IMSI] = { TLV_TYPE_TLV },
152 [SGSAP_IE_VLR_NAME] = { TLV_TYPE_TLV },
153 [SGSAP_IE_TMSI] = { TLV_TYPE_TLV },
154 [SGSAP_IE_LAI] = { TLV_TYPE_TLV },
155 [SGSAP_IE_CHAN_NEEDED] = { TLV_TYPE_TLV },
156 [SGSAP_IE_EMLPP_PRIORITY] = { TLV_TYPE_TLV },
157 [SGSAP_IE_TMSI_STATUS] = { TLV_TYPE_TLV },
158 [SGSAP_IE_SGS_CAUSE] = { TLV_TYPE_TLV },
159 [SGSAP_IE_MME_NAME] = { TLV_TYPE_TLV },
160 [SGSAP_IE_EPS_LU_TYPE] = { TLV_TYPE_TLV },
161 [SGSAP_IE_GLOBAL_CN_ID] = { TLV_TYPE_TLV },
162 [SGSAP_IE_MOBILE_ID] = { TLV_TYPE_TLV },
163 [SGSAP_IE_REJECT_CAUSE] = { TLV_TYPE_TLV },
164 [SGSAP_IE_IMSI_DET_EPS_TYPE] = { TLV_TYPE_TLV },
165 [SGSAP_IE_IMSI_DET_NONEPS_TYPE] = { TLV_TYPE_TLV },
166 [SGSAP_IE_IMEISV] = { TLV_TYPE_TLV },
167 [SGSAP_IE_NAS_MSG_CONTAINER] = { TLV_TYPE_TLV },
168 [SGSAP_IE_MM_INFO] = { TLV_TYPE_TLV },
169 [SGSAP_IE_ERR_MSG] = { TLV_TYPE_TLV },
170 [SGSAP_IE_CLI] = { TLV_TYPE_TLV },
171 [SGSAP_IE_LCS_CLIENT_ID] = { TLV_TYPE_TLV },
172 [SGSAP_IE_LCS_INDICATOR] = { TLV_TYPE_TLV },
173 [SGSAP_IE_SS_CODE] = { TLV_TYPE_TLV },
174 [SGSAP_IE_SERVICE_INDICATOR] = { TLV_TYPE_TLV },
175 [SGSAP_IE_UE_TIMEZONE] = { TLV_TYPE_TLV },
176 [SGSAP_IE_MS_CLASSMARK2] = { TLV_TYPE_TLV },
177 [SGSAP_IE_TAI] = { TLV_TYPE_TLV },
178 [SGSAP_IE_EUTRAN_CGI] = { TLV_TYPE_TLV },
179 [SGSAP_IE_UE_EMM_MODE] = { TLV_TYPE_TLV },
180 [SGSAP_IE_ADDL_PAGING_INDICATORS]={ TLV_TYPE_TLV },
181 [SGSAP_IE_TMSI_BASED_NRI_CONT] = { TLV_TYPE_TLV },
182 },
183};
Philipp Maiere190e032018-12-07 12:31:08 +0100184
185
186/* Allocate an empty message buffer, suitable to hold a complete SGsAP msg. */
187struct msgb *gsm29118_msgb_alloc(void)
188{
189 /* by far sufficient for the maximum size message of 298 bytes
190 * (9+7+5+3+10+253+10+1) SGsAP-UP-UD */
191 return msgb_alloc_headroom(1024, 512, "SGsAP");
192}
193
194/* Encode VLR/MME name from string and append to SGsAP msg */
195static int msgb_sgsap_name_put(struct msgb *msg, enum sgsap_iei iei, const char *name)
196{
197 uint8_t buf[APN_MAXLEN];
198 uint8_t len;
199 /* encoding is like DNS names, which is like APN fields */
200 memset(buf, 0, sizeof(buf));
201 len = osmo_apn_from_str(buf, sizeof(buf), name);
202
203 /* Note: While the VLR-Name (see 3GPP TS 29.118, chapter 9.4.22) has
204 * a flexible length, the MME-Name has a fixed size of 55 octets. (see
205 * 3GPP TS 29.118, chapter 9.4.13). */
206 if (iei == SGSAP_IE_MME_NAME && len != SGS_MME_NAME_LEN)
207 return -1;
208 msgb_tlv_put(msg, iei, len, buf);
209 return 0;
210}
211
212/* Encode IMSI from string representation and append to SGSaAP msg */
213static void msgb_sgsap_imsi_put(struct msgb *msg, const char *imsi)
214{
215 uint8_t buf[16];
216 uint8_t len;
217 /* encoding is just like TS 04.08 */
218 len = gsm48_generate_mid_from_imsi(buf, imsi);
219 /* skip first two bytes (tag+length) so we can use msgb_tlv_put */
220 msgb_tlv_put(msg, SGSAP_IE_IMSI, len - 2, buf + 2);
221}
222
223/* Encode LAI from struct representation and append to SGSaAP msg */
224static void msgb_sgsap_lai_put(struct msgb *msg, const struct osmo_location_area_id *lai)
225{
226 struct gsm48_loc_area_id lai_enc;
227 gsm48_generate_lai2(&lai_enc, lai);
228 msgb_tlv_put(msg, SGSAP_IE_LAI, sizeof(lai_enc), (uint8_t *) & lai_enc);
229}
230
231/* Many messages consist only of a message type and an imsi */
232static struct msgb *create_simple_msg(enum sgsap_msg_type msg_type, const char *imsi)
233{
234 struct msgb *msg = gsm29118_msgb_alloc();
235 msgb_sgsap_imsi_put(msg, imsi);
236 msgb_push_u8(msg, msg_type);
237 return msg;
238}
239
240/* 8.3 SGsAP-ALERT-REQUEST.
241 * \param[in] imsi IMSI of the subscriber.
242 * \returns callee-allocated msgb with the encoded message.*/
243struct msgb *gsm29118_create_alert_req(const char *imsi)
244{
245 return create_simple_msg(SGSAP_MSGT_ALERT_REQ, imsi);
246}
247
248/* 8.4 SGsAP-DOWNLINK-UNITDATA.
249 * \param[in] imsi IMSI of the subscriber.
250 * \param[in] nas_msg user provided message buffer with L3 message.
251 * \returns callee-allocated msgb with the encoded message. */
252struct msgb *gsm29118_create_dl_ud(const char *imsi, struct msgb *nas_msg)
253{
254 struct msgb *msg = gsm29118_msgb_alloc();
255 msgb_sgsap_imsi_put(msg, imsi);
256 msgb_tlv_put(msg, SGSAP_IE_NAS_MSG_CONTAINER, nas_msg->len, nas_msg->data);
257 msgb_push_u8(msg, SGSAP_MSGT_DL_UD);
258 return msg;
259}
260
261/* 8.5 SGsAP-EPS-DETACH-ACK.
262 * \param[in] imsi IMSI of the subscriber.
263 * \returns callee-allocated msgb with the encoded message. */
264struct msgb *gsm29118_create_eps_det_ack(const char *imsi)
265{
266 return create_simple_msg(SGSAP_MSGT_EPS_DET_ACK, imsi);
267}
268
269/* 8.7 SGsAP-IMSI-DETACH-ACK.
270 * \param[in] imsi IMSI of the subscriber.
271 * \returns callee-allocated msgb with the encoded message. */
272struct msgb *gsm29118_create_imsi_det_ack(const char *imsi)
273{
274 return create_simple_msg(SGSAP_MSGT_IMSI_DET_ACK, imsi);
275}
276
277/*! 8.9 SGsAP-LOCATION-UPDATE-ACCEPT.
278 * \param[in] imsi IMSI of the subscriber.
279 * \param[in] lai Location Area Identity (optional, may be NULL).
280 * \param[in] new_id value part of new Mobile Identity (optional, may be NULL).
281 * \param[in] new_id_len length of \a new_id in octets.
282 * \returns callee-allocated msgb with the encoded message */
283struct msgb *gsm29118_create_lu_ack(const char *imsi, const struct osmo_location_area_id *lai, const uint8_t *new_id,
284 unsigned int new_id_len)
285{
286 struct msgb *msg = gsm29118_msgb_alloc();
287 msgb_sgsap_imsi_put(msg, imsi);
288 msgb_sgsap_lai_put(msg, lai);
289 if (new_id && new_id_len)
290 msgb_tlv_put(msg, SGSAP_IE_MOBILE_ID, new_id_len, new_id);
291 msgb_push_u8(msg, SGSAP_MSGT_LOC_UPD_ACK);
292 return msg;
293}
294
295/* 8.10 SGsAP-LOCATION-UPDATE-REJECT.
296 * \param[in] imsi IMSI of the subscriber.
297 * \param[in] rej_cause LU cause code, see also 3GPP TS 29.018, subclause 18.4.21.
298 * \param[in] lai location area identifier.
299 * \returns callee-allocated msgb with the encoded message */
300struct msgb *gsm29118_create_lu_rej(const char *imsi, uint8_t rej_cause, const struct osmo_location_area_id *lai)
301{
302 struct msgb *msg = gsm29118_msgb_alloc();
303 msgb_sgsap_imsi_put(msg, imsi);
304 msgb_tlv_put(msg, SGSAP_IE_REJECT_CAUSE, 1, &rej_cause);
305 if (lai)
306 msgb_sgsap_lai_put(msg, lai);
307 msgb_push_u8(msg, SGSAP_MSGT_LOC_UPD_REJ);
308 return msg;
309}
310
311/* 8.12 SGsAP-MM-INFORMATION-REQUEST.
312 * \param[in] imsi IMSI of the subscriber.
313 * \param[in] mm_info MM information, see also 3GPP TS 29.018, subclause 18.4.16.
314 * \param[in] mm_info_len length of \a mm_info in octets.
315 * \returns callee-allocated msgb with the encoded message. */
316struct msgb *gsm29118_create_mm_info_req(const char *imsi, const uint8_t *mm_info, uint8_t mm_info_len)
317{
318 struct msgb *msg = gsm29118_msgb_alloc();
319 msgb_sgsap_imsi_put(msg, imsi);
320 msgb_tlv_put(msg, SGSAP_IE_MM_INFO, mm_info_len, mm_info);
321 msgb_push_u8(msg, SGSAP_MSGT_MM_INFO_REQ);
322 return msg;
323}
324
325/* 8.14 SGsAP-PAGING-REQUEST.
326 * \param[in] params user provided memory with message contents to encode.
327 * \returns callee-allocated msgb with the encoded message or NULL on error. */
328struct msgb *gsm29118_create_paging_req(struct gsm29118_paging_req *params)
329{
330 int rc;
331 struct msgb *msg = gsm29118_msgb_alloc();
332 msgb_sgsap_imsi_put(msg, params->imsi);
333 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
334 if (rc < 0)
335 goto error;
336 msgb_tlv_put(msg, SGSAP_IE_SERVICE_INDICATOR, 1, &params->serv_ind);
337 if (params->lai_present)
338 msgb_sgsap_lai_put(msg, &params->lai);
339 msgb_push_u8(msg, SGSAP_MSGT_PAGING_REQ);
340 return msg;
341error:
342 msgb_free(msg);
343 return NULL;
344}
345
346/* 8.15 SGsAP-RESET-ACK.
347 * \param[in] params user provided memory with message contents to encode.
348 * \returns callee-allocated msgb with the encoded message or NULL on error. */
349struct msgb *gsm29118_create_reset_ack(struct gsm29118_reset_msg *params)
350{
351 int rc;
352 struct msgb *msg = gsm29118_msgb_alloc();
353 if (params->vlr_name_present && params->mme_name_present == false)
354 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
355 else if (params->mme_name_present && params->vlr_name_present == false)
356 rc = msgb_sgsap_name_put(msg, SGSAP_IE_MME_NAME, params->mme_name);
357 else
358 goto error;
359 if (rc < 0)
360 goto error;
361 msgb_push_u8(msg, SGSAP_MSGT_RESET_ACK);
362 return msg;
363error:
364 msgb_free(msg);
365 return NULL;
366}
367
368/* 8.16 SGsAP-RESET-INDICATION.
369 * \param[in] params user provided memory with message contents to encode.
370 * \returns callee-allocated msgb with the encoded message or NULL on error. */
371struct msgb *gsm29118_create_reset_ind(struct gsm29118_reset_msg *params)
372{
373 int rc;
374 struct msgb *msg = gsm29118_msgb_alloc();
375 if (params->vlr_name_present && params->mme_name_present == false)
376 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
377 else if (params->mme_name_present && params->vlr_name_present == false)
378 rc = msgb_sgsap_name_put(msg, SGSAP_IE_MME_NAME, params->mme_name);
379 else
380 goto error;
381 if (rc < 0)
382 goto error;
383 msgb_push_u8(msg, SGSAP_MSGT_RESET_IND);
384 return msg;
385error:
386 msgb_free(msg);
387 return NULL;
388}
389
390/* 8.18 SGsAP-STATUS.
391 * \param[in] imsi IMSI of the subscriber.
392 * \param[in] cause sgs related cause code.
393 * \param[in] err_msg user provided message buffer containing the errornous message.
394 * \returns callee-allocated msgb with the encoded message */
395struct msgb *gsm29118_create_status(const char *imsi, enum sgsap_sgs_cause cause, const struct msgb *err_msg)
396{
397 struct msgb *msg = gsm29118_msgb_alloc();
398 uint8_t c8 = cause;
399 unsigned int err_msg_len;
400 msgb_tlv_put(msg, SGSAP_IE_SGS_CAUSE, 1, &c8);
401 if (imsi)
402 msgb_sgsap_imsi_put(msg, imsi);
403 if (err_msg) {
404 err_msg_len = msgb_l2len(err_msg);
405 if (err_msg_len > 255)
406 err_msg_len = 255;
407 msgb_tlv_put(msg, SGSAP_IE_ERR_MSG, err_msg_len, msgb_l2(err_msg));
408 }
409 msgb_push_u8(msg, SGSAP_MSGT_STATUS);
410 return msg;
411}
412
413/* 8.23 SGsAP-RELEASE-REQUEST.
414 * \param[in] imsi IMSI of the subscriber.
415 * \param[in] cause sgs related cause code.
416 * \returns callee-allocated msgb with the encoded message. */
417struct msgb *gsm29118_create_release_req(const char *imsi, const uint8_t sgs_cause)
418{
419 struct msgb *msg = gsm29118_msgb_alloc();
420 msgb_sgsap_imsi_put(msg, imsi);
421 if (sgs_cause)
422 msgb_tlv_put(msg, SGSAP_IE_SGS_CAUSE, 1, &sgs_cause);
423 msgb_push_u8(msg, SGSAP_MSGT_RELEASE_REQ);
424 return msg;
425}
426
427/* 8.24 SGsAP-SERVICE-ABORT-REQUEST.
428 * \param[in] imsi IMSI of the subscriber.
429 * \returns callee-allocated msgb with the encoded message. */
430struct msgb *gsm29118_create_service_abort_req(const char *imsi)
431{
432 return create_simple_msg(SGSAP_MSGT_SERVICE_ABORT_REQ, imsi);
433}