blob: b13cb8b23810a801eba9f7bcf91f03e31405a2f3 [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) {
73 comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len;
74 memcpy(comp_entity->nsapi,
75 comp_field->v42bis_params->nsapi,
76 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
110 /* Display info message */
111 if (comp_entity == NULL) {
112 LOGP(DSNDCP, LOGL_ERROR,
Philipp73f83d52016-09-02 13:38:01 +0200113 "Compression entity (%d) creation failed!\n",
Philippf1f34362016-08-26 17:00:21 +0200114 comp_entity->entity);
115 return NULL;
116 }
117 if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
118 LOGP(DSNDCP, LOGL_INFO,
119 "New header compression entity (%d) created.\n",
120 comp_entity->entity);
121 } else {
122 LOGP(DSNDCP, LOGL_INFO,
123 "New data compression entity (%d) created.\n",
124 comp_entity->entity);
125 }
126
127 return comp_entity;
128}
129
130/* Allocate a compression enitiy list */
131struct llist_head *gprs_sndcp_comp_alloc(const void *ctx)
132{
133 struct llist_head *lh;
134
135 lh = talloc_zero(ctx, struct llist_head);
136 INIT_LLIST_HEAD(lh);
137
138 return lh;
139}
140
141/* Free a compression entitiy list */
142void gprs_sndcp_comp_free(struct llist_head *comp_entities)
143{
144 struct gprs_sndcp_comp *comp_entity;
145
146 /* We expect the caller to take care of allocating a
147 * compression entity list properly. Attempting to
148 * free a non existing list clearly points out
149 * a malfunction. */
150 OSMO_ASSERT(comp_entities);
151
152 llist_for_each_entry(comp_entity, comp_entities, list) {
153 /* Free compression entity */
154 if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
155 LOGP(DSNDCP, LOGL_INFO,
156 "Deleting header compression entity %d ...\n",
157 comp_entity->entity);
158 gprs_sndcp_pcomp_term(comp_entity);
159 } else {
160 LOGP(DSNDCP, LOGL_INFO,
161 "Deleting data compression entity %d ...\n",
162 comp_entity->entity);
Philipp73f83d52016-09-02 13:38:01 +0200163 gprs_sndcp_dcomp_term(comp_entity);
Philippf1f34362016-08-26 17:00:21 +0200164 }
165 }
166
167 talloc_free(comp_entities);
168}
169
170/* Delete a compression entity */
171void gprs_sndcp_comp_delete(struct llist_head *comp_entities,
172 unsigned int entity)
173{
174 struct gprs_sndcp_comp *comp_entity;
175 struct gprs_sndcp_comp *comp_entity_to_delete = NULL;
176
177 OSMO_ASSERT(comp_entities);
178
179 llist_for_each_entry(comp_entity, comp_entities, list) {
180 if (comp_entity->entity == entity) {
181 comp_entity_to_delete = comp_entity;
182 break;
183 }
184 }
185
186 if (!comp_entity_to_delete)
187 return;
188
189 if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
190 LOGP(DSNDCP, LOGL_INFO,
191 "Deleting header compression entity %d ...\n",
192 comp_entity_to_delete->entity);
193 gprs_sndcp_pcomp_term(comp_entity_to_delete);
194 } else {
195 LOGP(DSNDCP, LOGL_INFO,
196 "Deleting data compression entity %d ...\n",
197 comp_entity_to_delete->entity);
198 }
199
200 /* Delete compression entity */
201 llist_del(&comp_entity_to_delete->list);
202 talloc_free(comp_entity_to_delete);
203}
204
205/* Create and Add a new compression entity
206 * (returns a pointer to the compression entity that has just been created) */
207struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx,
208 struct llist_head *comp_entities,
209 const struct gprs_sndcp_comp_field
210 *comp_field)
211{
212 struct gprs_sndcp_comp *comp_entity;
213
214 OSMO_ASSERT(comp_entities);
215 OSMO_ASSERT(comp_field);
216
217 /* Just to be sure, if the entity is already in
218 * the list it will be deleted now */
219 gprs_sndcp_comp_delete(comp_entities, comp_field->entity);
220
221 /* Create and add a new entity to the list */
222 comp_entity = gprs_sndcp_comp_create(ctx, comp_field);
223
224 if (!comp_entity)
225 return NULL;
226
227 llist_add(&comp_entity->list, comp_entities);
228 return comp_entity;
229}
230
231/* Find which compression entity handles the specified pcomp/dcomp */
232struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head
233 *comp_entities, uint8_t comp)
234{
235 struct gprs_sndcp_comp *comp_entity;
236 int i;
237
238 OSMO_ASSERT(comp_entities);
239
240 llist_for_each_entry(comp_entity, comp_entities, list) {
241 for (i = 0; i < comp_entity->comp_len; i++) {
242 if (comp_entity->comp[i] == comp)
243 return comp_entity;
244 }
245 }
246
247 LOGP(DSNDCP, LOGL_ERROR,
248 "Could not find a matching compression entity for given pcomp/dcomp value %d.\n",
249 comp);
250 return NULL;
251}
252
253/* Find which compression entity handles the specified nsapi */
254struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head
255 *comp_entities, uint8_t nsapi)
256{
257 struct gprs_sndcp_comp *comp_entity;
258 int i;
259
260 OSMO_ASSERT(comp_entities);
261
262 llist_for_each_entry(comp_entity, comp_entities, list) {
263 for (i = 0; i < comp_entity->nsapi_len; i++) {
264 if (comp_entity->nsapi[i] == nsapi)
265 return comp_entity;
266 }
267 }
268
269 return NULL;
270}
271
272/* Find a comp_index for a given pcomp/dcomp value */
273uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity,
274 uint8_t comp)
275{
276 /* Note: This function returns a normalized version of the comp value,
277 * which matches up with the position of the comp field. Since comp=0
278 * is reserved for "no compression", the index value starts counting
279 * at one. The return value is the PCOMPn/DCOMPn value one can find
280 * in the Specification (see e.g. 3GPP TS 44.065, 6.5.3.2, Table 7) */
281
282 int i;
283 OSMO_ASSERT(comp_entity);
284
285 /* A pcomp/dcomp value of zero is reserved for "no comproession",
286 * So we just bail and return zero in this case */
287 if (comp == 0)
288 return 0;
289
290 /* Look in the pcomp/dcomp list for the index */
291 for (i = 0; i < comp_entity->comp_len; i++) {
292 if (comp_entity->comp[i] == comp)
293 return i + 1;
294 }
295
296 LOGP(DSNDCP, LOGL_ERROR,
297 "Could not find a matching comp_index for given pcomp/dcomp value %d\n",
298 comp);
299 return 0;
300}
301
302/* Find a pcomp/dcomp value for a given comp_index */
303uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity,
304 uint8_t comp_index)
305{
306 OSMO_ASSERT(comp_entity);
307
308 /* A comp_index of zero translates to zero right away. */
309 if (comp_index == 0)
310 return 0;
311
312 if (comp_index > comp_entity->comp_len) {
313 LOGP(DSNDCP, LOGL_ERROR,
314 "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n",
315 comp_index);
316 return 0;
317 }
318
319 /* Look in the pcomp/dcomp list for the comp_index, see
320 * note in gprs_sndcp_comp_get_idx() */
321 return comp_entity->comp[comp_index - 1];
322}