blob: 1e90a6897c4dbfe295e242d6d91cde7833b1b88e [file] [log] [blame]
Harald Weltebe3c38c2023-11-23 22:08:51 +01001/*
2 * Copyright (C) 2022-2023 Harald Welte <laforge@osmocom.org>
3 *
4 * All Rights Reserved
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
19/*! \addtogroup rlp
20 * @{
21 * RLP (Radio Link Protocol) as per 3GPP TS 24.022
22 *
23 */
24
25#include <stdint.h>
26#include <stddef.h>
27#include <string.h>
28#include <errno.h>
29
30#include <osmocom/gsm/rlp.h>
31
32const struct value_string osmo_rlp_ftype_vals[] = {
33 { OSMO_RLP_FT_U, "U" },
34 { OSMO_RLP_FT_S, "S" },
35 { OSMO_RLP_FT_IS, "IS" },
36 { 0, NULL }
37};
38
39const struct value_string osmo_rlp_ftype_u_vals[] = {
40 { OSMO_RLP_U_FT_SABM, "SABM" },
41 { OSMO_RLP_U_FT_UA, "UA" },
42 { OSMO_RLP_U_FT_DISC, "DISC" },
43 { OSMO_RLP_U_FT_DM, "DM" },
44 { OSMO_RLP_U_FT_NULL, "NULL" },
45 { OSMO_RLP_U_FT_UI, "UI" },
46 { OSMO_RLP_U_FT_XID, "XID" },
47 { OSMO_RLP_U_FT_TEST, "TEST" },
48 { OSMO_RLP_U_FT_REMAP, "REMAP" },
49 { 0, NULL }
50};
51
52const struct value_string osmo_rlp_ftype_s_vals[] = {
53 { OSMO_RLP_S_FT_RR, "RR" },
54 { OSMO_RLP_S_FT_REJ, "REJ" },
55 { OSMO_RLP_S_FT_RNR, "RNR" },
56 { OSMO_RLP_S_FT_SREJ, "SREJ" },
57 { 0, NULL }
58};
59
Harald Welte7f2b22b2023-11-26 18:53:30 +010060/* number of bytes used up by FCS */
61#define FCS_SIZE_BYTES 3
Harald Weltebe3c38c2023-11-23 22:08:51 +010062
63/*! decode a RLP frame into its abstract representation. Doesn't check FCS correctness.
64 * \param[out] out caller-allocated memory for output of decoded frame
65 * \param[in] version RLP version number to use when decoding
66 * \param[in] data raw RLP frame input data
Harald Welte7f2b22b2023-11-26 18:53:30 +010067 * \param[in] data_len length of data (in octets); must be 30 (240bit) or 72 (576bit)
Harald Weltebe3c38c2023-11-23 22:08:51 +010068 * \returns 0 in case of success; negative on error */
69int osmo_rlp_decode(struct osmo_rlp_frame_decoded *out, uint8_t version, const uint8_t *data, size_t data_len)
70{
Harald Welte7f2b22b2023-11-26 18:53:30 +010071 const uint8_t hdr_len = 2; /* will become a variable when we introduce v2 support */
Harald Weltebe3c38c2023-11-23 22:08:51 +010072 uint8_t n_s, n_r;
73
Harald Welte7f2b22b2023-11-26 18:53:30 +010074 if (data_len != 240/8 && data_len != 576/8)
Harald Weltebe3c38c2023-11-23 22:08:51 +010075 return -EINVAL;
76
77 /* we only support version 0+1 so far */
78 if (version >= 2)
79 return -ENOTSUP;
80
81 memset(out, 0, sizeof(*out));
82 out->version = version;
83
84 out->c_r = data[0] & 1;
85 n_s = (data[0] >> 3) | (data[1] & 1) << 5;
86 n_r = (data[1] >> 2);
Harald Welte7f2b22b2023-11-26 18:53:30 +010087 out->fcs = (data[data_len-1] << 16) | (data[data_len-2]) << 8 | (data[data_len-3] << 0);
Harald Weltebe3c38c2023-11-23 22:08:51 +010088 out->p_f = (data[1] >> 1) & 1;
89
90 switch (n_s) {
91 case 0x3f:
92 out->ftype = OSMO_RLP_FT_U;
93 out->u_ftype = n_r & 0x1f;
94 if (out->u_ftype == OSMO_RLP_U_FT_XID) {
Harald Welte7f2b22b2023-11-26 18:53:30 +010095 memcpy(out->info, data + hdr_len, data_len - (hdr_len + FCS_SIZE_BYTES));
96 out->info_len = data_len - (hdr_len + FCS_SIZE_BYTES);
Harald Weltebe3c38c2023-11-23 22:08:51 +010097 }
98 break;
99 case 0x3e:
100 out->ftype = OSMO_RLP_FT_S;
101 out->s_ftype = (data[0] >> 1) & 3;
102 out->n_r = n_r;
103 break;
104 default:
105 out->ftype = OSMO_RLP_FT_IS;
106 out->s_ftype = (data[0] >> 1) & 3;
107 out->n_s = n_s;
108 out->n_r = n_r;
Harald Welte7f2b22b2023-11-26 18:53:30 +0100109 memcpy(out->info, data + hdr_len, data_len - (hdr_len + FCS_SIZE_BYTES));
110 out->info_len = data_len - (2 + 3);
Harald Weltebe3c38c2023-11-23 22:08:51 +0100111 break;
112 }
113
114 return 0;
115}
116
117/*! encode a RLP frame from its abstract representation. Generates FCS.
118 * \param[out] out caller-allocated output buffer
Harald Welte7f2b22b2023-11-26 18:53:30 +0100119 * \param[in] out_size size of output buffer (in octets); must be 30 (240bit) or 72 (576bit)
Harald Weltebe3c38c2023-11-23 22:08:51 +0100120 * \param[in] in decoded RLP frame which is to be encoded
121 * \returns number of output bytes used; negative on error */
122int osmo_rlp_encode(uint8_t *out, size_t out_size, const struct osmo_rlp_frame_decoded *in)
123{
Harald Welte7f2b22b2023-11-26 18:53:30 +0100124 const uint8_t hdr_len = 2; /* will become a variable when we introduce v2 support */
Harald Weltebe3c38c2023-11-23 22:08:51 +0100125 uint8_t n_s, n_r, s_bits;
126 uint32_t fcs;
127
128 /* we only support version 0+1 so far */
129 if (in->version >= 2)
130 return -ENOTSUP;
131
Harald Welte7f2b22b2023-11-26 18:53:30 +0100132 if (out_size != 240/8 && out_size != 576/8)
Harald Weltebe3c38c2023-11-23 22:08:51 +0100133 return -EINVAL;
134
Harald Welte7f2b22b2023-11-26 18:53:30 +0100135 memset(out, 0, out_size);
Harald Weltebe3c38c2023-11-23 22:08:51 +0100136
137 if (in->c_r)
138 out[0] |= 0x01;
139 if (in->p_f)
140 out[1] |= 0x02;
141
142 switch (in->ftype) {
143 case OSMO_RLP_FT_U:
144 n_s = 0x3f;
145 n_r = in->u_ftype;
146 s_bits = 0;
Harald Welte7f2b22b2023-11-26 18:53:30 +0100147 if (in->u_ftype == OSMO_RLP_U_FT_XID) {
148 if (in->info_len > out_size - (hdr_len + FCS_SIZE_BYTES))
149 return -EINVAL;
150 memcpy(out+hdr_len, in->info, in->info_len);
151 }
Harald Weltebe3c38c2023-11-23 22:08:51 +0100152 break;
153 case OSMO_RLP_FT_S:
154 n_s = 0x3e;
155 n_r = in->n_r;
156 s_bits = in->s_ftype;
157 break;
158 case OSMO_RLP_FT_IS:
159 /* we only support 240 bit so far */
Harald Welte7f2b22b2023-11-26 18:53:30 +0100160 if (in->info_len > out_size - (hdr_len + FCS_SIZE_BYTES))
Harald Weltebe3c38c2023-11-23 22:08:51 +0100161 return -EINVAL;
162 n_s = in->n_s;
163 n_r = in->n_r;
164 s_bits = in->s_ftype;
Harald Welte7f2b22b2023-11-26 18:53:30 +0100165 memcpy(out+hdr_len, in->info, in->info_len);
Harald Weltebe3c38c2023-11-23 22:08:51 +0100166 break;
167 default:
168 return -EINVAL;
169 }
170
171 /* patch N(S) into output data */
172 out[0] |= (n_s & 0x1F) << 3;
173 out[1] |= (n_s & 0x20) >> 5;
174
175 /* patch N(R) / M-bits into output data */
176 out[1] |= (n_r & 0x3f) << 2;
177
178 /* patch S-bits into output data */
179 out[0] |= (s_bits & 3) << 1;
180
181 /* compute FCS + add it to end of frame */
Harald Welte7f2b22b2023-11-26 18:53:30 +0100182 fcs = osmo_rlp_fcs_compute(out, out_size - FCS_SIZE_BYTES);
183 out[out_size - 3] = (fcs >> 0) & 0xff;
184 out[out_size - 2] = (fcs >> 8) & 0xff;
185 out[out_size - 1] = (fcs >> 16) & 0xff;
Harald Weltebe3c38c2023-11-23 22:08:51 +0100186
Harald Welte7f2b22b2023-11-26 18:53:30 +0100187 return out_size;
Harald Weltebe3c38c2023-11-23 22:08:51 +0100188}
189
190
191static const uint32_t rlp_fcs_table[256] = {
192 0x00B29D2D, 0x00643A5B, 0x0044D87A, 0x00927F0C, 0x00051C38, 0x00D3BB4E, 0x00F3596F, 0x0025FE19,
193 0x008694BC, 0x005033CA, 0x0070D1EB, 0x00A6769D, 0x003115A9, 0x00E7B2DF, 0x00C750FE, 0x0011F788,
194 0x00DA8E0F, 0x000C2979, 0x002CCB58, 0x00FA6C2E, 0x006D0F1A, 0x00BBA86C, 0x009B4A4D, 0x004DED3B,
195 0x00EE879E, 0x003820E8, 0x0018C2C9, 0x00CE65BF, 0x0059068B, 0x008FA1FD, 0x00AF43DC, 0x0079E4AA,
196 0x0062BB69, 0x00B41C1F, 0x0094FE3E, 0x00425948, 0x00D53A7C, 0x00039D0A, 0x00237F2B, 0x00F5D85D,
197 0x0056B2F8, 0x0080158E, 0x00A0F7AF, 0x007650D9, 0x00E133ED, 0x0037949B, 0x001776BA, 0x00C1D1CC,
198 0x000AA84B, 0x00DC0F3D, 0x00FCED1C, 0x002A4A6A, 0x00BD295E, 0x006B8E28, 0x004B6C09, 0x009DCB7F,
199 0x003EA1DA, 0x00E806AC, 0x00C8E48D, 0x001E43FB, 0x008920CF, 0x005F87B9, 0x007F6598, 0x00A9C2EE,
200 0x0049DA1E, 0x009F7D68, 0x00BF9F49, 0x0069383F, 0x00FE5B0B, 0x0028FC7D, 0x00081E5C, 0x00DEB92A,
201 0x007DD38F, 0x00AB74F9, 0x008B96D8, 0x005D31AE, 0x00CA529A, 0x001CF5EC, 0x003C17CD, 0x00EAB0BB,
202 0x0021C93C, 0x00F76E4A, 0x00D78C6B, 0x00012B1D, 0x00964829, 0x0040EF5F, 0x00600D7E, 0x00B6AA08,
203 0x0015C0AD, 0x00C367DB, 0x00E385FA, 0x0035228C, 0x00A241B8, 0x0074E6CE, 0x005404EF, 0x0082A399,
204 0x0099FC5A, 0x004F5B2C, 0x006FB90D, 0x00B91E7B, 0x002E7D4F, 0x00F8DA39, 0x00D83818, 0x000E9F6E,
205 0x00ADF5CB, 0x007B52BD, 0x005BB09C, 0x008D17EA, 0x001A74DE, 0x00CCD3A8, 0x00EC3189, 0x003A96FF,
206 0x00F1EF78, 0x0027480E, 0x0007AA2F, 0x00D10D59, 0x00466E6D, 0x0090C91B, 0x00B02B3A, 0x00668C4C,
207 0x00C5E6E9, 0x0013419F, 0x0033A3BE, 0x00E504C8, 0x007267FC, 0x00A4C08A, 0x008422AB, 0x005285DD,
208 0x001F18F0, 0x00C9BF86, 0x00E95DA7, 0x003FFAD1, 0x00A899E5, 0x007E3E93, 0x005EDCB2, 0x00887BC4,
209 0x002B1161, 0x00FDB617, 0x00DD5436, 0x000BF340, 0x009C9074, 0x004A3702, 0x006AD523, 0x00BC7255,
210 0x00770BD2, 0x00A1ACA4, 0x00814E85, 0x0057E9F3, 0x00C08AC7, 0x00162DB1, 0x0036CF90, 0x00E068E6,
211 0x00430243, 0x0095A535, 0x00B54714, 0x0063E062, 0x00F48356, 0x00222420, 0x0002C601, 0x00D46177,
212 0x00CF3EB4, 0x001999C2, 0x00397BE3, 0x00EFDC95, 0x0078BFA1, 0x00AE18D7, 0x008EFAF6, 0x00585D80,
213 0x00FB3725, 0x002D9053, 0x000D7272, 0x00DBD504, 0x004CB630, 0x009A1146, 0x00BAF367, 0x006C5411,
214 0x00A72D96, 0x00718AE0, 0x005168C1, 0x0087CFB7, 0x0010AC83, 0x00C60BF5, 0x00E6E9D4, 0x00304EA2,
215 0x00932407, 0x00458371, 0x00656150, 0x00B3C626, 0x0024A512, 0x00F20264, 0x00D2E045, 0x00044733,
216 0x00E45FC3, 0x0032F8B5, 0x00121A94, 0x00C4BDE2, 0x0053DED6, 0x008579A0, 0x00A59B81, 0x00733CF7,
217 0x00D05652, 0x0006F124, 0x00261305, 0x00F0B473, 0x0067D747, 0x00B17031, 0x00919210, 0x00473566,
218 0x008C4CE1, 0x005AEB97, 0x007A09B6, 0x00ACAEC0, 0x003BCDF4, 0x00ED6A82, 0x00CD88A3, 0x001B2FD5,
219 0x00B84570, 0x006EE206, 0x004E0027, 0x0098A751, 0x000FC465, 0x00D96313, 0x00F98132, 0x002F2644,
220 0x00347987, 0x00E2DEF1, 0x00C23CD0, 0x00149BA6, 0x0083F892, 0x00555FE4, 0x0075BDC5, 0x00A31AB3,
221 0x00007016, 0x00D6D760, 0x00F63541, 0x00209237, 0x00B7F103, 0x00615675, 0x0041B454, 0x00971322,
222 0x005C6AA5, 0x008ACDD3, 0x00AA2FF2, 0x007C8884, 0x00EBEBB0, 0x003D4CC6, 0x001DAEE7, 0x00CB0991,
223 0x00686334, 0x00BEC442, 0x009E2663, 0x00488115, 0x00DFE221, 0x00094557, 0x0029A776, 0x00FF0000
224};
225
226/*! compute RLP FCS according to 3GPP TS 24.022 Section 4.4.
227 * \param[in] in input data over which to compute FCS
228 * \param[in] in_len length of input data (in octets)
229 * \returns computed frame check sequence (FCS). */
230uint32_t osmo_rlp_fcs_compute(const uint8_t *in, size_t in_len)
231{
232 uint32_t divider = 0;
233 size_t i;
234
235 for (i = 0; i < in_len; i++) {
236 uint8_t input = in[i] ^ (divider & 0xff);
237 divider = (divider >> 8) ^ rlp_fcs_table[input];
238 }
239
240 return divider;
241}
242
243/*! @} */