blob: 7886da68ee668eebba490c0964314d88472d05b6 [file] [log] [blame]
Neels Hofmeyrc6848f42020-09-18 18:00:50 +02001/* 3GPP TS 48.071 BSSLAP protocol definitions */
2/*
3 * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * Author: Neels Hofmeyr <neels@hofmeyr.de>
7 *
8 * SPDX-License-Identifier: GPL-2.0+
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
26#include <errno.h>
27
28#include <osmocom/core/msgb.h>
29#include <osmocom/gsm/bsslap.h>
30#include <osmocom/gsm/tlv.h>
31
32#include <osmocom/core/logging.h>
33
34/*! \addtogroup bsslap
35 * @{
36 * \file bsslap.c
37 * Message encoding and decoding for 3GPP TS 48.071 BSSLAP protocol.
38 */
39
40static const struct tlv_definition osmo_bsslap_tlvdef = {
41 .def = {
42 [BSSLAP_IEI_TA] = { TLV_TYPE_TV },
43 [BSSLAP_IEI_CELL_ID] = { TLV_TYPE_FIXED, 2 },
44 [BSSLAP_IEI_CHAN_DESC] = { TLV_TYPE_FIXED, 3 },
45 [BSSLAP_IEI_MEAS_REP] = { TLV_TYPE_TLV },
46 [BSSLAP_IEI_CAUSE] = { TLV_TYPE_TV },
47 [BSSLAP_IEI_RRLP_FLAG] = { TLV_TYPE_TV },
48 [BSSLAP_IEI_RRLP] = { TLV_TYPE_TLV },
49 [BSSLAP_IEI_CELL_ID_LIST] = { TLV_TYPE_TLV },
50 [BSSLAP_IEI_ENH_MEAS_REP] = { TLV_TYPE_TLV },
51 [BSSLAP_IEI_LAC] = { TLV_TYPE_TLV },
52 [BSSLAP_IEI_FREQ_LIST] = { TLV_TYPE_TLV },
53 [BSSLAP_IEI_MS_POWER] = { TLV_TYPE_TV },
54 [BSSLAP_IEI_DELTA_TIMER] = { TLV_TYPE_TV },
55 [BSSLAP_IEI_SERVING_CELL_ID] = { TLV_TYPE_TLV },
56 [BSSLAP_IEI_ENCR_KEY] = { TLV_TYPE_FIXED, 8 },
57 [BSSLAP_IEI_CIPH_MODE_SET] = { TLV_TYPE_TV },
58 [BSSLAP_IEI_CHAN_MODE] = { TLV_TYPE_TV, 2 },
59 [BSSLAP_IEI_MR_CONFIG] = { TLV_TYPE_TLV },
60 [BSSLAP_IEI_POLLING_REPETITION] = { TLV_TYPE_TV },
61 [BSSLAP_IEI_PACKET_CHAN_DESC] = { TLV_TYPE_FIXED, 4 },
62 [BSSLAP_IEI_TLLI] = { TLV_TYPE_FIXED, 4 },
63 [BSSLAP_IEI_TFI] = { TLV_TYPE_TLV },
64 [BSSLAP_IEI_TBF_START_TIME] = { TLV_TYPE_FIXED, 2 },
65 [BSSLAP_IEI_PWRUP_START_TIME] = { TLV_TYPE_TLV },
66 [BSSLAP_IEI_LONG_ENCR_KEY] = { TLV_TYPE_FIXED, 16 },
67 [BSSLAP_IEI_CONCUR_POS_PROC_F] = { TLV_TYPE_TV },
68 },
69};
70
71#define DEC_ERR(RC, MSG_TYPE, IEI, CAUSE, fmt, args...) do { \
72 if (err && !*err) { \
73 *err = talloc_zero(err_ctx, struct osmo_bsslap_err); \
74 **err = (struct osmo_bsslap_err){ \
75 .rc = (RC), \
76 .msg_type = (MSG_TYPE), \
77 .iei = (IEI), \
78 .cause = (CAUSE), \
79 .logmsg = talloc_asprintf(*err, "Error decoding BSSLAP%s%s%s%s%s: " fmt, \
80 (MSG_TYPE) >= 0 ? " " : "", \
81 (MSG_TYPE) >= 0 ? osmo_bsslap_msgt_name(MSG_TYPE) : "", \
82 (IEI) >= 0 ? ": " : "", \
83 (IEI) >= 0 ? osmo_bsslap_iei_name(IEI) : "", \
84 (IEI) >= 0 ? " IE" : "", \
85##args), \
86 }; \
87 } \
88 return RC; \
89 } while(0)
90
91static void osmo_bsslap_ie_enc_cell_id(struct msgb *msg, uint16_t cell_id)
92{
93 msgb_put_u8(msg, BSSLAP_IEI_CELL_ID);
94 msgb_put_u16(msg, cell_id);
95}
96
97static int osmo_bsslap_ie_dec_cell_id(uint16_t *cell_id,
98 enum bsslap_msgt msgt, enum bsslap_iei iei,
99 struct osmo_bsslap_err **err, void *err_ctx,
100 const uint8_t *data, size_t len)
101{
102 if (len != 2)
103 DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Expected 2 bytes, got %zu", len);
104 *cell_id = osmo_load16be(data);
105 return 0;
106}
107
108static void osmo_bsslap_ie_enc_ta(struct msgb *msg, uint8_t ta)
109{
110 msgb_put_u8(msg, BSSLAP_IEI_TA);
111 msgb_put_u8(msg, ta);
112}
113
114static int osmo_bsslap_ie_dec_ta(uint8_t *ta,
115 enum bsslap_msgt msgt, enum bsslap_iei iei,
116 struct osmo_bsslap_err **err, void *err_ctx,
117 const uint8_t *data, size_t len)
118{
119 if (len != 1)
120 DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Expected 1 byte, got %zu", len);
121 *ta = data[0];
122 return 0;
123}
124
125static void osmo_bsslap_ie_enc_cause(struct msgb *msg, enum bsslap_cause cause)
126{
127 msgb_put_u8(msg, BSSLAP_IEI_CAUSE);
128 msgb_put_u8(msg, cause);
129}
130
131static int osmo_bsslap_ie_dec_cause(enum bsslap_cause *cause,
132 enum bsslap_msgt msgt, enum bsslap_iei iei,
133 struct osmo_bsslap_err **err, void *err_ctx,
134 const uint8_t *data, size_t len)
135{
136 if (len != 1)
137 DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Expected 1 byte, got %zu", len);
138 *cause = data[0];
139 return 0;
140}
141
142static void osmo_bsslap_ie_enc_chan_desc(struct msgb *msg, const struct gsm48_chan_desc *chan_desc)
143{
144 struct gsm48_chan_desc *put_chan_desc;
145 msgb_put_u8(msg, BSSLAP_IEI_CHAN_DESC);
146 put_chan_desc = (void*)msgb_put(msg, sizeof(*chan_desc));
147 *put_chan_desc = *chan_desc;
148}
149
150static int osmo_bsslap_ie_dec_chan_desc(struct gsm48_chan_desc *chan_desc,
151 enum bsslap_msgt msgt, enum bsslap_iei iei,
152 struct osmo_bsslap_err **err, void *err_ctx,
153 const uint8_t *data, size_t len)
154{
155 if (len != sizeof(*chan_desc))
156 DEC_ERR(-EINVAL, msgt, iei, LCS_CAUSE_UNSPECIFIED, "Expected %zu bytes, got %zu",
157 sizeof(*chan_desc), len);
158 *chan_desc = *(struct gsm48_chan_desc*)data;
159 return 0;
160}
161
162/*! Encode BSSLAP PDU and append to msgb (3GPP TS 48.071).
163 * \param[out] msg msgb to append to.
164 * \param[in] pdu PDU data to encode.
165 * \return number of bytes written, negative on error.
166 */
167int osmo_bsslap_enc(struct msgb *msg, const struct bsslap_pdu *pdu)
168{
169 uint8_t *old_tail = msg->tail;
170
171 msgb_put_u8(msg, pdu->msg_type);
172
173 switch (pdu->msg_type) {
174 case BSSLAP_MSGT_TA_REQUEST:
175 /* The TA Request message contains only the message type. */
176 break;
177
178 case BSSLAP_MSGT_TA_RESPONSE:
179 osmo_bsslap_ie_enc_cell_id(msg, pdu->ta_response.cell_id);
180 osmo_bsslap_ie_enc_ta(msg, pdu->ta_response.ta);
181 break;
182
183 case BSSLAP_MSGT_REJECT:
184 osmo_bsslap_ie_enc_cause(msg, pdu->reject);
185 break;
186
187 case BSSLAP_MSGT_RESET:
188 osmo_bsslap_ie_enc_cell_id(msg, pdu->reset.cell_id);
189 osmo_bsslap_ie_enc_ta(msg, pdu->reset.ta);
190 osmo_bsslap_ie_enc_chan_desc(msg, &pdu->reset.chan_desc);
191 osmo_bsslap_ie_enc_cause(msg, pdu->reset.cause);
192 break;
193
194 case BSSLAP_MSGT_ABORT:
195 osmo_bsslap_ie_enc_cause(msg, pdu->abort);
196 break;
197
198 case BSSLAP_MSGT_TA_LAYER3:
199 osmo_bsslap_ie_enc_ta(msg, pdu->ta_layer3.ta);
200 break;
201
202 default:
203 return -ENOTSUP;
204 }
205 return (msg->tail - old_tail);
206}
207
208/*! Decode BSSLAP PDU (3GPP TS 48.071).
209 * \param[out] pdu Write decoded values here.
210 * \param[out] err Returned pointer to error info, dynamically allocated; NULL to not return any.
211 * \param[in] err_ctx Talloc context to allocate err from, if required.
212 * \param[in] data Pointer to BSSLAP PDU raw data.
213 * \param[in] len Data length to decode.
214 * \return 0 on success, negative on error.
215 */
216int osmo_bsslap_dec(struct bsslap_pdu *pdu,
217 struct osmo_bsslap_err **err, void *err_ctx,
218 const uint8_t *data, size_t len)
219{
220 const uint8_t *ies_start;
221 int ies_len;
222 struct tlv_parsed tp;
223
224 *pdu = (struct bsslap_pdu){};
225 if (err)
226 *err = NULL;
227
228#define DEC_IE_MANDATORY(IEI, DEC_FUN, DEC_FUN_ARG) do { \
229 const struct tlv_p_entry *e; \
230 int rc; \
231 if (!(e = TLVP_GET(&tp, IEI))) \
232 DEC_ERR(-EINVAL, pdu->msg_type, IEI, LCS_CAUSE_DATA_MISSING_IN_REQ, "missing mandatory IE"); \
233 rc = DEC_FUN(DEC_FUN_ARG, pdu->msg_type, IEI, err, err_ctx, e->val, e->len); \
234 if (rc) \
235 DEC_ERR(rc, pdu->msg_type, IEI, LCS_CAUSE_UNSPECIFIED, "cannot parse IE"); \
236 } while (0)
237
238 if (len < 1)
239 DEC_ERR(-EINVAL, -1, -1, LCS_CAUSE_UNSPECIFIED, "PDU too short: %zu b", len);
240
241 pdu->msg_type = data[0];
242
243 if (pdu->msg_type == BSSLAP_MSGT_TA_REQUEST) {
244 /* The TA Request message contains only the message type. */
245 return 0;
246 }
247
248 ies_start = &data[1];
249 ies_len = len - 1;
250
251 if (tlv_parse2(&tp, 1, &osmo_bsslap_tlvdef, ies_start, ies_len, 0, 0) <= 0)
252 DEC_ERR(-EINVAL, pdu->msg_type, -1, LCS_CAUSE_UNSPECIFIED, "failed to parse TLV structure");
253
254 switch (pdu->msg_type) {
255
256 case BSSLAP_MSGT_TA_RESPONSE:
257 DEC_IE_MANDATORY(BSSLAP_IEI_CELL_ID, osmo_bsslap_ie_dec_cell_id, &pdu->ta_response.cell_id);
258 DEC_IE_MANDATORY(BSSLAP_IEI_TA, osmo_bsslap_ie_dec_ta, &pdu->ta_response.ta);
259 return 0;
260
261 case BSSLAP_MSGT_REJECT:
262 DEC_IE_MANDATORY(BSSLAP_IEI_CAUSE, osmo_bsslap_ie_dec_cause, &pdu->reject);
263 return 0;
264
265 case BSSLAP_MSGT_RESET:
266 DEC_IE_MANDATORY(BSSLAP_IEI_CELL_ID, osmo_bsslap_ie_dec_cell_id, &pdu->reset.cell_id);
267 DEC_IE_MANDATORY(BSSLAP_IEI_TA, osmo_bsslap_ie_dec_ta, &pdu->reset.ta);
268 DEC_IE_MANDATORY(BSSLAP_IEI_CHAN_DESC, osmo_bsslap_ie_dec_chan_desc, &pdu->reset.chan_desc);
269 DEC_IE_MANDATORY(BSSLAP_IEI_CAUSE, osmo_bsslap_ie_dec_cause, &pdu->reset.cause);
270 return 0;
271
272 case BSSLAP_MSGT_ABORT:
273 DEC_IE_MANDATORY(BSSLAP_IEI_CAUSE, osmo_bsslap_ie_dec_cause, &pdu->abort);
274 return 0;
275
276 case BSSLAP_MSGT_TA_LAYER3:
277 DEC_IE_MANDATORY(BSSLAP_IEI_TA, osmo_bsslap_ie_dec_ta, &pdu->ta_layer3.ta);
278 return 0;
279
280 default:
281 DEC_ERR(-EINVAL, pdu->msg_type, -1, LCS_CAUSE_UNSPECIFIED, "Unsupported message type");
282 }
283}
284
285const struct value_string osmo_bsslap_msgt_names[] = {
286 { BSSLAP_MSGT_TA_REQUEST, "TA Request" },
287 { BSSLAP_MSGT_TA_RESPONSE, "TA Response" },
288 { BSSLAP_MSGT_REJECT, "Reject" },
289 { BSSLAP_MSGT_RESET, "Reset" },
290 { BSSLAP_MSGT_ABORT, "Abort" },
291 { BSSLAP_MSGT_TA_LAYER3, "TA Layer3" },
292 { BSSLAP_MSGT_MS_POS_CMD, "MS Position Command" },
293 { BSSLAP_MSGT_MS_POS_RESP, "MS Position Response" },
294 { BSSLAP_MSGT_UTDOA_REQ, "U-TDOA Request" },
295 { BSSLAP_MSGT_UTDOA_RESP, "U-TDOA Response" },
296 {}
297};
298
299const struct value_string osmo_bsslap_iei_names[] = {
300 { BSSLAP_IEI_TA, "Timing Advance" },
301 { BSSLAP_IEI_CELL_ID, "Cell Identity" },
302 { BSSLAP_IEI_CHAN_DESC, "Channel Description" },
303 { BSSLAP_IEI_MEAS_REP, "Measurement Report" },
304 { BSSLAP_IEI_CAUSE, "Cause" },
305 { BSSLAP_IEI_RRLP_FLAG, "RRLP Flag" },
306 { BSSLAP_IEI_RRLP, "RRLP" },
307 { BSSLAP_IEI_CELL_ID_LIST, "Cell Identity List" },
308 { BSSLAP_IEI_ENH_MEAS_REP, "Enhanced Measurement Report" },
309 { BSSLAP_IEI_LAC, "Location Area Code" },
310 { BSSLAP_IEI_FREQ_LIST, "Frequency List" },
311 { BSSLAP_IEI_MS_POWER, "MS Power" },
312 { BSSLAP_IEI_DELTA_TIMER, "Delta Timer" },
313 { BSSLAP_IEI_SERVING_CELL_ID, "Serving Cell Identifier" },
314 { BSSLAP_IEI_ENCR_KEY, "Encryption Key" },
315 { BSSLAP_IEI_CIPH_MODE_SET, "Cipher Mode Setting" },
316 { BSSLAP_IEI_CHAN_MODE, "Channel Mode" },
317 { BSSLAP_IEI_MR_CONFIG, "MultiRate Configuration" },
318 { BSSLAP_IEI_POLLING_REPETITION, "Polling Repetition" },
319 { BSSLAP_IEI_PACKET_CHAN_DESC, "Packet Channel Description" },
320 { BSSLAP_IEI_TLLI, "TLLI" },
321 { BSSLAP_IEI_TFI, "TFI" },
322 { BSSLAP_IEI_TBF_START_TIME, "TBF Starting Time" },
323 { BSSLAP_IEI_PWRUP_START_TIME, "Powerup Starting Time" },
324 { BSSLAP_IEI_LONG_ENCR_KEY, "Long Encryption Key" },
325 { BSSLAP_IEI_CONCUR_POS_PROC_F, "Concurrent Positioning Flag" },
326 {}
327};
328
329/*! @} */