blob: e2d01c29fcb3b297c9506c6ddd905f6bc97a6aab [file] [log] [blame]
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +01001/* Copied from tbf.cpp
2 *
3 * Copyright (C) 2012 Ivan Klyuchnikov
4 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
5 * Copyright (C) 2013 by Holger Hans Peter Freyther
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +010022#include <bts.h>
23
Holger Hans Peter Freyther857281f2013-11-13 14:56:55 +010024#include <stdio.h>
25
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +010026extern "C" {
27#include <osmocom/core/msgb.h>
28}
29
Pau Espin Pedrol1de68732020-03-11 14:04:52 +010030#include "pcu_utils.h"
31
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +010032/* reset LLC frame */
33void gprs_llc::reset()
34{
Holger Hans Peter Freyther32f9a592013-11-13 17:14:42 +010035 m_index = 0;
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010036 m_length = 0;
Holger Hans Peter Freythera42b2ad2013-11-26 16:39:47 +010037
38 memset(frame, 0x42, sizeof(frame));
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +010039}
40
41void gprs_llc::reset_frame_space()
42{
Holger Hans Peter Freyther32f9a592013-11-13 17:14:42 +010043 m_index = 0;
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +010044}
45
Jacob Erlbeck612e93e2015-03-20 13:57:27 +010046/* Put an Unconfirmed Information (UI) Dummy command, see GSM 44.064, 6.4.2.2 */
47void gprs_llc::put_dummy_frame(size_t req_len)
48{
49 /* The shortest dummy command (the spec requests at least 6 octets) */
50 static const uint8_t llc_dummy_command[] = {
51 0x43, 0xc0, 0x01, 0x2b, 0x2b, 0x2b
52 };
Jacob Erlbeck3db617f2015-07-07 13:43:44 +020053 static const size_t max_dummy_command_len = 79;
Jacob Erlbeck612e93e2015-03-20 13:57:27 +010054
55 put_frame(llc_dummy_command, sizeof(llc_dummy_command));
56
57 if (req_len > max_dummy_command_len)
58 req_len = max_dummy_command_len;
59
60 /* Add further stuffing, if the requested length exceeds the minimum
61 * dummy command length */
62 while (m_length < req_len)
63 frame[m_length++] = 0x2b;
64}
65
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +010066void gprs_llc::put_frame(const uint8_t *data, size_t len)
67{
Holger Hans Peter Freyther857281f2013-11-13 14:56:55 +010068 /* only put frames when we are empty */
Holger Hans Peter Freyther32f9a592013-11-13 17:14:42 +010069 OSMO_ASSERT(m_index == 0 && m_length == 0);
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010070 append_frame(data, len);
71}
Holger Hans Peter Freyther857281f2013-11-13 14:56:55 +010072
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010073void gprs_llc::append_frame(const uint8_t *data, size_t len)
74{
Holger Hans Peter Freyther857281f2013-11-13 14:56:55 +010075 /* TODO: bounds check */
Holger Hans Peter Freyther60582202013-11-21 21:30:23 +010076 memcpy(frame + m_length, data, len);
Holger Hans Peter Freythere2310262013-11-13 16:56:15 +010077 m_length += len;
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +010078}
79
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +020080void gprs_llc::init()
81{
82 reset();
83}
84
85bool gprs_llc::is_user_data_frame(uint8_t *data, size_t len)
86{
87 if (len < 2)
88 return false;
89
90 if ((data[0] & 0x0f) == 1 /* GPRS_SAPI_GMM */)
91 return false;
92
Jacob Erlbeckd0aee852015-06-11 11:47:06 +020093 if ((data[0] & 0xe0) != 0xc0 /* LLC UI */)
94 /* It is not an LLC UI frame, see TS 44.064, 6.3 */
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +020095 return false;
96
97 return true;
98}
99
100void gprs_llc_queue::init()
101{
102 INIT_LLIST_HEAD(&m_queue);
103 m_queue_size = 0;
Jacob Erlbeck07eb6552015-06-15 11:05:44 +0200104 m_queue_octets = 0;
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +0200105 m_avg_queue_delay = 0;
106}
107
Pau Espin Pedrol5fc6e012020-02-26 20:05:33 +0100108
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100109void gprs_llc_queue::enqueue(struct msgb *llc_msg, const struct timespec *expire_time)
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +0200110{
Jacob Erlbeckb671dbf2015-06-15 14:32:33 +0200111 MetaInfo *meta_storage;
112
Pau Espin Pedrol5fc6e012020-02-26 20:05:33 +0100113 osmo_static_assert(sizeof(*meta_storage) <= sizeof(llc_msg->cb), info_does_not_fit);
Jacob Erlbeckb671dbf2015-06-15 14:32:33 +0200114
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +0200115 m_queue_size += 1;
Jacob Erlbeckb671dbf2015-06-15 14:32:33 +0200116 m_queue_octets += msgb_length(llc_msg);
117
118 meta_storage = (MetaInfo *)&llc_msg->cb[0];
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100119 osmo_clock_gettime(CLOCK_MONOTONIC, &meta_storage->recv_time);
Pau Espin Pedrol5fc6e012020-02-26 20:05:33 +0100120 meta_storage->expire_time = *expire_time;
Jacob Erlbeckb671dbf2015-06-15 14:32:33 +0200121
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +0200122 msgb_enqueue(&m_queue, llc_msg);
123}
124
125void gprs_llc_queue::clear(BTS *bts)
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +0100126{
127 struct msgb *msg;
128
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +0200129 while ((msg = msgb_dequeue(&m_queue))) {
130 if (bts)
Pau Espin Pedrol2338e532020-05-12 20:54:35 +0200131 bts->do_rate_ctr_inc(CTR_LLC_FRAME_DROPPED);
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +0100132 msgb_free(msg);
133 }
Holger Hans Peter Freyther550bb882013-12-04 17:10:54 +0100134
135 m_queue_size = 0;
Jacob Erlbeck07eb6552015-06-15 11:05:44 +0200136 m_queue_octets = 0;
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +0100137}
138
Jacob Erlbeck257b6302015-08-21 18:07:47 +0200139void gprs_llc_queue::move_and_merge(gprs_llc_queue *o)
140{
141 struct msgb *msg, *msg1 = NULL, *msg2 = NULL;
142 struct llist_head new_queue;
143 size_t queue_size = 0;
144 size_t queue_octets = 0;
145 INIT_LLIST_HEAD(&new_queue);
146
147 while (1) {
148 if (msg1 == NULL)
149 msg1 = msgb_dequeue(&m_queue);
150
151 if (msg2 == NULL)
152 msg2 = msgb_dequeue(&o->m_queue);
153
154 if (msg1 == NULL && msg2 == NULL)
155 break;
156
157 if (msg1 == NULL) {
158 msg = msg2;
159 msg2 = NULL;
160 } else if (msg2 == NULL) {
161 msg = msg1;
162 msg1 = NULL;
163 } else {
164 const MetaInfo *mi1 = (MetaInfo *)&msg1->cb[0];
165 const MetaInfo *mi2 = (MetaInfo *)&msg2->cb[0];
166
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100167 if (timespeccmp(&mi2->recv_time, &mi1->recv_time, >)) {
Jacob Erlbeck257b6302015-08-21 18:07:47 +0200168 msg = msg1;
169 msg1 = NULL;
170 } else {
171 msg = msg2;
172 msg2 = NULL;
173 }
174 }
175
176 msgb_enqueue(&new_queue, msg);
177 queue_size += 1;
178 queue_octets += msgb_length(msg);
179 }
180
181 OSMO_ASSERT(llist_empty(&m_queue));
182 OSMO_ASSERT(llist_empty(&o->m_queue));
183
184 o->m_queue_size = 0;
185 o->m_queue_octets = 0;
186
187 llist_splice_init(&new_queue, &m_queue);
188 m_queue_size = queue_size;
189 m_queue_octets = queue_octets;
190}
191
Daniel Willmann9c623892013-12-04 18:11:47 +0100192#define ALPHA 0.5f
193
Jacob Erlbeckb671dbf2015-06-15 14:32:33 +0200194struct msgb *gprs_llc_queue::dequeue(const MetaInfo **info)
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +0100195{
Daniel Willmann9c623892013-12-04 18:11:47 +0100196 struct msgb *msg;
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100197 struct timespec *tv, tv_now, tv_result;
Daniel Willmann9c623892013-12-04 18:11:47 +0100198 uint32_t lifetime;
Jacob Erlbeckb671dbf2015-06-15 14:32:33 +0200199 const MetaInfo *meta_storage;
Daniel Willmann9c623892013-12-04 18:11:47 +0100200
Jacob Erlbeck6dbe8222015-05-29 10:37:09 +0200201 msg = msgb_dequeue(&m_queue);
Daniel Willmann9c623892013-12-04 18:11:47 +0100202 if (!msg)
203 return NULL;
204
Jacob Erlbeckb671dbf2015-06-15 14:32:33 +0200205 meta_storage = (MetaInfo *)&msg->cb[0];
206
207 if (info)
208 *info = meta_storage;
209
Daniel Willmann9c623892013-12-04 18:11:47 +0100210 m_queue_size -= 1;
Jacob Erlbeckb671dbf2015-06-15 14:32:33 +0200211 m_queue_octets -= msgb_length(msg);
Daniel Willmann9c623892013-12-04 18:11:47 +0100212
213 /* take the second time */
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100214 osmo_clock_gettime(CLOCK_MONOTONIC, &tv_now);
215 tv = (struct timespec *)&msg->data[sizeof(*tv)];
216 timespecsub(&tv_now, &meta_storage->recv_time, &tv_result);
Daniel Willmann9c623892013-12-04 18:11:47 +0100217
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100218 lifetime = tv_result.tv_sec*1000 + tv_result.tv_nsec/1000000;
Daniel Willmann9c623892013-12-04 18:11:47 +0100219 m_avg_queue_delay = m_avg_queue_delay * ALPHA + lifetime * (1-ALPHA);
220
221 return msg;
Holger Hans Peter Freyther096f6f92013-11-07 07:21:06 +0100222}
Holger Hans Peter Freytherfce431c2013-11-13 15:17:12 +0100223
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100224void gprs_llc_queue::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timespec *tv)
Holger Hans Peter Freytherfce431c2013-11-13 15:17:12 +0100225{
226 uint16_t delay_csec;
227 if (bts->bts_data()->force_llc_lifetime)
228 delay_csec = bts->bts_data()->force_llc_lifetime;
229 else
230 delay_csec = pdu_delay_csec;
231
Holger Hans Peter Freyther5a7f6362013-11-21 21:59:32 +0100232 /* keep timestamp at 0 for infinite delay */
Holger Hans Peter Freyther985fd112013-11-13 15:19:39 +0100233 if (delay_csec == 0xffff) {
234 memset(tv, 0, sizeof(*tv));
235 return;
236 }
237
238 /* calculate timestamp of timeout */
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100239 struct timespec now, csec;
240 osmo_clock_gettime(CLOCK_MONOTONIC, &now);
241 csecs_to_timespec(delay_csec, &csec);
Holger Hans Peter Freyther51e093b2013-11-13 15:35:45 +0100242
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100243 timespecadd(&now, &csec, tv);
Holger Hans Peter Freytherfce431c2013-11-13 15:17:12 +0100244}
Holger Hans Peter Freytherb1302b02013-11-13 17:15:26 +0100245
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100246bool gprs_llc_queue::is_frame_expired(const struct timespec *tv_now,
247 const struct timespec *tv)
Holger Hans Peter Freytherb1302b02013-11-13 17:15:26 +0100248{
249 /* Timeout is infinite */
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100250 if (tv->tv_sec == 0 && tv->tv_nsec == 0)
Holger Hans Peter Freytherb1302b02013-11-13 17:15:26 +0100251 return false;
252
Pau Espin Pedrol1de68732020-03-11 14:04:52 +0100253 return timespeccmp(tv_now, tv, >);
Holger Hans Peter Freytherb1302b02013-11-13 17:15:26 +0100254}