blob: 2c02b2fd70f4043871af75db1f20f7c5e0a32d43 [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{
222 uint8_t buf[16];
223 uint8_t len;
224 /* encoding is just like TS 04.08 */
225 len = gsm48_generate_mid_from_imsi(buf, imsi);
226 /* skip first two bytes (tag+length) so we can use msgb_tlv_put */
227 msgb_tlv_put(msg, SGSAP_IE_IMSI, len - 2, buf + 2);
228}
229
230/* Encode LAI from struct representation and append to SGSaAP msg */
231static void msgb_sgsap_lai_put(struct msgb *msg, const struct osmo_location_area_id *lai)
232{
233 struct gsm48_loc_area_id lai_enc;
234 gsm48_generate_lai2(&lai_enc, lai);
235 msgb_tlv_put(msg, SGSAP_IE_LAI, sizeof(lai_enc), (uint8_t *) & lai_enc);
236}
237
238/* Many messages consist only of a message type and an imsi */
239static struct msgb *create_simple_msg(enum sgsap_msg_type msg_type, const char *imsi)
240{
241 struct msgb *msg = gsm29118_msgb_alloc();
242 msgb_sgsap_imsi_put(msg, imsi);
243 msgb_push_u8(msg, msg_type);
244 return msg;
245}
246
247/* 8.3 SGsAP-ALERT-REQUEST.
248 * \param[in] imsi IMSI of the subscriber.
249 * \returns callee-allocated msgb with the encoded message.*/
250struct msgb *gsm29118_create_alert_req(const char *imsi)
251{
252 return create_simple_msg(SGSAP_MSGT_ALERT_REQ, imsi);
253}
254
255/* 8.4 SGsAP-DOWNLINK-UNITDATA.
256 * \param[in] imsi IMSI of the subscriber.
257 * \param[in] nas_msg user provided message buffer with L3 message.
258 * \returns callee-allocated msgb with the encoded message. */
259struct msgb *gsm29118_create_dl_ud(const char *imsi, struct msgb *nas_msg)
260{
261 struct msgb *msg = gsm29118_msgb_alloc();
262 msgb_sgsap_imsi_put(msg, imsi);
263 msgb_tlv_put(msg, SGSAP_IE_NAS_MSG_CONTAINER, nas_msg->len, nas_msg->data);
264 msgb_push_u8(msg, SGSAP_MSGT_DL_UD);
265 return msg;
266}
267
268/* 8.5 SGsAP-EPS-DETACH-ACK.
269 * \param[in] imsi IMSI of the subscriber.
270 * \returns callee-allocated msgb with the encoded message. */
271struct msgb *gsm29118_create_eps_det_ack(const char *imsi)
272{
273 return create_simple_msg(SGSAP_MSGT_EPS_DET_ACK, imsi);
274}
275
276/* 8.7 SGsAP-IMSI-DETACH-ACK.
277 * \param[in] imsi IMSI of the subscriber.
278 * \returns callee-allocated msgb with the encoded message. */
279struct msgb *gsm29118_create_imsi_det_ack(const char *imsi)
280{
281 return create_simple_msg(SGSAP_MSGT_IMSI_DET_ACK, imsi);
282}
283
284/*! 8.9 SGsAP-LOCATION-UPDATE-ACCEPT.
285 * \param[in] imsi IMSI of the subscriber.
286 * \param[in] lai Location Area Identity (optional, may be NULL).
287 * \param[in] new_id value part of new Mobile Identity (optional, may be NULL).
288 * \param[in] new_id_len length of \a new_id in octets.
289 * \returns callee-allocated msgb with the encoded message */
290struct msgb *gsm29118_create_lu_ack(const char *imsi, const struct osmo_location_area_id *lai, const uint8_t *new_id,
291 unsigned int new_id_len)
292{
293 struct msgb *msg = gsm29118_msgb_alloc();
294 msgb_sgsap_imsi_put(msg, imsi);
295 msgb_sgsap_lai_put(msg, lai);
296 if (new_id && new_id_len)
297 msgb_tlv_put(msg, SGSAP_IE_MOBILE_ID, new_id_len, new_id);
298 msgb_push_u8(msg, SGSAP_MSGT_LOC_UPD_ACK);
299 return msg;
300}
301
302/* 8.10 SGsAP-LOCATION-UPDATE-REJECT.
303 * \param[in] imsi IMSI of the subscriber.
304 * \param[in] rej_cause LU cause code, see also 3GPP TS 29.018, subclause 18.4.21.
305 * \param[in] lai location area identifier.
306 * \returns callee-allocated msgb with the encoded message */
307struct msgb *gsm29118_create_lu_rej(const char *imsi, uint8_t rej_cause, const struct osmo_location_area_id *lai)
308{
309 struct msgb *msg = gsm29118_msgb_alloc();
310 msgb_sgsap_imsi_put(msg, imsi);
311 msgb_tlv_put(msg, SGSAP_IE_REJECT_CAUSE, 1, &rej_cause);
312 if (lai)
313 msgb_sgsap_lai_put(msg, lai);
314 msgb_push_u8(msg, SGSAP_MSGT_LOC_UPD_REJ);
315 return msg;
316}
317
318/* 8.12 SGsAP-MM-INFORMATION-REQUEST.
319 * \param[in] imsi IMSI of the subscriber.
320 * \param[in] mm_info MM information, see also 3GPP TS 29.018, subclause 18.4.16.
321 * \param[in] mm_info_len length of \a mm_info in octets.
322 * \returns callee-allocated msgb with the encoded message. */
323struct msgb *gsm29118_create_mm_info_req(const char *imsi, const uint8_t *mm_info, uint8_t mm_info_len)
324{
325 struct msgb *msg = gsm29118_msgb_alloc();
326 msgb_sgsap_imsi_put(msg, imsi);
327 msgb_tlv_put(msg, SGSAP_IE_MM_INFO, mm_info_len, mm_info);
328 msgb_push_u8(msg, SGSAP_MSGT_MM_INFO_REQ);
329 return msg;
330}
331
332/* 8.14 SGsAP-PAGING-REQUEST.
333 * \param[in] params user provided memory with message contents to encode.
334 * \returns callee-allocated msgb with the encoded message or NULL on error. */
335struct msgb *gsm29118_create_paging_req(struct gsm29118_paging_req *params)
336{
337 int rc;
338 struct msgb *msg = gsm29118_msgb_alloc();
339 msgb_sgsap_imsi_put(msg, params->imsi);
340 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
341 if (rc < 0)
342 goto error;
343 msgb_tlv_put(msg, SGSAP_IE_SERVICE_INDICATOR, 1, &params->serv_ind);
344 if (params->lai_present)
345 msgb_sgsap_lai_put(msg, &params->lai);
346 msgb_push_u8(msg, SGSAP_MSGT_PAGING_REQ);
347 return msg;
348error:
349 msgb_free(msg);
350 return NULL;
351}
352
353/* 8.15 SGsAP-RESET-ACK.
354 * \param[in] params user provided memory with message contents to encode.
355 * \returns callee-allocated msgb with the encoded message or NULL on error. */
356struct msgb *gsm29118_create_reset_ack(struct gsm29118_reset_msg *params)
357{
358 int rc;
359 struct msgb *msg = gsm29118_msgb_alloc();
360 if (params->vlr_name_present && params->mme_name_present == false)
361 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
362 else if (params->mme_name_present && params->vlr_name_present == false)
363 rc = msgb_sgsap_name_put(msg, SGSAP_IE_MME_NAME, params->mme_name);
364 else
365 goto error;
366 if (rc < 0)
367 goto error;
368 msgb_push_u8(msg, SGSAP_MSGT_RESET_ACK);
369 return msg;
370error:
371 msgb_free(msg);
372 return NULL;
373}
374
375/* 8.16 SGsAP-RESET-INDICATION.
376 * \param[in] params user provided memory with message contents to encode.
377 * \returns callee-allocated msgb with the encoded message or NULL on error. */
378struct msgb *gsm29118_create_reset_ind(struct gsm29118_reset_msg *params)
379{
380 int rc;
381 struct msgb *msg = gsm29118_msgb_alloc();
382 if (params->vlr_name_present && params->mme_name_present == false)
383 rc = msgb_sgsap_name_put(msg, SGSAP_IE_VLR_NAME, params->vlr_name);
384 else if (params->mme_name_present && params->vlr_name_present == false)
385 rc = msgb_sgsap_name_put(msg, SGSAP_IE_MME_NAME, params->mme_name);
386 else
387 goto error;
388 if (rc < 0)
389 goto error;
390 msgb_push_u8(msg, SGSAP_MSGT_RESET_IND);
391 return msg;
392error:
393 msgb_free(msg);
394 return NULL;
395}
396
397/* 8.18 SGsAP-STATUS.
398 * \param[in] imsi IMSI of the subscriber.
399 * \param[in] cause sgs related cause code.
400 * \param[in] err_msg user provided message buffer containing the errornous message.
401 * \returns callee-allocated msgb with the encoded message */
402struct msgb *gsm29118_create_status(const char *imsi, enum sgsap_sgs_cause cause, const struct msgb *err_msg)
403{
404 struct msgb *msg = gsm29118_msgb_alloc();
405 uint8_t c8 = cause;
406 unsigned int err_msg_len;
407 msgb_tlv_put(msg, SGSAP_IE_SGS_CAUSE, 1, &c8);
408 if (imsi)
409 msgb_sgsap_imsi_put(msg, imsi);
410 if (err_msg) {
411 err_msg_len = msgb_l2len(err_msg);
412 if (err_msg_len > 255)
413 err_msg_len = 255;
414 msgb_tlv_put(msg, SGSAP_IE_ERR_MSG, err_msg_len, msgb_l2(err_msg));
415 }
416 msgb_push_u8(msg, SGSAP_MSGT_STATUS);
417 return msg;
418}
419
420/* 8.23 SGsAP-RELEASE-REQUEST.
421 * \param[in] imsi IMSI of the subscriber.
422 * \param[in] cause sgs related cause code.
423 * \returns callee-allocated msgb with the encoded message. */
424struct msgb *gsm29118_create_release_req(const char *imsi, const uint8_t sgs_cause)
425{
426 struct msgb *msg = gsm29118_msgb_alloc();
427 msgb_sgsap_imsi_put(msg, imsi);
428 if (sgs_cause)
429 msgb_tlv_put(msg, SGSAP_IE_SGS_CAUSE, 1, &sgs_cause);
430 msgb_push_u8(msg, SGSAP_MSGT_RELEASE_REQ);
431 return msg;
432}
433
434/* 8.24 SGsAP-SERVICE-ABORT-REQUEST.
435 * \param[in] imsi IMSI of the subscriber.
436 * \returns callee-allocated msgb with the encoded message. */
437struct msgb *gsm29118_create_service_abort_req(const char *imsi)
438{
439 return create_simple_msg(SGSAP_MSGT_SERVICE_ABORT_REQ, imsi);
440}