blob: adfab657830aa3d20014b03a8c9fd8330c6074f6 [file] [log] [blame]
Pau Espin Pedrol5c598c72022-03-31 20:22:05 +02001/* 3GPP TS 44.064
Holger Hans Peter Freytherbe570812013-11-07 08:01:49 +01002 * Copyright (C) 2013 by Holger Hans Peter Freyther
Pau Espin Pedrol4f8384b2022-03-31 19:36:12 +02003 * Copyright (C) 2022 by by Sysmocom s.f.m.c. GmbH
Holger Hans Peter Freytherbe570812013-11-07 08:01:49 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Holger Hans Peter Freytherbe570812013-11-07 08:01:49 +010014 */
15
16#pragma once
17
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010018#ifdef __cplusplus
Jacob Erlbeck1eae96c2015-06-15 11:19:13 +020019extern "C" {
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010020#endif
Jacob Erlbeck1eae96c2015-06-15 11:19:13 +020021
Holger Hans Peter Freytherbe570812013-11-07 08:01:49 +010022#include <stdint.h>
Holger Hans Peter Freytheracb54272013-11-07 08:15:58 +010023#include <string.h>
Pau Espin Pedrol1de68732020-03-11 14:04:52 +010024#include <time.h>
Holger Hans Peter Freytherbe570812013-11-07 08:01:49 +010025
Pau Espin Pedrol5c598c72022-03-31 20:22:05 +020026#include <osmocom/core/endian.h>
Pau Espin Pedrol4f8384b2022-03-31 19:36:12 +020027#include <osmocom/core/linuxlist.h>
28#include <osmocom/core/msgb.h>
Pau Espin Pedrol5c598c72022-03-31 20:22:05 +020029#include <osmocom/core/endian.h>
Pau Espin Pedrol4f8384b2022-03-31 19:36:12 +020030
Holger Hans Peter Freytherbe570812013-11-07 08:01:49 +010031#define LLC_MAX_LEN 1543
32
Pau Espin Pedrol2182e622021-01-14 16:48:38 +010033struct gprs_rlcmac_bts;
Jacob Erlbeck1d0a52a2015-06-02 11:28:07 +020034
Pau Espin Pedrol5c598c72022-03-31 20:22:05 +020035struct gprs_llc_hdr {
36#if OSMO_IS_LITTLE_ENDIAN
37 union { /* 5.2, 6.2.0 */
38 uint8_t address;
39 uint8_t sapi:4, unused:2, c_r:1, pd:1;
40#elif OSMO_IS_BIG_ENDIAN
41/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
42 union {
43 uint8_t address;
44 uint8_t pd:1, c_r:1, unused:2, sapi:4;
45#endif
46 };
47 uint8_t control[0];
48} __attribute__ ((packed));
49
Holger Hans Peter Freytherbe570812013-11-07 08:01:49 +010050/**
51 * I represent the LLC data to a MS
52 */
53struct gprs_llc {
Holger Hans Peter Freytherbe570812013-11-07 08:01:49 +010054 uint8_t frame[LLC_MAX_LEN]; /* current DL or UL frame */
Pau Espin Pedrol14633832022-03-31 19:08:07 +020055 uint16_t index; /* current write/read position of frame */
56 uint16_t length; /* len of current DL LLC_frame, 0 == no frame */
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +020057};
Pau Espin Pedrol4f8384b2022-03-31 19:36:12 +020058bool llc_is_user_data_frame(const uint8_t *data, size_t len);
59
60void llc_init(struct gprs_llc *llc);
61void llc_reset(struct gprs_llc *llc);
62void llc_reset_frame_space(struct gprs_llc *llc);
63
64void llc_put_frame(struct gprs_llc *llc, const uint8_t *data, size_t len);
65void llc_put_dummy_frame(struct gprs_llc *llc, size_t req_len);
66void llc_append_frame(struct gprs_llc *llc, const uint8_t *data, size_t len);
Holger Hans Peter Freyther550bb882013-12-04 17:10:54 +010067
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010068static inline uint16_t llc_chunk_size(const struct gprs_llc *llc)
Holger Hans Peter Freytheracb54272013-11-07 08:15:58 +010069{
Pau Espin Pedrol14633832022-03-31 19:08:07 +020070 return llc->length - llc->index;
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010071}
72
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010073static inline uint16_t llc_remaining_space(const struct gprs_llc *llc)
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010074{
Pau Espin Pedrol14633832022-03-31 19:08:07 +020075 return LLC_MAX_LEN - llc->length;
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010076}
77
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010078static inline uint16_t llc_frame_length(const struct gprs_llc *llc)
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010079{
Pau Espin Pedrol14633832022-03-31 19:08:07 +020080 return llc->length;
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010081}
82
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010083static inline void llc_consume(struct gprs_llc *llc, size_t len)
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010084{
Pau Espin Pedrol14633832022-03-31 19:08:07 +020085 llc->index += len;
Holger Hans Peter Freytheracb54272013-11-07 08:15:58 +010086}
87
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010088static inline void llc_consume_data(struct gprs_llc *llc, uint8_t *data, size_t len)
Holger Hans Peter Freytheracb54272013-11-07 08:15:58 +010089{
90 /* copy and increment index */
Pau Espin Pedrol14633832022-03-31 19:08:07 +020091 memcpy(data, llc->frame + llc->index, len);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010092 llc_consume(llc, len);
Holger Hans Peter Freytheracb54272013-11-07 08:15:58 +010093}
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010094
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010095static inline bool llc_fits_in_current_frame(const struct gprs_llc *llc, uint8_t chunk_size)
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010096{
Pau Espin Pedrol14633832022-03-31 19:08:07 +020097 return llc->length + chunk_size <= LLC_MAX_LEN;
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010098}
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +020099
Pau Espin Pedrolee1cb752022-03-31 19:47:33 +0200100struct MetaInfo {
101 struct timespec recv_time;
102 struct timespec expire_time;
103};
104/**
105 * I store the LLC frames that come from the SGSN.
106 */
Pau Espin Pedrol5c598c72022-03-31 20:22:05 +0200107enum gprs_llc_queue_prio { /* lowest value has highest prio */
108 LLC_QUEUE_PRIO_GMM = 0, /* SAPI 1 */
109 LLC_QUEUE_PRIO_TOM_SMS, /* SAPI 2,7,8 */
110 LLC_QUEUE_PRIO_OTHER, /* Other SAPIs */
111 _LLC_QUEUE_PRIO_SIZE /* used to calculate size of enum */
112};
Pau Espin Pedrolee1cb752022-03-31 19:47:33 +0200113struct gprs_llc_queue {
114 uint32_t avg_queue_delay; /* Average delay of data going through the queue */
115 size_t queue_size;
116 size_t queue_octets;
Pau Espin Pedrol5c598c72022-03-31 20:22:05 +0200117 struct llist_head queue[_LLC_QUEUE_PRIO_SIZE]; /* queued LLC DL data. See enum gprs_llc_queue_prio. */
Pau Espin Pedrolee1cb752022-03-31 19:47:33 +0200118};
119
120void llc_queue_calc_pdu_lifetime(struct gprs_rlcmac_bts *bts, const uint16_t pdu_delay_csec,
121 struct timespec *tv);
122bool llc_queue_is_frame_expired(const struct timespec *tv_now, const struct timespec *tv);
123
124void llc_queue_init(struct gprs_llc_queue *q);
125void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts);
126void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o);
127void llc_queue_enqueue(struct gprs_llc_queue *q, struct msgb *llc_msg, const struct timespec *expire_time);
128struct msgb *llc_queue_dequeue(struct gprs_llc_queue *q, const struct MetaInfo **info);
129
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100130static inline size_t llc_queue_size(const struct gprs_llc_queue *q)
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +0200131{
Pau Espin Pedrol14633832022-03-31 19:08:07 +0200132 return q->queue_size;
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +0200133}
Jacob Erlbeck07eb6552015-06-15 11:05:44 +0200134
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100135static inline size_t llc_queue_octets(const struct gprs_llc_queue *q)
Jacob Erlbeck07eb6552015-06-15 11:05:44 +0200136{
Pau Espin Pedrol14633832022-03-31 19:08:07 +0200137 return q->queue_octets;
Jacob Erlbeck07eb6552015-06-15 11:05:44 +0200138}
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100139
140#ifdef __cplusplus
141}
142#endif