blob: b2ec50fcc0eb003746406a7b2ca47ac8d5433225 [file] [log] [blame]
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +02001/*
2 * Copyright (C) 2013 by Holger Hans Peter Freyther
3 *
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <bts.h>
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020022#include <poll_controller.h>
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020023#include <tbf.h>
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +020024#include <encoding.h>
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020025
26#include <gprs_rlcmac.h>
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +020027#include <gprs_debug.h>
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020028
29extern "C" {
30 #include <osmocom/core/talloc.h>
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +020031 #include <osmocom/core/msgb.h>
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020032}
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020033
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +020034#include <arpa/inet.h>
35
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +020036#include <errno.h>
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020037#include <string.h>
38
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +020039extern void *tall_pcu_ctx;
40
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020041static BTS s_bts;
42
43BTS* BTS::main_bts()
44{
45 return &s_bts;
46}
47
48struct gprs_rlcmac_bts *BTS::bts_data()
49{
50 return &m_bts;
51}
52
53struct gprs_rlcmac_bts *bts_main_data()
54{
55 return BTS::main_bts()->bts_data();
56}
57
58BTS::BTS()
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020059 : m_cur_fn(0)
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020060 , m_pollController(*this)
Holger Hans Peter Freythercedf8902013-10-19 20:47:12 +020061 , m_sba(*this)
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020062{
63 memset(&m_bts, 0, sizeof(m_bts));
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020064 INIT_LLIST_HEAD(&m_bts.ul_tbfs);
65 INIT_LLIST_HEAD(&m_bts.dl_tbfs);
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020066 m_bts.bts = this;
Holger Hans Peter Freyther4ed1dae2013-10-20 10:14:03 +020067
68 /* initialize back pointers */
69 for (size_t trx_no = 0; trx_no < ARRAY_SIZE(m_bts.trx); ++trx_no) {
70 struct gprs_rlcmac_trx *trx = &m_bts.trx[trx_no];
71 trx->trx_no = trx_no;
72 trx->bts = this;
73
74 for (size_t ts_no = 0; ts_no < ARRAY_SIZE(trx->pdch); ++ts_no) {
75 struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts_no];
76 pdch->ts_no = ts_no;
77 pdch->trx = trx;
78 }
79 }
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020080}
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020081
82void BTS::set_current_frame_number(int fn)
83{
84 m_cur_fn = fn;
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020085 m_pollController.expireTimedout(m_cur_fn);
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020086}
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020087
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +020088int BTS::add_paging(uint8_t chan_needed, uint8_t *identity_lv)
89{
90 uint8_t l, trx, ts, any_tbf = 0;
91 struct gprs_rlcmac_tbf *tbf;
92 struct gprs_rlcmac_paging *pag;
93 uint8_t slot_mask[8];
94 int8_t first_ts; /* must be signed */
95
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020096 llist_head *tbfs_lists[] = {
97 &m_bts.ul_tbfs,
98 &m_bts.dl_tbfs,
99 NULL
100 };
101
102
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200103 LOGP(DRLCMAC, LOGL_INFO, "Add RR paging: chan-needed=%d MI=%s\n",
104 chan_needed, osmo_hexdump(identity_lv + 1, identity_lv[0]));
105
106 /* collect slots to page
107 * Mark slots for every TBF, but only mark one of it.
108 * Mark only the first slot found.
109 * Don't mark, if TBF uses a different slot that is already marked. */
110 memset(slot_mask, 0, sizeof(slot_mask));
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200111 for (l = 0; tbfs_lists[l]; l++) {
112 llist_for_each_entry(tbf, tbfs_lists[l], list) {
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200113 first_ts = -1;
114 for (ts = 0; ts < 8; ts++) {
115 if (tbf->pdch[ts]) {
116 /* remember the first slot found */
117 if (first_ts < 0)
118 first_ts = ts;
119 /* break, if we already marked a slot */
120 if ((slot_mask[tbf->trx_no] & (1 << ts)))
121 break;
122 }
123 }
124 /* mark first slot found, if none is marked already */
125 if (ts == 8 && first_ts >= 0) {
126 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
127 "TRX=%d TS=%d, so we mark\n",
128 (tbf->direction == GPRS_RLCMAC_UL_TBF)
129 ? "UL" : "DL",
130 tbf->tfi, tbf->trx_no, first_ts);
131 slot_mask[tbf->trx_no] |= (1 << first_ts);
132 } else
133 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
134 "already marked TRX=%d TS=%d\n",
135 (tbf->direction == GPRS_RLCMAC_UL_TBF)
136 ? "UL" : "DL",
137 tbf->tfi, tbf->trx_no, ts);
138 }
139 }
140
141 /* Now we have a list of marked slots. Every TBF uses at least one
142 * of these slots. */
143
144 /* schedule paging to all marked slots */
145 for (trx = 0; trx < 8; trx++) {
146 if (slot_mask[trx] == 0)
147 continue;
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200148 for (ts = 0; ts < 8; ts++) {
149 if ((slot_mask[trx] & (1 << ts))) {
150 /* schedule */
151 pag = talloc_zero(tall_pcu_ctx,
152 struct gprs_rlcmac_paging);
153 if (!pag)
154 return -ENOMEM;
155 pag->chan_needed = chan_needed;
156 memcpy(pag->identity_lv, identity_lv,
157 identity_lv[0] + 1);
158 m_bts.trx[trx].pdch[ts].add_paging(pag);
159 LOGP(DRLCMAC, LOGL_INFO, "Paging on PACCH of "
160 "TRX=%d TS=%d\n", trx, ts);
Holger Hans Peter Freyther94464852013-10-19 18:33:52 +0200161 any_tbf = 1;
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200162 }
163 }
164 }
165
166 if (!any_tbf)
167 LOGP(DRLCMAC, LOGL_INFO, "No paging, because no TBF\n");
168
169 return 0;
170}
171
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200172/* search for active downlink or uplink tbf */
173gprs_rlcmac_tbf *BTS::tbf_by_tlli(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
174{
175 struct gprs_rlcmac_tbf *tbf;
176 if (dir == GPRS_RLCMAC_UL_TBF) {
177 llist_for_each_entry(tbf, &m_bts.ul_tbfs, list) {
178 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
179 && tbf->tlli == tlli && tbf->tlli_valid)
180 return tbf;
181 }
182 } else {
183 llist_for_each_entry(tbf, &m_bts.dl_tbfs, list) {
184 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
185 && tbf->tlli == tlli)
186 return tbf;
187 }
188 }
189 return NULL;
190}
191
192gprs_rlcmac_tbf *BTS::tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
193{
194 struct gprs_rlcmac_tbf *tbf;
195
196 /* only one TBF can poll on specific TS/FN, because scheduler can only
197 * schedule one downlink control block (with polling) at a FN per TS */
198 llist_for_each_entry(tbf, &m_bts.ul_tbfs, list) {
199 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
200 && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
201 && tbf->poll_fn == fn && tbf->trx_no == trx
202 && tbf->control_ts == ts)
203 return tbf;
204 }
205 llist_for_each_entry(tbf, &m_bts.dl_tbfs, list) {
206 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
207 && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
208 && tbf->poll_fn == fn && tbf->trx_no == trx
209 && tbf->control_ts == ts)
210 return tbf;
211 }
212 return NULL;
213}
214
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200215void gprs_rlcmac_pdch::enable()
216{
217 /* TODO: Check if there are still allocated resources.. */
218 INIT_LLIST_HEAD(&paging_list);
219 m_is_enabled = 1;
220}
221
222void gprs_rlcmac_pdch::disable()
223{
224 /* TODO.. kick free_resources once we know the TRX/TS we are on */
225 m_is_enabled = 0;
226}
227
Holger Hans Peter Freythercedf8902013-10-19 20:47:12 +0200228/* TODO: kill the parameter and make a pdch belong to a trx.. to a bts.. */
Holger Hans Peter Freyther09ef27a2013-10-20 16:37:05 +0200229void gprs_rlcmac_pdch::free_resources()
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200230{
231 struct gprs_rlcmac_paging *pag;
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200232
233 /* we are not enabled. there should be no resources */
234 if (!is_enabled())
235 return;
236
237 /* kick all TBF on slot */
238 gprs_rlcmac_tbf::free_all(this);
239
240 /* flush all pending paging messages */
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200241 while ((pag = dequeue_paging()))
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200242 talloc_free(pag);
243
Holger Hans Peter Freyther09ef27a2013-10-20 16:37:05 +0200244 trx->bts->sba()->free_resources(this);
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200245}
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200246
247struct gprs_rlcmac_paging *gprs_rlcmac_pdch::dequeue_paging()
248{
249 struct gprs_rlcmac_paging *pag;
250
251 if (llist_empty(&paging_list))
252 return NULL;
253 pag = llist_entry(paging_list.next, struct gprs_rlcmac_paging, list);
254 llist_del(&pag->list);
255
256 return pag;
257}
258
259struct msgb *gprs_rlcmac_pdch::packet_paging_request()
260{
261 struct gprs_rlcmac_paging *pag;
262 struct msgb *msg;
263 unsigned wp = 0, len;
264
265 /* no paging, no message */
266 pag = dequeue_paging();
267 if (!pag)
268 return NULL;
269
270 LOGP(DRLCMAC, LOGL_DEBUG, "Scheduling paging\n");
271
272 /* alloc message */
273 msg = msgb_alloc(23, "pag ctrl block");
274 if (!msg) {
275 talloc_free(pag);
276 return NULL;
277 }
278 bitvec *pag_vec = bitvec_alloc(23);
279 if (!pag_vec) {
280 msgb_free(msg);
281 talloc_free(pag);
282 return NULL;
283 }
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +0200284 wp = Encoding::write_packet_paging_request(pag_vec);
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200285
286 /* loop until message is full */
287 while (pag) {
288 /* try to add paging */
289 if ((pag->identity_lv[1] & 0x07) == 4) {
290 /* TMSI */
291 LOGP(DRLCMAC, LOGL_DEBUG, "- TMSI=0x%08x\n",
292 ntohl(*((uint32_t *)(pag->identity_lv + 1))));
293 len = 1 + 1 + 1 + 32 + 2 + 1;
294 if (pag->identity_lv[0] != 5) {
295 LOGP(DRLCMAC, LOGL_ERROR, "TMSI paging with "
296 "MI != 5 octets!\n");
297 goto continue_next;
298 }
299 } else {
300 /* MI */
301 LOGP(DRLCMAC, LOGL_DEBUG, "- MI=%s\n",
302 osmo_hexdump(pag->identity_lv + 1,
303 pag->identity_lv[0]));
304 len = 1 + 1 + 1 + 4 + (pag->identity_lv[0]<<3) + 2 + 1;
305 if (pag->identity_lv[0] > 8) {
306 LOGP(DRLCMAC, LOGL_ERROR, "Paging with "
307 "MI > 8 octets!\n");
308 goto continue_next;
309 }
310 }
311 if (wp + len > 184) {
312 LOGP(DRLCMAC, LOGL_DEBUG, "- Does not fit, so schedule "
313 "next time\n");
314 /* put back paging record, because does not fit */
315 llist_add_tail(&pag->list, &paging_list);
316 break;
317 }
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +0200318 Encoding::write_repeated_page_info(pag_vec, wp, pag->identity_lv[0],
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200319 pag->identity_lv + 1, pag->chan_needed);
320
321continue_next:
322 talloc_free(pag);
323 pag = dequeue_paging();
324 }
325
326 bitvec_pack(pag_vec, msgb_put(msg, 23));
327 RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
328 LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n");
329 decode_gsm_rlcmac_downlink(pag_vec, mac_control_block);
330 LOGPC(DCSN1, LOGL_NOTICE, "\n");
331 LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n");
332 bitvec_free(pag_vec);
333 talloc_free(mac_control_block);
334
335 return msg;
336}
337
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200338void gprs_rlcmac_pdch::add_paging(struct gprs_rlcmac_paging *pag)
339{
340 llist_add(&pag->list, &paging_list);
341}