blob: a0c35bfbca190297c350c19cce3932d8dd14b621 [file] [log] [blame]
Harald Welte96f71f22010-05-03 19:28:05 +02001/* GPRS SNDCP protocol implementation as per 3GPP TS 04.65 */
2
3/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
Harald Weltece22f922010-06-03 21:21:21 +02004 * (C) 2010 by On-Waves
Harald Welte96f71f22010-05-03 19:28:05 +02005 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * 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
Harald Welte96f71f22010-05-03 19:28:05 +020011 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte96f71f22010-05-03 19:28:05 +020017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * 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/>.
Harald Welte96f71f22010-05-03 19:28:05 +020020 *
21 */
22
23#include <errno.h>
24#include <stdint.h>
Max82040102016-07-06 11:59:18 +020025#include <stdbool.h>
Harald Welte96f71f22010-05-03 19:28:05 +020026
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010027#include <osmocom/core/msgb.h>
28#include <osmocom/core/linuxlist.h>
29#include <osmocom/core/timer.h>
30#include <osmocom/core/talloc.h>
Pau Espin Pedrol4be5ab32021-02-04 12:49:40 +010031#include <osmocom/core/endian.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080032#include <osmocom/gprs/gprs_bssgp.h>
Harald Welte96f71f22010-05-03 19:28:05 +020033
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020034#include <osmocom/sgsn/debug.h>
Pau Espin Pedrol4398ac02022-12-23 17:12:39 +010035#include <osmocom/sgsn/gprs_ns.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020036#include <osmocom/sgsn/gprs_llc.h>
37#include <osmocom/sgsn/sgsn.h>
38#include <osmocom/sgsn/gprs_sndcp.h>
39#include <osmocom/sgsn/gprs_llc_xid.h>
40#include <osmocom/sgsn/gprs_sndcp_xid.h>
41#include <osmocom/sgsn/gprs_sndcp_pcomp.h>
42#include <osmocom/sgsn/gprs_sndcp_dcomp.h>
43#include <osmocom/sgsn/gprs_sndcp_comp.h>
Pau Espin Pedrol05d5f282022-12-23 17:09:08 +010044#include <osmocom/sgsn/gprs_gmm.h>
Philippf1f34362016-08-26 17:00:21 +020045
46#define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */
47
48#if DEBUG_IP_PACKETS == 1
49/* Calculate TCP/IP checksum */
50static uint16_t calc_ip_csum(uint8_t *data, int len)
51{
52 int i;
53 uint32_t accumulator = 0;
54 uint16_t *pointer = (uint16_t *) data;
55
56 for (i = len; i > 1; i -= 2) {
57 accumulator += *pointer;
58 pointer++;
59 }
60
61 if (len % 2)
62 accumulator += *pointer;
63
64 accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff);
65 accumulator += (accumulator >> 16) & 0xffff;
66 return (~accumulator);
67}
68
69/* Calculate TCP/IP checksum */
Maxcaff83e2022-10-09 13:32:09 +030070static uint16_t calc_tcpip_csum(const void *ctx, const uint8_t *packet, int len)
Philippf1f34362016-08-26 17:00:21 +020071{
72 uint8_t *buf;
73 uint16_t csum;
74
75 buf = talloc_zero_size(ctx, len);
76 memset(buf, 0, len);
77 memcpy(buf, packet + 12, 8);
78 buf[9] = packet[9];
79 buf[11] = (len - 20) & 0xFF;
80 buf[10] = (len - 20) >> 8 & 0xFF;
81 memcpy(buf + 12, packet + 20, len - 20);
82 csum = calc_ip_csum(buf, len - 20 + 12);
83 talloc_free(buf);
84 return csum;
85}
86
87/* Show some ip packet details */
Maxcaff83e2022-10-09 13:32:09 +030088static void debug_ip_packet(const uint8_t *data, int len, int dir, const char *info)
Philippf1f34362016-08-26 17:00:21 +020089{
90 uint8_t tcp_flags;
91 char flags_debugmsg[256];
92 int len_short;
93 static unsigned int packet_count = 0;
94 static unsigned int tcp_csum_err_count = 0;
95 static unsigned int ip_csum_err_count = 0;
96
97 packet_count++;
98
99 if (len > 80)
100 len_short = 80;
101 else
102 len_short = len;
103
104 if (dir)
105 DEBUGP(DSNDCP, "%s: MS => SGSN: %s\n", info,
106 osmo_hexdump_nospc(data, len_short));
107 else
108 DEBUGP(DSNDCP, "%s: MS <= SGSN: %s\n", info,
109 osmo_hexdump_nospc(data, len_short));
110
111 DEBUGP(DSNDCP, "%s: Length.: %d\n", info, len);
112 DEBUGP(DSNDCP, "%s: NO.: %d\n", info, packet_count);
113
114 if (len < 20) {
115 DEBUGP(DSNDCP, "%s: Error: Short IP packet!\n", info);
116 return;
117 }
118
119 if (calc_ip_csum(data, 20) != 0) {
120 DEBUGP(DSNDCP, "%s: Bad IP-Header checksum!\n", info);
121 ip_csum_err_count++;
122 } else
123 DEBUGP(DSNDCP, "%s: IP-Header checksum ok.\n", info);
124
125 if (data[9] == 0x06) {
126 if (len < 40) {
127 DEBUGP(DSNDCP, "%s: Error: Short TCP packet!\n", info);
128 return;
129 }
130
131 DEBUGP(DSNDCP, "%s: Protocol type: TCP\n", info);
132 tcp_flags = data[33];
133
134 if (calc_tcpip_csum(NULL, data, len) != 0) {
135 DEBUGP(DSNDCP, "%s: Bad TCP checksum!\n", info);
136 tcp_csum_err_count++;
137 } else
138 DEBUGP(DSNDCP, "%s: TCP checksum ok.\n", info);
139
140 memset(flags_debugmsg, 0, sizeof(flags_debugmsg));
141 if (tcp_flags & 1)
142 strcat(flags_debugmsg, "FIN ");
143 if (tcp_flags & 2)
144 strcat(flags_debugmsg, "SYN ");
145 if (tcp_flags & 4)
146 strcat(flags_debugmsg, "RST ");
147 if (tcp_flags & 8)
148 strcat(flags_debugmsg, "PSH ");
149 if (tcp_flags & 16)
150 strcat(flags_debugmsg, "ACK ");
151 if (tcp_flags & 32)
152 strcat(flags_debugmsg, "URG ");
153 DEBUGP(DSNDCP, "%s: FLAGS: %s\n", info, flags_debugmsg);
154 } else if (data[9] == 0x11) {
155 DEBUGP(DSNDCP, "%s: Protocol type: UDP\n", info);
156 } else {
157 DEBUGP(DSNDCP, "%s: Protocol type: (%02x)\n", info, data[9]);
158 }
159
160 DEBUGP(DSNDCP, "%s: IP-Header checksum errors: %d\n", info,
161 ip_csum_err_count);
162 DEBUGP(DSNDCP, "%s: TCP-Checksum errors: %d\n", info,
163 tcp_csum_err_count);
164}
165#endif
Harald Weltef78a3b22010-06-30 17:21:19 +0200166
Harald Welte96f71f22010-05-03 19:28:05 +0200167/* Chapter 7.2: SN-PDU Formats */
168struct sndcp_common_hdr {
Pau Espin Pedrol4be5ab32021-02-04 12:49:40 +0100169#if OSMO_IS_LITTLE_ENDIAN
Harald Welte96f71f22010-05-03 19:28:05 +0200170 /* octet 1 */
171 uint8_t nsapi:4;
172 uint8_t more:1;
173 uint8_t type:1;
174 uint8_t first:1;
175 uint8_t spare:1;
Pau Espin Pedrol4be5ab32021-02-04 12:49:40 +0100176#elif OSMO_IS_BIG_ENDIAN
177/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
178 uint8_t spare:1, first:1, type:1, more:1, nsapi:4;
179#endif
Harald Weltece22f922010-06-03 21:21:21 +0200180} __attribute__((packed));
181
182/* PCOMP / DCOMP only exist in first fragment */
183struct sndcp_comp_hdr {
Pau Espin Pedrol4be5ab32021-02-04 12:49:40 +0100184#if OSMO_IS_LITTLE_ENDIAN
Harald Welte96f71f22010-05-03 19:28:05 +0200185 /* octet 2 */
Harald Welte5cc2bc32010-06-02 23:17:05 +0200186 uint8_t pcomp:4;
187 uint8_t dcomp:4;
Pau Espin Pedrol4be5ab32021-02-04 12:49:40 +0100188#elif OSMO_IS_BIG_ENDIAN
189/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
190 uint8_t dcomp:4, pcomp:4;
191#endif
Harald Welteebabdea2010-06-01 18:28:10 +0200192} __attribute__((packed));
Harald Welte96f71f22010-05-03 19:28:05 +0200193
194struct sndcp_udata_hdr {
Pau Espin Pedrol4be5ab32021-02-04 12:49:40 +0100195#if OSMO_IS_LITTLE_ENDIAN
Harald Welte96f71f22010-05-03 19:28:05 +0200196 /* octet 3 */
197 uint8_t npdu_high:4;
198 uint8_t seg_nr:4;
199 /* octet 4 */
200 uint8_t npdu_low;
Pau Espin Pedrol4be5ab32021-02-04 12:49:40 +0100201#elif OSMO_IS_BIG_ENDIAN
202/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
203 uint8_t seg_nr:4, npdu_high:4;
204 uint8_t npdu_low;
205#endif
Harald Welteebabdea2010-06-01 18:28:10 +0200206} __attribute__((packed));
207
Harald Welteebabdea2010-06-01 18:28:10 +0200208
209static void *tall_sndcp_ctx;
210
211/* A fragment queue entry, containing one framgent of a N-PDU */
Harald Weltece22f922010-06-03 21:21:21 +0200212struct defrag_queue_entry {
Harald Welteebabdea2010-06-01 18:28:10 +0200213 struct llist_head list;
Harald Weltece22f922010-06-03 21:21:21 +0200214 /* segment number of this fragment */
215 uint32_t seg_nr;
216 /* length of the data area of this fragment */
Harald Welteebabdea2010-06-01 18:28:10 +0200217 uint32_t data_len;
Harald Weltece22f922010-06-03 21:21:21 +0200218 /* pointer to the data of this fragment */
219 uint8_t *data;
Harald Welteebabdea2010-06-01 18:28:10 +0200220};
221
Harald Weltef78a3b22010-06-30 17:21:19 +0200222LLIST_HEAD(gprs_sndcp_entities);
Harald Welte96f71f22010-05-03 19:28:05 +0200223
Philippf1f34362016-08-26 17:00:21 +0200224/* Check if any compression parameters are set in the sgsn configuration */
Maxcaff83e2022-10-09 13:32:09 +0300225static inline int any_pcomp_or_dcomp_active(const struct sgsn_instance *sgsn)
226{
Philipp73f83d52016-09-02 13:38:01 +0200227 if (sgsn->cfg.pcomp_rfc1144.active || sgsn->cfg.pcomp_rfc1144.passive ||
228 sgsn->cfg.dcomp_v42bis.active || sgsn->cfg.dcomp_v42bis.passive)
Philippf1f34362016-08-26 17:00:21 +0200229 return true;
230 else
231 return false;
232}
233
Harald Weltece22f922010-06-03 21:21:21 +0200234/* Enqueue a fragment into the defragment queue */
Harald Weltef78a3b22010-06-30 17:21:19 +0200235static int defrag_enqueue(struct gprs_sndcp_entity *sne, uint8_t seg_nr,
Harald Welte3d6815a2010-07-02 17:16:07 +0200236 uint8_t *data, uint32_t data_len)
Harald Welteebabdea2010-06-01 18:28:10 +0200237{
Harald Weltece22f922010-06-03 21:21:21 +0200238 struct defrag_queue_entry *dqe;
Harald Welteebabdea2010-06-01 18:28:10 +0200239
Harald Weltece22f922010-06-03 21:21:21 +0200240 dqe = talloc_zero(tall_sndcp_ctx, struct defrag_queue_entry);
241 if (!dqe)
242 return -ENOMEM;
243 dqe->data = talloc_zero_size(dqe, data_len);
244 if (!dqe->data) {
245 talloc_free(dqe);
246 return -ENOMEM;
247 }
248 dqe->seg_nr = seg_nr;
249 dqe->data_len = data_len;
250
251 llist_add(&dqe->list, &sne->defrag.frag_list);
252
253 if (seg_nr > sne->defrag.highest_seg)
254 sne->defrag.highest_seg = seg_nr;
255
256 sne->defrag.seg_have |= (1 << seg_nr);
257 sne->defrag.tot_len += data_len;
258
Harald Welte8f0c0a32010-07-02 10:29:06 +0200259 memcpy(dqe->data, data, data_len);
260
Harald Weltece22f922010-06-03 21:21:21 +0200261 return 0;
Harald Welteebabdea2010-06-01 18:28:10 +0200262}
263
Harald Weltece22f922010-06-03 21:21:21 +0200264/* return if we have all segments of this N-PDU */
Maxcaff83e2022-10-09 13:32:09 +0300265static int defrag_have_all_segments(const struct gprs_sndcp_entity *sne)
Harald Welteebabdea2010-06-01 18:28:10 +0200266{
Harald Weltece22f922010-06-03 21:21:21 +0200267 uint32_t seg_needed = 0;
268 unsigned int i;
Harald Welteebabdea2010-06-01 18:28:10 +0200269
Harald Weltece22f922010-06-03 21:21:21 +0200270 /* create a bitmask of needed segments */
Harald Welte951a12c2010-07-01 15:09:45 +0200271 for (i = 0; i <= sne->defrag.highest_seg; i++)
Harald Weltece22f922010-06-03 21:21:21 +0200272 seg_needed |= (1 << i);
273
274 if (seg_needed == sne->defrag.seg_have)
275 return 1;
276
277 return 0;
Harald Welteebabdea2010-06-01 18:28:10 +0200278}
279
Maxcaff83e2022-10-09 13:32:09 +0300280static struct defrag_queue_entry *defrag_get_seg(const struct gprs_sndcp_entity *sne,
Harald Weltece22f922010-06-03 21:21:21 +0200281 uint32_t seg_nr)
Harald Welteebabdea2010-06-01 18:28:10 +0200282{
Harald Weltece22f922010-06-03 21:21:21 +0200283 struct defrag_queue_entry *dqe;
284
285 llist_for_each_entry(dqe, &sne->defrag.frag_list, list) {
286 if (dqe->seg_nr == seg_nr) {
287 llist_del(&dqe->list);
288 return dqe;
289 }
290 }
291 return NULL;
Harald Welteebabdea2010-06-01 18:28:10 +0200292}
Harald Weltece22f922010-06-03 21:21:21 +0200293
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100294/* Returns talloced buffer containing decompressed data, NULL on error. */
295static uint8_t *decompress_segment(struct gprs_sndcp_entity *sne, void *ctx,
296 const uint8_t *compressed_data, unsigned int compressed_data_len,
297 unsigned int *decompressed_data_len)
298{
299 int rc;
300 uint8_t *expnd = NULL;
301 *decompressed_data_len = 0;
302
303#if DEBUG_IP_PACKETS == 1
304 DEBUGP(DSNDCP, "\n");
305 DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
306 DEBUGP(DSNDCP, "===================================================\n");
307#endif
308
309 expnd = talloc_zero_size(ctx, compressed_data_len * MAX_DATADECOMPR_FAC +
310 MAX_HDRDECOMPR_INCR);
311 memcpy(expnd, compressed_data, compressed_data_len);
312
313 /* Apply data decompression */
314 rc = gprs_sndcp_dcomp_expand(expnd, compressed_data_len, sne->defrag.dcomp,
315 sne->defrag.data);
316 if (rc < 0) {
317 LOGP(DSNDCP, LOGL_ERROR,
318 "Data decompression failed!\n");
319 talloc_free(expnd);
320 return NULL;
321 }
322
323 /* Apply header decompression */
324 rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp, sne->defrag.proto);
325 if (rc < 0) {
326 LOGP(DSNDCP, LOGL_ERROR,
327 "TCP/IP Header decompression failed!\n");
328 talloc_free(expnd);
329 return NULL;
330 }
331
332 *decompressed_data_len = rc;
333
334#if DEBUG_IP_PACKETS == 1
335 debug_ip_packet(expnd, *decompressed_data_len, 1, "defrag_segments()");
336 DEBUGP(DSNDCP, "===================================================\n");
337 DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
338 DEBUGP(DSNDCP, "\n");
339#endif
340 return expnd;
341}
342
Harald Welte8b705f22010-07-02 16:18:59 +0200343/* Perform actual defragmentation and create an output packet */
Harald Weltef78a3b22010-06-30 17:21:19 +0200344static int defrag_segments(struct gprs_sndcp_entity *sne)
Harald Weltece22f922010-06-03 21:21:21 +0200345{
346 struct msgb *msg;
347 unsigned int seg_nr;
348 uint8_t *npdu;
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100349 unsigned int npdu_len;
Philippf1f34362016-08-26 17:00:21 +0200350 int rc;
351 uint8_t *expnd = NULL;
Harald Weltece22f922010-06-03 21:21:21 +0200352
Harald Welteab4094c2010-07-02 16:01:47 +0200353 LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u "
354 "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi,
355 sne->defrag.npdu, sne->defrag.highest_seg, sne->defrag.tot_len);
Sylvain Munauteda125c2010-06-09 20:56:52 +0200356 msg = msgb_alloc_headroom(sne->defrag.tot_len+256, 128, "SNDCP Defrag");
Harald Weltece22f922010-06-03 21:21:21 +0200357 if (!msg)
358 return -ENOMEM;
359
360 /* FIXME: message headers + identifiers */
361
362 npdu = msg->data;
363
Harald Welte993697c2010-07-02 10:11:42 +0200364 for (seg_nr = 0; seg_nr <= sne->defrag.highest_seg; seg_nr++) {
Harald Weltece22f922010-06-03 21:21:21 +0200365 struct defrag_queue_entry *dqe;
366 uint8_t *data;
367
368 dqe = defrag_get_seg(sne, seg_nr);
369 if (!dqe) {
370 LOGP(DSNDCP, LOGL_ERROR, "Segment %u missing\n", seg_nr);
Holger Hans Peter Freythera8ddb082012-03-01 20:30:32 +0100371 msgb_free(msg);
Harald Weltece22f922010-06-03 21:21:21 +0200372 return -EIO;
373 }
374 /* actually append the segment to the N-PDU */
375 data = msgb_put(msg, dqe->data_len);
376 memcpy(data, dqe->data, dqe->data_len);
377
378 /* release memory for the fragment queue entry */
379 talloc_free(dqe);
380 }
381
Philippf1f34362016-08-26 17:00:21 +0200382 npdu_len = sne->defrag.tot_len;
383
Harald Welte8b705f22010-07-02 16:18:59 +0200384 /* FIXME: cancel timer */
385
Harald Weltece22f922010-06-03 21:21:21 +0200386 /* actually send the N-PDU to the SGSN core code, which then
387 * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */
Philippf1f34362016-08-26 17:00:21 +0200388
389 /* Decompress packet */
Philippf1f34362016-08-26 17:00:21 +0200390 if (any_pcomp_or_dcomp_active(sgsn)) {
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100391 expnd = decompress_segment(sne, msg, npdu, npdu_len, &npdu_len);
392 if (!expnd) {
393 rc = -EIO;
394 goto ret_free;
Philipp73f83d52016-09-02 13:38:01 +0200395 }
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100396 } else {
Philippf1f34362016-08-26 17:00:21 +0200397 expnd = npdu;
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100398 }
Philippf1f34362016-08-26 17:00:21 +0200399
400 /* Hand off packet to gtp */
401 rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli,
402 sne->nsapi, msg, npdu_len, expnd);
403
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100404ret_free:
Harald Welte627e2852020-06-08 20:46:53 +0200405 /* we must free the memory we allocated above; ownership is not transferred
406 * downwards in the call above */
407 msgb_free(msg);
408
Philipp Maieref6205b2020-10-02 17:35:25 +0200409 /* Note: We do not have to free expnd explicitly, because it is created
410 * within the talloc context of msg, which we just freed. */
Philippf1f34362016-08-26 17:00:21 +0200411
412 return rc;
Harald Weltece22f922010-06-03 21:21:21 +0200413}
414
Philippf1f34362016-08-26 17:00:21 +0200415static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg,
416 uint8_t *hdr, unsigned int len)
Harald Weltece22f922010-06-03 21:21:21 +0200417{
418 struct sndcp_common_hdr *sch;
Harald Weltece22f922010-06-03 21:21:21 +0200419 struct sndcp_udata_hdr *suh;
420 uint16_t npdu_num;
421 uint8_t *data;
422 int rc;
423
424 sch = (struct sndcp_common_hdr *) hdr;
425 if (sch->first) {
Harald Weltece22f922010-06-03 21:21:21 +0200426 suh = (struct sndcp_udata_hdr *) (hdr + 1 + sizeof(struct sndcp_common_hdr));
427 } else
428 suh = (struct sndcp_udata_hdr *) (hdr + sizeof(struct sndcp_common_hdr));
429
430 data = (uint8_t *)suh + sizeof(struct sndcp_udata_hdr);
431
432 npdu_num = (suh->npdu_high << 8) | suh->npdu_low;
433
Harald Welteab4094c2010-07-02 16:01:47 +0200434 LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Input PDU %u Segment %u "
435 "Length %u %s %s\n", sne->lle->llme->tlli, sne->nsapi, npdu_num,
436 suh->seg_nr, len, sch->first ? "F " : "", sch->more ? "M" : "");
Harald Welteb87bc862010-07-01 20:29:20 +0200437
Harald Weltece22f922010-06-03 21:21:21 +0200438 if (sch->first) {
439 /* first segment of a new packet. Discard all leftover fragments of
440 * previous packet */
441 if (!llist_empty(&sne->defrag.frag_list)) {
Harald Welte65d96782010-07-01 12:19:02 +0200442 struct defrag_queue_entry *dqe, *dqe2;
Harald Welteb87bc862010-07-01 20:29:20 +0200443 LOGP(DSNDCP, LOGL_INFO, "TLLI=0x%08x NSAPI=%u: Dropping "
444 "SN-PDU %u due to insufficient segments (%04x)\n",
445 sne->lle->llme->tlli, sne->nsapi, sne->defrag.npdu,
446 sne->defrag.seg_have);
Harald Welte65d96782010-07-01 12:19:02 +0200447 llist_for_each_entry_safe(dqe, dqe2, &sne->defrag.frag_list, list) {
Harald Weltece22f922010-06-03 21:21:21 +0200448 llist_del(&dqe->list);
449 talloc_free(dqe);
450 }
451 }
452 /* store the currently de-fragmented PDU number */
453 sne->defrag.npdu = npdu_num;
Harald Welte8b705f22010-07-02 16:18:59 +0200454
455 /* Re-set fragmentation state */
Harald Weltece22f922010-06-03 21:21:21 +0200456 sne->defrag.no_more = sne->defrag.highest_seg = sne->defrag.seg_have = 0;
Harald Welte8b705f22010-07-02 16:18:59 +0200457 sne->defrag.tot_len = 0;
458 /* FIXME: (re)start timer */
Harald Weltece22f922010-06-03 21:21:21 +0200459 }
460
461 if (sne->defrag.npdu != npdu_num) {
462 LOGP(DSNDCP, LOGL_INFO, "Segment for different SN-PDU "
463 "(%u != %u)\n", npdu_num, sne->defrag.npdu);
464 /* FIXME */
465 }
466
467 /* FIXME: check if seg_nr already exists */
Harald Welte3d6815a2010-07-02 17:16:07 +0200468 /* make sure to subtract length of SNDCP header from 'len' */
469 rc = defrag_enqueue(sne, suh->seg_nr, data, len - (data - hdr));
Harald Weltece22f922010-06-03 21:21:21 +0200470 if (rc < 0)
471 return rc;
472
473 if (!sch->more) {
474 /* this is suppsed to be the last segment of the N-PDU, but it
475 * might well be not the last to arrive */
476 sne->defrag.no_more = 1;
477 }
478
479 if (sne->defrag.no_more) {
480 /* we have already received the last segment before, let's check
481 * if all the previous segments exist */
482 if (defrag_have_all_segments(sne))
483 return defrag_segments(sne);
484 }
485
486 return 0;
487}
Harald Welteebabdea2010-06-01 18:28:10 +0200488
Harald Weltef78a3b22010-06-30 17:21:19 +0200489static struct gprs_sndcp_entity *gprs_sndcp_entity_by_lle(const struct gprs_llc_lle *lle,
Harald Welteebabdea2010-06-01 18:28:10 +0200490 uint8_t nsapi)
491{
Harald Weltef78a3b22010-06-30 17:21:19 +0200492 struct gprs_sndcp_entity *sne;
Harald Welteebabdea2010-06-01 18:28:10 +0200493
Harald Weltef78a3b22010-06-30 17:21:19 +0200494 llist_for_each_entry(sne, &gprs_sndcp_entities, list) {
Harald Welteebabdea2010-06-01 18:28:10 +0200495 if (sne->lle == lle && sne->nsapi == nsapi)
496 return sne;
497 }
498 return NULL;
499}
500
Harald Weltef78a3b22010-06-30 17:21:19 +0200501static struct gprs_sndcp_entity *gprs_sndcp_entity_alloc(struct gprs_llc_lle *lle,
Harald Welteebabdea2010-06-01 18:28:10 +0200502 uint8_t nsapi)
503{
Harald Weltef78a3b22010-06-30 17:21:19 +0200504 struct gprs_sndcp_entity *sne;
Harald Welteebabdea2010-06-01 18:28:10 +0200505
Harald Weltef78a3b22010-06-30 17:21:19 +0200506 sne = talloc_zero(tall_sndcp_ctx, struct gprs_sndcp_entity);
Harald Welteebabdea2010-06-01 18:28:10 +0200507 if (!sne)
508 return NULL;
509
510 sne->lle = lle;
511 sne->nsapi = nsapi;
Harald Weltece22f922010-06-03 21:21:21 +0200512 sne->defrag.timer.data = sne;
Harald Welteebabdea2010-06-01 18:28:10 +0200513 //sne->fqueue.timer.cb = FIXME;
514 sne->rx_state = SNDCP_RX_S_FIRST;
Harald Welte362aea02010-07-01 12:31:10 +0200515 INIT_LLIST_HEAD(&sne->defrag.frag_list);
Harald Welteebabdea2010-06-01 18:28:10 +0200516
Harald Weltef78a3b22010-06-30 17:21:19 +0200517 llist_add(&sne->list, &gprs_sndcp_entities);
Harald Welte61444522010-06-02 12:40:48 +0200518
Harald Welteebabdea2010-06-01 18:28:10 +0200519 return sne;
520}
521
522/* Entry point for the SNSM-ACTIVATE.indication */
523int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
524{
Harald Welte61444522010-06-02 12:40:48 +0200525 LOGP(DSNDCP, LOGL_INFO, "SNSM-ACTIVATE.ind (lle=%p TLLI=%08x, "
526 "SAPI=%u, NSAPI=%u)\n", lle, lle->llme->tlli, lle->sapi, nsapi);
Harald Welteebabdea2010-06-01 18:28:10 +0200527
Harald Weltef78a3b22010-06-30 17:21:19 +0200528 if (gprs_sndcp_entity_by_lle(lle, nsapi)) {
Harald Welte16836a32010-06-02 10:25:40 +0200529 LOGP(DSNDCP, LOGL_ERROR, "Trying to ACTIVATE "
530 "already-existing entity (TLLI=%08x, NSAPI=%u)\n",
531 lle->llme->tlli, nsapi);
532 return -EEXIST;
533 }
534
Harald Weltef78a3b22010-06-30 17:21:19 +0200535 if (!gprs_sndcp_entity_alloc(lle, nsapi)) {
Harald Welte16836a32010-06-02 10:25:40 +0200536 LOGP(DSNDCP, LOGL_ERROR, "Out of memory during ACTIVATE\n");
Harald Welteebabdea2010-06-01 18:28:10 +0200537 return -ENOMEM;
Harald Welte16836a32010-06-02 10:25:40 +0200538 }
Harald Welteebabdea2010-06-01 18:28:10 +0200539
540 return 0;
541}
542
Harald Weltece22f922010-06-03 21:21:21 +0200543/* Entry point for the SNSM-DEACTIVATE.indication */
Maxcaff83e2022-10-09 13:32:09 +0300544int sndcp_sm_deactivate_ind(const struct gprs_llc_lle *lle, uint8_t nsapi)
Harald Weltece22f922010-06-03 21:21:21 +0200545{
Harald Weltef78a3b22010-06-30 17:21:19 +0200546 struct gprs_sndcp_entity *sne;
Harald Weltece22f922010-06-03 21:21:21 +0200547
548 LOGP(DSNDCP, LOGL_INFO, "SNSM-DEACTIVATE.ind (lle=%p, TLLI=%08x, "
549 "SAPI=%u, NSAPI=%u)\n", lle, lle->llme->tlli, lle->sapi, nsapi);
550
Harald Weltef78a3b22010-06-30 17:21:19 +0200551 sne = gprs_sndcp_entity_by_lle(lle, nsapi);
Harald Weltece22f922010-06-03 21:21:21 +0200552 if (!sne) {
553 LOGP(DSNDCP, LOGL_ERROR, "SNSM-DEACTIVATE.ind for non-"
554 "existing TLLI=%08x SAPI=%u NSAPI=%u\n", lle->llme->tlli,
555 lle->sapi, nsapi);
556 return -ENOENT;
557 }
558 llist_del(&sne->list);
559 /* frag queue entries are hierarchically allocated, so no need to
560 * free them explicitly here */
561 talloc_free(sne);
562
563 return 0;
564}
565
Oliver Smithf7642852021-12-07 13:16:17 +0100566/* Clean up all gprs_sndcp_entities related to llme (OS#4824) */
Maxcaff83e2022-10-09 13:32:09 +0300567void gprs_sndcp_sm_deactivate_ind_by_llme(const struct gprs_llc_llme *llme)
Oliver Smithf7642852021-12-07 13:16:17 +0100568{
569 struct gprs_sndcp_entity *sne, *sne2;
570
571 llist_for_each_entry_safe(sne, sne2, &gprs_sndcp_entities, list) {
572 if (sne->lle->llme == llme) {
573 LOGP(DSNDCP, LOGL_INFO, "SNSM-DEACTIVATE.ind for SNDCP attached to llme=%p\n", llme);
574 /* Free and remove from list */
575 sndcp_sm_deactivate_ind(sne->lle, sne->nsapi);
576 }
577 }
578}
579
Harald Weltece22f922010-06-03 21:21:21 +0200580/* Fragmenter state */
581struct sndcp_frag_state {
582 uint8_t frag_nr;
583 struct msgb *msg; /* original message */
584 uint8_t *next_byte; /* first byte of next fragment */
585
Harald Weltef78a3b22010-06-30 17:21:19 +0200586 struct gprs_sndcp_entity *sne;
Harald Weltece22f922010-06-03 21:21:21 +0200587 void *mmcontext;
588};
589
590/* returns '1' if there are more fragments to send, '0' if none */
Philippf1f34362016-08-26 17:00:21 +0200591static int sndcp_send_ud_frag(struct sndcp_frag_state *fs,
592 uint8_t pcomp, uint8_t dcomp)
Harald Weltece22f922010-06-03 21:21:21 +0200593{
Harald Weltef78a3b22010-06-30 17:21:19 +0200594 struct gprs_sndcp_entity *sne = fs->sne;
Harald Weltece22f922010-06-03 21:21:21 +0200595 struct gprs_llc_lle *lle = sne->lle;
596 struct sndcp_common_hdr *sch;
597 struct sndcp_comp_hdr *scomph;
598 struct sndcp_udata_hdr *suh;
599 struct msgb *fmsg;
600 unsigned int max_payload_len;
601 unsigned int len;
602 uint8_t *data;
603 int rc, more;
604
Sylvain Munauteda125c2010-06-09 20:56:52 +0200605 fmsg = msgb_alloc_headroom(fs->sne->lle->params.n201_u+256, 128,
Harald Weltece22f922010-06-03 21:21:21 +0200606 "SNDCP Frag");
Holger Hans Peter Freytherf9ffd1f2014-10-10 17:35:54 +0200607 if (!fmsg) {
608 msgb_free(fs->msg);
Harald Weltece22f922010-06-03 21:21:21 +0200609 return -ENOMEM;
Holger Hans Peter Freytherf9ffd1f2014-10-10 17:35:54 +0200610 }
Harald Weltece22f922010-06-03 21:21:21 +0200611
612 /* make sure lower layers route the fragment like the original */
613 msgb_tlli(fmsg) = msgb_tlli(fs->msg);
614 msgb_bvci(fmsg) = msgb_bvci(fs->msg);
615 msgb_nsei(fmsg) = msgb_nsei(fs->msg);
616
617 /* prepend common SNDCP header */
618 sch = (struct sndcp_common_hdr *) msgb_put(fmsg, sizeof(*sch));
619 sch->nsapi = sne->nsapi;
620 /* Set FIRST bit if we are the first fragment in a series */
621 if (fs->frag_nr == 0)
622 sch->first = 1;
623 sch->type = 1;
624
625 /* append the compression header for first fragment */
626 if (sch->first) {
627 scomph = (struct sndcp_comp_hdr *)
628 msgb_put(fmsg, sizeof(*scomph));
Philippf1f34362016-08-26 17:00:21 +0200629 scomph->pcomp = pcomp;
630 scomph->dcomp = dcomp;
Harald Weltece22f922010-06-03 21:21:21 +0200631 }
632
633 /* append the user-data header */
634 suh = (struct sndcp_udata_hdr *) msgb_put(fmsg, sizeof(*suh));
635 suh->npdu_low = sne->tx_npdu_nr & 0xff;
636 suh->npdu_high = (sne->tx_npdu_nr >> 8) & 0xf;
637 suh->seg_nr = fs->frag_nr % 0xf;
638
639 /* calculate remaining length to be sent */
640 len = (fs->msg->data + fs->msg->len) - fs->next_byte;
641 /* how much payload can we actually send via LLC? */
642 max_payload_len = lle->params.n201_u - (sizeof(*sch) + sizeof(*suh));
643 if (sch->first)
644 max_payload_len -= sizeof(*scomph);
645 /* check if we're exceeding the max */
646 if (len > max_payload_len)
647 len = max_payload_len;
648
649 /* copy the actual fragment data into our fmsg */
650 data = msgb_put(fmsg, len);
651 memcpy(data, fs->next_byte, len);
652
653 /* Increment fragment number and data pointer to next fragment */
654 fs->frag_nr++;
655 fs->next_byte += len;
656
657 /* determine if we have more fragemnts to send */
658 if ((fs->msg->data + fs->msg->len) <= fs->next_byte)
659 more = 0;
660 else
661 more = 1;
662
663 /* set the MORE bit of the SNDCP header accordingly */
664 sch->more = more;
665
Max82040102016-07-06 11:59:18 +0200666 rc = gprs_llc_tx_ui(fmsg, lle->sapi, 0, fs->mmcontext, true);
Holger Hans Peter Freytherf9ffd1f2014-10-10 17:35:54 +0200667 /* abort in case of error, do not advance frag_nr / next_byte */
Harald Weltece22f922010-06-03 21:21:21 +0200668 if (rc < 0) {
Holger Hans Peter Freytherf9ffd1f2014-10-10 17:35:54 +0200669 msgb_free(fs->msg);
Harald Weltece22f922010-06-03 21:21:21 +0200670 return rc;
671 }
672
673 if (!more) {
674 /* we've sent all fragments */
675 msgb_free(fs->msg);
676 memset(fs, 0, sizeof(*fs));
677 /* increment NPDU number for next frame */
678 sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff;
679 return 0;
680 }
681
682 /* default: more fragments to send */
683 return 1;
684}
685
Harald Weltedb2c39f2010-06-03 07:14:59 +0200686/* Request transmission of a SN-PDU over specified LLC Entity + SAPI */
Harald Weltebb1c8052010-06-03 06:38:38 +0200687int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
688 void *mmcontext)
689{
Harald Weltef78a3b22010-06-30 17:21:19 +0200690 struct gprs_sndcp_entity *sne;
Harald Weltebb1c8052010-06-03 06:38:38 +0200691 struct sndcp_common_hdr *sch;
Harald Weltece22f922010-06-03 21:21:21 +0200692 struct sndcp_comp_hdr *scomph;
Harald Weltebb1c8052010-06-03 06:38:38 +0200693 struct sndcp_udata_hdr *suh;
Harald Weltece22f922010-06-03 21:21:21 +0200694 struct sndcp_frag_state fs;
Philippf1f34362016-08-26 17:00:21 +0200695 uint8_t pcomp = 0;
696 uint8_t dcomp = 0;
697 int rc;
Harald Weltebb1c8052010-06-03 06:38:38 +0200698
699 /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
700
Philippf1f34362016-08-26 17:00:21 +0200701 /* Compress packet */
702#if DEBUG_IP_PACKETS == 1
703 DEBUGP(DSNDCP, " \n");
704 DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
705 DEBUGP(DSNDCP, "===================================================\n");
706 debug_ip_packet(msg->data, msg->len, 0, "sndcp_initdata_req()");
707#endif
708 if (any_pcomp_or_dcomp_active(sgsn)) {
709
710 /* Apply header compression */
711 rc = gprs_sndcp_pcomp_compress(msg->data, msg->len, &pcomp,
712 lle->llme->comp.proto, nsapi);
713 if (rc < 0) {
714 LOGP(DSNDCP, LOGL_ERROR,
715 "TCP/IP Header compression failed!\n");
716 return -EIO;
717 }
718
719 /* Fixup pointer locations and sizes in message buffer to match
720 * the new, compressed buffer size */
721 msgb_get(msg, msg->len);
722 msgb_put(msg, rc);
Philipp73f83d52016-09-02 13:38:01 +0200723
724 /* Apply data compression */
725 rc = gprs_sndcp_dcomp_compress(msg->data, msg->len, &dcomp,
726 lle->llme->comp.data, nsapi);
727 if (rc < 0) {
728 LOGP(DSNDCP, LOGL_ERROR, "Data compression failed!\n");
729 return -EIO;
730 }
731
732 /* Fixup pointer locations and sizes in message buffer to match
733 * the new, compressed buffer size */
734 msgb_get(msg, msg->len);
735 msgb_put(msg, rc);
Philippf1f34362016-08-26 17:00:21 +0200736 }
737#if DEBUG_IP_PACKETS == 1
738 DEBUGP(DSNDCP, "===================================================\n");
739 DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
740 DEBUGP(DSNDCP, " \n");
741#endif
742
Harald Weltef78a3b22010-06-30 17:21:19 +0200743 sne = gprs_sndcp_entity_by_lle(lle, nsapi);
Harald Weltebb1c8052010-06-03 06:38:38 +0200744 if (!sne) {
Max559636a2022-10-08 20:24:22 +0300745 LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity (lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n",
746 lle, lle->llme->tlli, lle->sapi, nsapi);
Holger Hans Peter Freytherf9ffd1f2014-10-10 17:35:54 +0200747 msgb_free(msg);
Harald Weltebb1c8052010-06-03 06:38:38 +0200748 return -EIO;
749 }
750
Harald Weltece22f922010-06-03 21:21:21 +0200751 /* Check if we need to fragment this N-PDU into multiple SN-PDUs */
Max559636a2022-10-08 20:24:22 +0300752 if (msg->len > lle->params.n201_u -
Harald Weltece22f922010-06-03 21:21:21 +0200753 (sizeof(*sch) + sizeof(*suh) + sizeof(*scomph))) {
754 /* initialize the fragmenter state */
755 fs.msg = msg;
756 fs.frag_nr = 0;
757 fs.next_byte = msg->data;
758 fs.sne = sne;
759 fs.mmcontext = mmcontext;
760
761 /* call function to generate and send fragments until all
762 * of the N-PDU has been sent */
763 while (1) {
Philippf1f34362016-08-26 17:00:21 +0200764 int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp);
Harald Weltece22f922010-06-03 21:21:21 +0200765 if (rc == 0)
766 return 0;
767 if (rc < 0)
768 return rc;
769 }
770 /* not reached */
771 return 0;
772 }
773
774 /* this is the non-fragmenting case where we only build 1 SN-PDU */
775
Harald Weltebb1c8052010-06-03 06:38:38 +0200776 /* prepend the user-data header */
777 suh = (struct sndcp_udata_hdr *) msgb_push(msg, sizeof(*suh));
Harald Weltece22f922010-06-03 21:21:21 +0200778 suh->npdu_low = sne->tx_npdu_nr & 0xff;
779 suh->npdu_high = (sne->tx_npdu_nr >> 8) & 0xf;
780 suh->seg_nr = 0;
781 sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff;
782
783 scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph));
Philippf1f34362016-08-26 17:00:21 +0200784 scomph->pcomp = pcomp;
785 scomph->dcomp = dcomp;
Harald Weltebb1c8052010-06-03 06:38:38 +0200786
787 /* prepend common SNDCP header */
788 sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch));
789 sch->first = 1;
790 sch->type = 1;
791 sch->nsapi = nsapi;
792
Max82040102016-07-06 11:59:18 +0200793 return gprs_llc_tx_ui(msg, lle->sapi, 0, mmcontext, true);
Harald Weltebb1c8052010-06-03 06:38:38 +0200794}
795
Harald Welteebabdea2010-06-01 18:28:10 +0200796/* Section 5.1.2.17 LL-UNITDATA.ind */
Harald Welte36f12172010-07-02 16:44:24 +0200797int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
798 uint8_t *hdr, uint16_t len)
Harald Welteebabdea2010-06-01 18:28:10 +0200799{
Harald Weltef78a3b22010-06-30 17:21:19 +0200800 struct gprs_sndcp_entity *sne;
Harald Welteebabdea2010-06-01 18:28:10 +0200801 struct sndcp_common_hdr *sch = (struct sndcp_common_hdr *)hdr;
Harald Weltece22f922010-06-03 21:21:21 +0200802 struct sndcp_comp_hdr *scomph = NULL;
Harald Welteebabdea2010-06-01 18:28:10 +0200803 struct sndcp_udata_hdr *suh;
Alexander Couzensa8f78252019-09-16 02:44:58 +0200804 struct sgsn_mm_ctx *mmctx;
Harald Welte16836a32010-06-02 10:25:40 +0200805 uint8_t *npdu;
Holger Hans Peter Freythercfee9522014-04-04 12:43:08 +0200806 uint16_t npdu_num __attribute__((unused));
Harald Welteebabdea2010-06-01 18:28:10 +0200807 int npdu_len;
Philippf1f34362016-08-26 17:00:21 +0200808 int rc;
809 uint8_t *expnd = NULL;
Harald Welteebabdea2010-06-01 18:28:10 +0200810
Harald Weltece22f922010-06-03 21:21:21 +0200811 sch = (struct sndcp_common_hdr *) hdr;
812 if (sch->first) {
813 scomph = (struct sndcp_comp_hdr *) (hdr + 1);
814 suh = (struct sndcp_udata_hdr *) (hdr + 1 + sizeof(struct sndcp_common_hdr));
815 } else
816 suh = (struct sndcp_udata_hdr *) (hdr + sizeof(struct sndcp_common_hdr));
817
Harald Welteebabdea2010-06-01 18:28:10 +0200818 if (sch->type == 0) {
Harald Welte69996cb2010-06-02 10:26:19 +0200819 LOGP(DSNDCP, LOGL_ERROR, "SN-DATA PDU at unitdata_ind() function\n");
Harald Welte96f71f22010-05-03 19:28:05 +0200820 return -EINVAL;
821 }
822
Harald Welte16836a32010-06-02 10:25:40 +0200823 if (len < sizeof(*sch) + sizeof(*suh)) {
Harald Welte69996cb2010-06-02 10:26:19 +0200824 LOGP(DSNDCP, LOGL_ERROR, "SN-UNITDATA PDU too short (%u)\n", len);
Harald Welteebabdea2010-06-01 18:28:10 +0200825 return -EIO;
826 }
827
Harald Weltef78a3b22010-06-30 17:21:19 +0200828 sne = gprs_sndcp_entity_by_lle(lle, sch->nsapi);
Harald Welteebabdea2010-06-01 18:28:10 +0200829 if (!sne) {
Harald Welte69996cb2010-06-02 10:26:19 +0200830 LOGP(DSNDCP, LOGL_ERROR, "Message for non-existing SNDCP Entity "
Harald Welte61444522010-06-02 12:40:48 +0200831 "(lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n", lle,
832 lle->llme->tlli, lle->sapi, sch->nsapi);
Harald Welteebabdea2010-06-01 18:28:10 +0200833 return -EIO;
834 }
Harald Welte8911cef2010-07-01 19:56:19 +0200835 /* FIXME: move this RA_ID up to the LLME or even higher */
836 bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg));
Harald Welteebabdea2010-06-01 18:28:10 +0200837
Alexander Couzensa8f78252019-09-16 02:44:58 +0200838 mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &sne->ra_id);
839 if (!mmctx) {
840 LOGP(DSNDCP, LOGL_ERROR, "Message for non-existing MM ctx "
841 "(lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n",
842 lle, lle->llme->tlli, lle->sapi, sch->nsapi);
843 return -EIO;
844 }
Pau Espin Pedrol11ccc432021-02-16 13:59:05 +0100845 gprs_gb_recv_pdu(mmctx, msg);
Alexander Couzensa8f78252019-09-16 02:44:58 +0200846
Harald Welte7e5bb622016-09-28 08:20:58 +0800847 if (scomph) {
Philippf1f34362016-08-26 17:00:21 +0200848 sne->defrag.pcomp = scomph->pcomp;
849 sne->defrag.dcomp = scomph->dcomp;
850 sne->defrag.proto = lle->llme->comp.proto;
851 sne->defrag.data = lle->llme->comp.data;
852 }
853
Harald Welteab4094c2010-07-02 16:01:47 +0200854 /* any non-first segment is by definition something to defragment
855 * as is any segment that tells us there are more segments */
856 if (!sch->first || sch->more)
Harald Welte60da7d42010-07-02 15:45:12 +0200857 return defrag_input(sne, msg, hdr, len);
Harald Welteebabdea2010-06-01 18:28:10 +0200858
Harald Welte16836a32010-06-02 10:25:40 +0200859 npdu_num = (suh->npdu_high << 8) | suh->npdu_low;
Harald Welteebabdea2010-06-01 18:28:10 +0200860 npdu = (uint8_t *)suh + sizeof(*suh);
Alexander Couzens410bc9b2018-09-18 20:01:28 +0200861 npdu_len = (msg->data + msg->len) - npdu;
Philippf1f34362016-08-26 17:00:21 +0200862
Harald Welte61444522010-06-02 12:40:48 +0200863 if (npdu_len <= 0) {
Harald Welte69996cb2010-06-02 10:26:19 +0200864 LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len);
Harald Welteebabdea2010-06-01 18:28:10 +0200865 return -EIO;
866 }
867 /* actually send the N-PDU to the SGSN core code, which then
868 * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */
Philippf1f34362016-08-26 17:00:21 +0200869
870 /* Decompress packet */
Philippf1f34362016-08-26 17:00:21 +0200871 if (any_pcomp_or_dcomp_active(sgsn)) {
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100872 expnd = decompress_segment(sne, msg, npdu, npdu_len, (unsigned int *)&npdu_len);
873 if (!expnd) {
874 rc = -EIO;
875 goto ret_free;
Philipp73f83d52016-09-02 13:38:01 +0200876 }
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100877 } else {
Philippf1f34362016-08-26 17:00:21 +0200878 expnd = npdu;
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100879 }
Philippf1f34362016-08-26 17:00:21 +0200880
881 /* Hand off packet to gtp */
882 rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli,
883 sne->nsapi, msg, npdu_len, expnd);
884
Pau Espin Pedrol57b63872022-12-06 11:50:26 +0100885ret_free:
Philippf1f34362016-08-26 17:00:21 +0200886 if (any_pcomp_or_dcomp_active(sgsn))
887 talloc_free(expnd);
888
889 return rc;
Harald Welte96f71f22010-05-03 19:28:05 +0200890}
891
Holger Hans Peter Freythercfee9522014-04-04 12:43:08 +0200892#if 0
Harald Welte2720e732010-05-17 00:44:57 +0200893/* Section 5.1.2.1 LL-RESET.ind */
Harald Weltef78a3b22010-06-30 17:21:19 +0200894static int sndcp_ll_reset_ind(struct gprs_sndcp_entity *se)
Harald Welte2720e732010-05-17 00:44:57 +0200895{
896 /* treat all outstanding SNDCP-LLC request type primitives as not sent */
897 /* reset all SNDCP XID parameters to default values */
Holger Hans Peter Freyther6142dc42011-10-14 23:37:27 +0200898 LOGP(DSNDCP, LOGL_NOTICE, "not implemented.\n");
899 return 0;
Harald Welte2720e732010-05-17 00:44:57 +0200900}
901
Harald Welte2720e732010-05-17 00:44:57 +0200902static int sndcp_ll_status_ind()
903{
904 /* inform the SM sub-layer by means of SNSM-STATUS.req */
Holger Hans Peter Freyther6142dc42011-10-14 23:37:27 +0200905 LOGP(DSNDCP, LOGL_NOTICE, "not implemented.\n");
906 return 0;
Harald Welte2720e732010-05-17 00:44:57 +0200907}
908
909static struct sndcp_state_list {{
910 uint32_t states;
911 unsigned int type;
Harald Weltef78a3b22010-06-30 17:21:19 +0200912 int (*rout)(struct gprs_sndcp_entity *se, struct msgb *msg);
Harald Welte2720e732010-05-17 00:44:57 +0200913} sndcp_state_list[] = {
914 { ALL_STATES,
915 LL_RESET_IND, sndcp_ll_reset_ind },
916 { ALL_STATES,
917 LL_ESTABLISH_IND, sndcp_ll_est_ind },
918 { SBIT(SNDCP_S_EST_RQD),
919 LL_ESTABLISH_RESP, sndcp_ll_est_ind },
920 { SBIT(SNDCP_S_EST_RQD),
921 LL_ESTABLISH_CONF, sndcp_ll_est_conf },
922 { SBIT(SNDCP_S_
923};
924
925static int sndcp_rx_llc_prim()
926{
927 case LL_ESTABLISH_REQ:
928 case LL_RELEASE_REQ:
929 case LL_XID_REQ:
930 case LL_DATA_REQ:
931 LL_UNITDATA_REQ, /* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
932
933 switch (prim) {
934 case LL_RESET_IND:
935 case LL_ESTABLISH_IND:
936 case LL_ESTABLISH_RESP:
937 case LL_ESTABLISH_CONF:
938 case LL_RELEASE_IND:
939 case LL_RELEASE_CONF:
940 case LL_XID_IND:
941 case LL_XID_RESP:
942 case LL_XID_CONF:
943 case LL_DATA_IND:
944 case LL_DATA_CONF:
945 case LL_UNITDATA_IND:
946 case LL_STATUS_IND:
Neels Hofmeyrcc7db182016-12-18 23:52:38 +0100947 }
Harald Welte2720e732010-05-17 00:44:57 +0200948}
Harald Welteebabdea2010-06-01 18:28:10 +0200949#endif
Philippf1f34362016-08-26 17:00:21 +0200950
951/* Generate SNDCP-XID message */
952static int gprs_llc_gen_sndcp_xid(uint8_t *bytes, int bytes_len, uint8_t nsapi)
953{
954 int entity = 0;
955 LLIST_HEAD(comp_fields);
956 struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params;
957 struct gprs_sndcp_comp_field rfc1144_comp_field;
Philipp73f83d52016-09-02 13:38:01 +0200958 struct gprs_sndcp_dcomp_v42bis_params v42bis_params;
959 struct gprs_sndcp_comp_field v42bis_comp_field;
Philippf1f34362016-08-26 17:00:21 +0200960
961 memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field));
Philipp73f83d52016-09-02 13:38:01 +0200962 memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field));
Philippf1f34362016-08-26 17:00:21 +0200963
964 /* Setup rfc1144 */
965 if (sgsn->cfg.pcomp_rfc1144.active) {
966 rfc1144_params.nsapi[0] = nsapi;
967 rfc1144_params.nsapi_len = 1;
968 rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01;
969 rfc1144_comp_field.p = 1;
970 rfc1144_comp_field.entity = entity;
Stefan Sperlingc5721542018-11-07 16:33:39 +0100971 rfc1144_comp_field.algo.pcomp = RFC_1144;
Philippf1f34362016-08-26 17:00:21 +0200972 rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1;
973 rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2;
974 rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM;
975 rfc1144_comp_field.rfc1144_params = &rfc1144_params;
976 entity++;
977 llist_add(&rfc1144_comp_field.list, &comp_fields);
978 }
979
Philipp73f83d52016-09-02 13:38:01 +0200980 /* Setup V.42bis */
981 if (sgsn->cfg.dcomp_v42bis.active) {
982 v42bis_params.nsapi[0] = nsapi;
983 v42bis_params.nsapi_len = 1;
984 v42bis_params.p0 = sgsn->cfg.dcomp_v42bis.p0;
985 v42bis_params.p1 = sgsn->cfg.dcomp_v42bis.p1;
986 v42bis_params.p2 = sgsn->cfg.dcomp_v42bis.p2;
987 v42bis_comp_field.p = 1;
988 v42bis_comp_field.entity = entity;
Stefan Sperlingc5721542018-11-07 16:33:39 +0100989 v42bis_comp_field.algo.dcomp = V42BIS;
Philipp73f83d52016-09-02 13:38:01 +0200990 v42bis_comp_field.comp[V42BIS_DCOMP1] = 1;
991 v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM;
992 v42bis_comp_field.v42bis_params = &v42bis_params;
993 entity++;
994 llist_add(&v42bis_comp_field.list, &comp_fields);
995 }
996
Philippdb142dc2016-12-22 14:15:20 +0100997 /* Do not attempt to compile anything if there is no data in the list */
998 if (llist_empty(&comp_fields))
999 return 0;
1000
Philippf1f34362016-08-26 17:00:21 +02001001 /* Compile bytestream */
Philippdb142dc2016-12-22 14:15:20 +01001002 return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields,
1003 DEFAULT_SNDCP_VERSION);
Philippf1f34362016-08-26 17:00:21 +02001004}
1005
1006/* Set of SNDCP-XID bnegotiation (See also: TS 144 065,
1007 * Section 6.8 XID parameter negotiation) */
1008int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi)
1009{
1010 /* Note: The specification requires the SNDCP-User to set of an
1011 * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter
1012 * negotiation, Figure 11: SNDCP XID negotiation procedure. In
1013 * our case the SNDCP-User is sgsn_libgtp.c, which calls
1014 * sndcp_sn_xid_req directly. */
1015
1016 uint8_t l3params[1024];
1017 int xid_len;
1018 struct gprs_llc_xid_field xid_field_request;
1019
1020 /* Wipe off all compression entities and their states to
1021 * get rid of possible leftovers from a previous session */
1022 gprs_sndcp_comp_free(lle->llme->comp.proto);
1023 gprs_sndcp_comp_free(lle->llme->comp.data);
1024 lle->llme->comp.proto = gprs_sndcp_comp_alloc(lle->llme);
1025 lle->llme->comp.data = gprs_sndcp_comp_alloc(lle->llme);
Harald Welteaf779d22019-04-12 16:56:04 +02001026 talloc_free(lle->xid);
1027 lle->xid = NULL;
Philippf1f34362016-08-26 17:00:21 +02001028
1029 /* Generate compression parameter bytestream */
1030 xid_len = gprs_llc_gen_sndcp_xid(l3params, sizeof(l3params), nsapi);
1031
1032 /* Send XID with the SNDCP-XID bytetsream included */
1033 if (xid_len > 0) {
1034 xid_field_request.type = GPRS_LLC_XID_T_L3_PAR;
1035 xid_field_request.data = l3params;
1036 xid_field_request.data_len = xid_len;
1037 return gprs_ll_xid_req(lle, &xid_field_request);
1038 }
1039
1040 /* When bytestream can not be generated, proceed without SNDCP-XID */
1041 return gprs_ll_xid_req(lle, NULL);
1042
1043}
1044
1045/* Handle header compression entites */
1046static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field,
Maxcaff83e2022-10-09 13:32:09 +03001047 const struct gprs_llc_lle *lle)
Philippf1f34362016-08-26 17:00:21 +02001048{
1049 /* Note: This functions also transforms the comp_field into its
1050 * echo form (strips comp values, resets propose bit etc...)
1051 * the processed comp_fields can then be sent back as XID-
1052 * Response without further modification. */
1053
1054 /* Delete propose bit */
1055 comp_field->p = 0;
1056
1057 /* Process proposed parameters */
Stefan Sperlingc5721542018-11-07 16:33:39 +01001058 switch (comp_field->algo.pcomp) {
Philippf1f34362016-08-26 17:00:21 +02001059 case RFC_1144:
1060 if (sgsn->cfg.pcomp_rfc1144.passive
1061 && comp_field->rfc1144_params->nsapi_len > 0) {
1062 DEBUGP(DSNDCP,
1063 "Accepting RFC1144 header compression...\n");
1064 gprs_sndcp_comp_add(lle->llme, lle->llme->comp.proto,
1065 comp_field);
1066 } else {
1067 DEBUGP(DSNDCP,
1068 "Rejecting RFC1144 header compression...\n");
1069 gprs_sndcp_comp_delete(lle->llme->comp.proto,
1070 comp_field->entity);
1071 comp_field->rfc1144_params->nsapi_len = 0;
1072 }
1073 break;
1074 case RFC_2507:
1075 /* RFC 2507 is not yet supported,
1076 * so we set applicable nsapis to zero */
1077 DEBUGP(DSNDCP, "Rejecting RFC2507 header compression...\n");
1078 comp_field->rfc2507_params->nsapi_len = 0;
1079 gprs_sndcp_comp_delete(lle->llme->comp.proto,
1080 comp_field->entity);
1081 break;
1082 case ROHC:
1083 /* ROHC is not yet supported,
1084 * so we set applicable nsapis to zero */
1085 DEBUGP(DSNDCP, "Rejecting ROHC header compression...\n");
1086 comp_field->rohc_params->nsapi_len = 0;
1087 gprs_sndcp_comp_delete(lle->llme->comp.proto,
1088 comp_field->entity);
1089 break;
1090 }
1091
1092 return 0;
1093}
1094
1095/* Hanle data compression entites */
1096static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field,
Maxcaff83e2022-10-09 13:32:09 +03001097 const struct gprs_llc_lle *lle)
Philippf1f34362016-08-26 17:00:21 +02001098{
1099 /* See note in handle_pcomp_entities() */
1100
1101 /* Delete propose bit */
1102 comp_field->p = 0;
1103
1104 /* Process proposed parameters */
Stefan Sperlingc5721542018-11-07 16:33:39 +01001105 switch (comp_field->algo.dcomp) {
Philippf1f34362016-08-26 17:00:21 +02001106 case V42BIS:
Philipp73f83d52016-09-02 13:38:01 +02001107 if (sgsn->cfg.dcomp_v42bis.passive &&
1108 comp_field->v42bis_params->nsapi_len > 0) {
1109 DEBUGP(DSNDCP,
1110 "Accepting V.42bis data compression...\n");
1111 gprs_sndcp_comp_add(lle->llme, lle->llme->comp.data,
1112 comp_field);
1113 } else {
1114 LOGP(DSNDCP, LOGL_DEBUG,
1115 "Rejecting V.42bis data compression...\n");
1116 gprs_sndcp_comp_delete(lle->llme->comp.data,
1117 comp_field->entity);
1118 comp_field->v42bis_params->nsapi_len = 0;
1119 }
Philippf1f34362016-08-26 17:00:21 +02001120 break;
1121 case V44:
1122 /* V44 is not yet supported,
1123 * so we set applicable nsapis to zero */
1124 DEBUGP(DSNDCP, "Rejecting V.44 data compression...\n");
1125 comp_field->v44_params->nsapi_len = 0;
1126 gprs_sndcp_comp_delete(lle->llme->comp.data,
1127 comp_field->entity);
1128 break;
1129 }
1130
1131 return 0;
1132
1133}
1134
1135/* Process SNDCP-XID indication
1136 * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
1137int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication,
1138 struct gprs_llc_xid_field *xid_field_response,
Maxcaff83e2022-10-09 13:32:09 +03001139 const struct gprs_llc_lle *lle)
Philippf1f34362016-08-26 17:00:21 +02001140{
1141 /* Note: This function computes the SNDCP-XID response that is sent
1142 * back to the ms when a ms originated XID is received. The
1143 * Input XID fields are directly processed and the result is directly
1144 * handed back. */
1145
1146 int rc;
1147 int compclass;
Philippdb142dc2016-12-22 14:15:20 +01001148 int version;
Philippf1f34362016-08-26 17:00:21 +02001149
1150 struct llist_head *comp_fields;
1151 struct gprs_sndcp_comp_field *comp_field;
1152
1153 OSMO_ASSERT(xid_field_indication);
1154 OSMO_ASSERT(xid_field_response);
1155 OSMO_ASSERT(lle);
1156
Keithbfd67d22019-04-29 18:23:10 +01001157 /* Some phones send zero byte length SNDCP frames
1158 * and do require a confirmation response. */
1159 if (xid_field_indication->data_len == 0) {
1160 xid_field_response->type = GPRS_LLC_XID_T_L3_PAR;
1161 xid_field_response->data_len = 0;
1162 return 0;
1163 }
1164
Philippf1f34362016-08-26 17:00:21 +02001165 /* Parse SNDCP-CID XID-Field */
Philippdb142dc2016-12-22 14:15:20 +01001166 comp_fields = gprs_sndcp_parse_xid(&version, lle->llme,
Philippf1f34362016-08-26 17:00:21 +02001167 xid_field_indication->data,
1168 xid_field_indication->data_len,
1169 NULL);
1170 if (!comp_fields)
1171 return -EINVAL;
1172
Philippf1f34362016-08-26 17:00:21 +02001173 /* Handle compression entites */
1174 DEBUGP(DSNDCP, "SNDCP-XID-IND (ms):\n");
1175 gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG);
1176
1177 llist_for_each_entry(comp_field, comp_fields, list) {
1178 compclass = gprs_sndcp_get_compression_class(comp_field);
1179 if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION)
1180 rc = handle_pcomp_entities(comp_field, lle);
1181 else if (compclass == SNDCP_XID_DATA_COMPRESSION)
1182 rc = handle_dcomp_entities(comp_field, lle);
1183 else {
1184 gprs_sndcp_comp_delete(lle->llme->comp.proto,
1185 comp_field->entity);
1186 gprs_sndcp_comp_delete(lle->llme->comp.data,
1187 comp_field->entity);
1188 rc = 0;
1189 }
1190
1191 if (rc < 0) {
1192 talloc_free(comp_fields);
1193 return -EINVAL;
1194 }
1195 }
1196
1197 DEBUGP(DSNDCP, "SNDCP-XID-RES (sgsn):\n");
1198 gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG);
1199
1200 /* Reserve some memory to store the modified SNDCP-XID bytes */
1201 xid_field_response->data =
1202 talloc_zero_size(lle->llme, xid_field_indication->data_len);
1203
1204 /* Set Type flag for response */
1205 xid_field_response->type = GPRS_LLC_XID_T_L3_PAR;
1206
1207 /* Compile modified SNDCP-XID bytes */
1208 rc = gprs_sndcp_compile_xid(xid_field_response->data,
1209 xid_field_indication->data_len,
Philippdb142dc2016-12-22 14:15:20 +01001210 comp_fields, 0);
Philippf1f34362016-08-26 17:00:21 +02001211
1212 if (rc > 0)
1213 xid_field_response->data_len = rc;
1214 else {
1215 talloc_free(xid_field_response->data);
1216 xid_field_response->data = NULL;
1217 xid_field_response->data_len = 0;
1218 return -EINVAL;
1219 }
1220
1221 talloc_free(comp_fields);
1222
1223 return 0;
1224}
1225
1226/* Process SNDCP-XID indication
1227 * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
1228int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf,
1229 struct gprs_llc_xid_field *xid_field_request,
1230 struct gprs_llc_lle *lle)
1231{
1232 /* Note: This function handles an incomming SNDCP-XID confirmiation.
1233 * Since the confirmation fields may lack important parameters we
1234 * will reconstruct these missing fields using the original request
1235 * we have sent. After that we will create (or delete) the
1236 * compression entites */
1237
1238 struct llist_head *comp_fields_req;
1239 struct llist_head *comp_fields_conf;
1240 struct gprs_sndcp_comp_field *comp_field;
1241 int rc;
1242 int compclass;
1243
1244 /* We need both, the confirmation that is sent back by the ms,
1245 * and the original request we have sent. If one of this is missing
1246 * we can not process the confirmation, the caller must check if
1247 * request and confirmation fields are available. */
1248 OSMO_ASSERT(xid_field_conf);
1249 OSMO_ASSERT(xid_field_request);
1250
1251 /* Parse SNDCP-CID XID-Field */
Philippdb142dc2016-12-22 14:15:20 +01001252 comp_fields_req = gprs_sndcp_parse_xid(NULL, lle->llme,
Philippf1f34362016-08-26 17:00:21 +02001253 xid_field_request->data,
1254 xid_field_request->data_len,
1255 NULL);
1256 if (!comp_fields_req)
1257 return -EINVAL;
1258
1259 DEBUGP(DSNDCP, "SNDCP-XID-REQ (sgsn):\n");
1260 gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG);
1261
1262 /* Parse SNDCP-CID XID-Field */
Philippdb142dc2016-12-22 14:15:20 +01001263 comp_fields_conf = gprs_sndcp_parse_xid(NULL, lle->llme,
Philippf1f34362016-08-26 17:00:21 +02001264 xid_field_conf->data,
1265 xid_field_conf->data_len,
1266 comp_fields_req);
1267 if (!comp_fields_conf)
1268 return -EINVAL;
1269
1270 DEBUGP(DSNDCP, "SNDCP-XID-CONF (ms):\n");
1271 gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG);
1272
1273 /* Handle compression entites */
1274 llist_for_each_entry(comp_field, comp_fields_conf, list) {
1275 compclass = gprs_sndcp_get_compression_class(comp_field);
1276 if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION)
1277 rc = handle_pcomp_entities(comp_field, lle);
1278 else if (compclass == SNDCP_XID_DATA_COMPRESSION)
1279 rc = handle_dcomp_entities(comp_field, lle);
1280 else {
1281 gprs_sndcp_comp_delete(lle->llme->comp.proto,
1282 comp_field->entity);
1283 gprs_sndcp_comp_delete(lle->llme->comp.data,
1284 comp_field->entity);
1285 rc = 0;
1286 }
1287
1288 if (rc < 0) {
1289 talloc_free(comp_fields_req);
1290 talloc_free(comp_fields_conf);
1291 return -EINVAL;
1292 }
1293 }
1294
1295 talloc_free(comp_fields_req);
1296 talloc_free(comp_fields_conf);
1297
1298 return 0;
1299}