blob: a12c39aa661cf58c5aef088f0f0b15179b0286e5 [file] [log] [blame]
Philippf1f34362016-08-26 17:00:21 +02001/* GPRS SNDCP header compression entity management tools */
2
3/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * Author: Philipp Maier
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <stdio.h>
23#include <string.h>
24#include <stdint.h>
25#include <math.h>
26#include <errno.h>
27#include <stdbool.h>
28
29#include <osmocom/core/linuxlist.h>
30#include <osmocom/core/talloc.h>
31#include <osmocom/core/utils.h>
32
33#include <openbsc/debug.h>
34#include <openbsc/gprs_sndcp_xid.h>
35#include <openbsc/gprs_sndcp_comp.h>
36#include <openbsc/gprs_sndcp_pcomp.h>
Philipp73f83d52016-09-02 13:38:01 +020037#include <openbsc/gprs_sndcp_dcomp.h>
Philippf1f34362016-08-26 17:00:21 +020038
39/* Create a new compression entity from a XID-Field */
40static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx,
41 const struct
42 gprs_sndcp_comp_field
43 *comp_field)
44{
45 struct gprs_sndcp_comp *comp_entity;
46 comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp);
47
48 /* Copy relevant information from the SNDCP-XID field */
49 comp_entity->entity = comp_field->entity;
50 comp_entity->comp_len = comp_field->comp_len;
51 memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp));
52
53 if (comp_field->rfc1144_params) {
54 comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len;
55 memcpy(comp_entity->nsapi,
56 comp_field->rfc1144_params->nsapi,
57 sizeof(comp_entity->nsapi));
58 } else if (comp_field->rfc2507_params) {
59 comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len;
60 memcpy(comp_entity->nsapi,
61 comp_field->rfc2507_params->nsapi,
62 sizeof(comp_entity->nsapi));
63 } else if (comp_field->rohc_params) {
64 comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len;
65 memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi,
66 sizeof(comp_entity->nsapi));
67 } else if (comp_field->v42bis_params) {
68 comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len;
69 memcpy(comp_entity->nsapi,
70 comp_field->v42bis_params->nsapi,
71 sizeof(comp_entity->nsapi));
72 } else if (comp_field->v44_params) {
Philippae9beda2016-09-28 15:10:14 +020073 comp_entity->nsapi_len = comp_field->v44_params->nsapi_len;
Philippf1f34362016-08-26 17:00:21 +020074 memcpy(comp_entity->nsapi,
Philipp7d309352016-11-15 19:37:05 +010075 comp_field->v44_params->nsapi,
Philippf1f34362016-08-26 17:00:21 +020076 sizeof(comp_entity->nsapi));
77 } else {
78 /* The caller is expected to check carefully if the all
79 * data fields required for compression entity creation
80 * are present. Otherwise we blow an assertion here */
81 OSMO_ASSERT(false);
82 }
83 comp_entity->algo = comp_field->algo;
84
85 /* Check if an NSAPI is selected, if not, it does not make sense
86 * to create the compression entity, since the caller should
87 * have checked the presence of the NSAPI, we blow an assertion
88 * in case of missing NSAPIs */
89 OSMO_ASSERT(comp_entity->nsapi_len > 0);
90
91 /* Determine of which class our compression entity will be
92 * (Protocol or Data compresson ?) */
93 comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field);
94
95 OSMO_ASSERT(comp_entity->compclass != -1);
96
97 /* Create an algorithm specific compression context */
98 if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
99 if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) {
100 talloc_free(comp_entity);
101 comp_entity = NULL;
102 }
103 } else {
Philipp73f83d52016-09-02 13:38:01 +0200104 if (gprs_sndcp_dcomp_init(ctx, comp_entity, comp_field) != 0) {
105 talloc_free(comp_entity);
106 comp_entity = NULL;
107 }
Philippf1f34362016-08-26 17:00:21 +0200108 }
109
Philipp Maierd0ef1ed2017-01-23 15:36:37 +0100110 /* Bail on failure */
Philippf1f34362016-08-26 17:00:21 +0200111 if (comp_entity == NULL) {
112 LOGP(DSNDCP, LOGL_ERROR,
Philipp Maierd0ef1ed2017-01-23 15:36:37 +0100113 "Compression entity creation failed!\n");
Philippf1f34362016-08-26 17:00:21 +0200114 return NULL;
115 }
Philipp Maierd0ef1ed2017-01-23 15:36:37 +0100116
117 /* Display info message */
Philippf1f34362016-08-26 17:00:21 +0200118 if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
119 LOGP(DSNDCP, LOGL_INFO,
120 "New header compression entity (%d) created.\n",
121 comp_entity->entity);
122 } else {
123 LOGP(DSNDCP, LOGL_INFO,
124 "New data compression entity (%d) created.\n",
125 comp_entity->entity);
126 }
127
128 return comp_entity;
129}
130
131/* Allocate a compression enitiy list */
132struct llist_head *gprs_sndcp_comp_alloc(const void *ctx)
133{
134 struct llist_head *lh;
135
136 lh = talloc_zero(ctx, struct llist_head);
137 INIT_LLIST_HEAD(lh);
138
139 return lh;
140}
141
142/* Free a compression entitiy list */
143void gprs_sndcp_comp_free(struct llist_head *comp_entities)
144{
145 struct gprs_sndcp_comp *comp_entity;
146
147 /* We expect the caller to take care of allocating a
148 * compression entity list properly. Attempting to
149 * free a non existing list clearly points out
150 * a malfunction. */
151 OSMO_ASSERT(comp_entities);
152
153 llist_for_each_entry(comp_entity, comp_entities, list) {
154 /* Free compression entity */
155 if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
156 LOGP(DSNDCP, LOGL_INFO,
157 "Deleting header compression entity %d ...\n",
158 comp_entity->entity);
159 gprs_sndcp_pcomp_term(comp_entity);
160 } else {
161 LOGP(DSNDCP, LOGL_INFO,
162 "Deleting data compression entity %d ...\n",
163 comp_entity->entity);
Philipp73f83d52016-09-02 13:38:01 +0200164 gprs_sndcp_dcomp_term(comp_entity);
Philippf1f34362016-08-26 17:00:21 +0200165 }
166 }
167
168 talloc_free(comp_entities);
169}
170
171/* Delete a compression entity */
172void gprs_sndcp_comp_delete(struct llist_head *comp_entities,
173 unsigned int entity)
174{
175 struct gprs_sndcp_comp *comp_entity;
176 struct gprs_sndcp_comp *comp_entity_to_delete = NULL;
177
178 OSMO_ASSERT(comp_entities);
179
180 llist_for_each_entry(comp_entity, comp_entities, list) {
181 if (comp_entity->entity == entity) {
182 comp_entity_to_delete = comp_entity;
183 break;
184 }
185 }
186
187 if (!comp_entity_to_delete)
188 return;
189
190 if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
191 LOGP(DSNDCP, LOGL_INFO,
192 "Deleting header compression entity %d ...\n",
193 comp_entity_to_delete->entity);
194 gprs_sndcp_pcomp_term(comp_entity_to_delete);
195 } else {
196 LOGP(DSNDCP, LOGL_INFO,
197 "Deleting data compression entity %d ...\n",
198 comp_entity_to_delete->entity);
199 }
200
201 /* Delete compression entity */
202 llist_del(&comp_entity_to_delete->list);
203 talloc_free(comp_entity_to_delete);
204}
205
206/* Create and Add a new compression entity
207 * (returns a pointer to the compression entity that has just been created) */
208struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx,
209 struct llist_head *comp_entities,
210 const struct gprs_sndcp_comp_field
211 *comp_field)
212{
213 struct gprs_sndcp_comp *comp_entity;
214
215 OSMO_ASSERT(comp_entities);
216 OSMO_ASSERT(comp_field);
217
218 /* Just to be sure, if the entity is already in
219 * the list it will be deleted now */
220 gprs_sndcp_comp_delete(comp_entities, comp_field->entity);
221
222 /* Create and add a new entity to the list */
223 comp_entity = gprs_sndcp_comp_create(ctx, comp_field);
224
225 if (!comp_entity)
226 return NULL;
227
228 llist_add(&comp_entity->list, comp_entities);
229 return comp_entity;
230}
231
232/* Find which compression entity handles the specified pcomp/dcomp */
233struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head
234 *comp_entities, uint8_t comp)
235{
236 struct gprs_sndcp_comp *comp_entity;
237 int i;
238
239 OSMO_ASSERT(comp_entities);
240
241 llist_for_each_entry(comp_entity, comp_entities, list) {
242 for (i = 0; i < comp_entity->comp_len; i++) {
243 if (comp_entity->comp[i] == comp)
244 return comp_entity;
245 }
246 }
247
248 LOGP(DSNDCP, LOGL_ERROR,
249 "Could not find a matching compression entity for given pcomp/dcomp value %d.\n",
250 comp);
251 return NULL;
252}
253
254/* Find which compression entity handles the specified nsapi */
255struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head
256 *comp_entities, uint8_t nsapi)
257{
258 struct gprs_sndcp_comp *comp_entity;
259 int i;
260
261 OSMO_ASSERT(comp_entities);
262
263 llist_for_each_entry(comp_entity, comp_entities, list) {
264 for (i = 0; i < comp_entity->nsapi_len; i++) {
265 if (comp_entity->nsapi[i] == nsapi)
266 return comp_entity;
267 }
268 }
269
270 return NULL;
271}
272
273/* Find a comp_index for a given pcomp/dcomp value */
274uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity,
275 uint8_t comp)
276{
277 /* Note: This function returns a normalized version of the comp value,
278 * which matches up with the position of the comp field. Since comp=0
279 * is reserved for "no compression", the index value starts counting
280 * at one. The return value is the PCOMPn/DCOMPn value one can find
281 * in the Specification (see e.g. 3GPP TS 44.065, 6.5.3.2, Table 7) */
282
283 int i;
284 OSMO_ASSERT(comp_entity);
285
286 /* A pcomp/dcomp value of zero is reserved for "no comproession",
287 * So we just bail and return zero in this case */
288 if (comp == 0)
289 return 0;
290
291 /* Look in the pcomp/dcomp list for the index */
292 for (i = 0; i < comp_entity->comp_len; i++) {
293 if (comp_entity->comp[i] == comp)
294 return i + 1;
295 }
296
297 LOGP(DSNDCP, LOGL_ERROR,
298 "Could not find a matching comp_index for given pcomp/dcomp value %d\n",
299 comp);
300 return 0;
301}
302
303/* Find a pcomp/dcomp value for a given comp_index */
304uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity,
305 uint8_t comp_index)
306{
307 OSMO_ASSERT(comp_entity);
308
309 /* A comp_index of zero translates to zero right away. */
310 if (comp_index == 0)
311 return 0;
312
313 if (comp_index > comp_entity->comp_len) {
314 LOGP(DSNDCP, LOGL_ERROR,
315 "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n",
316 comp_index);
317 return 0;
318 }
319
320 /* Look in the pcomp/dcomp list for the comp_index, see
321 * note in gprs_sndcp_comp_get_idx() */
322 return comp_entity->comp[comp_index - 1];
323}