blob: d6ed8f3f74931dacd2a7fcb6abe27c6f32608ae1 [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;
67}
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020068
69void BTS::set_current_frame_number(int fn)
70{
71 m_cur_fn = fn;
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020072 m_pollController.expireTimedout(m_cur_fn);
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020073}
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020074
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +020075int BTS::add_paging(uint8_t chan_needed, uint8_t *identity_lv)
76{
77 uint8_t l, trx, ts, any_tbf = 0;
78 struct gprs_rlcmac_tbf *tbf;
79 struct gprs_rlcmac_paging *pag;
80 uint8_t slot_mask[8];
81 int8_t first_ts; /* must be signed */
82
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020083 llist_head *tbfs_lists[] = {
84 &m_bts.ul_tbfs,
85 &m_bts.dl_tbfs,
86 NULL
87 };
88
89
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +020090 LOGP(DRLCMAC, LOGL_INFO, "Add RR paging: chan-needed=%d MI=%s\n",
91 chan_needed, osmo_hexdump(identity_lv + 1, identity_lv[0]));
92
93 /* collect slots to page
94 * Mark slots for every TBF, but only mark one of it.
95 * Mark only the first slot found.
96 * Don't mark, if TBF uses a different slot that is already marked. */
97 memset(slot_mask, 0, sizeof(slot_mask));
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020098 for (l = 0; tbfs_lists[l]; l++) {
99 llist_for_each_entry(tbf, tbfs_lists[l], list) {
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200100 first_ts = -1;
101 for (ts = 0; ts < 8; ts++) {
102 if (tbf->pdch[ts]) {
103 /* remember the first slot found */
104 if (first_ts < 0)
105 first_ts = ts;
106 /* break, if we already marked a slot */
107 if ((slot_mask[tbf->trx_no] & (1 << ts)))
108 break;
109 }
110 }
111 /* mark first slot found, if none is marked already */
112 if (ts == 8 && first_ts >= 0) {
113 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
114 "TRX=%d TS=%d, so we mark\n",
115 (tbf->direction == GPRS_RLCMAC_UL_TBF)
116 ? "UL" : "DL",
117 tbf->tfi, tbf->trx_no, first_ts);
118 slot_mask[tbf->trx_no] |= (1 << first_ts);
119 } else
120 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
121 "already marked TRX=%d TS=%d\n",
122 (tbf->direction == GPRS_RLCMAC_UL_TBF)
123 ? "UL" : "DL",
124 tbf->tfi, tbf->trx_no, ts);
125 }
126 }
127
128 /* Now we have a list of marked slots. Every TBF uses at least one
129 * of these slots. */
130
131 /* schedule paging to all marked slots */
132 for (trx = 0; trx < 8; trx++) {
133 if (slot_mask[trx] == 0)
134 continue;
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200135 for (ts = 0; ts < 8; ts++) {
136 if ((slot_mask[trx] & (1 << ts))) {
137 /* schedule */
138 pag = talloc_zero(tall_pcu_ctx,
139 struct gprs_rlcmac_paging);
140 if (!pag)
141 return -ENOMEM;
142 pag->chan_needed = chan_needed;
143 memcpy(pag->identity_lv, identity_lv,
144 identity_lv[0] + 1);
145 m_bts.trx[trx].pdch[ts].add_paging(pag);
146 LOGP(DRLCMAC, LOGL_INFO, "Paging on PACCH of "
147 "TRX=%d TS=%d\n", trx, ts);
Holger Hans Peter Freyther94464852013-10-19 18:33:52 +0200148 any_tbf = 1;
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200149 }
150 }
151 }
152
153 if (!any_tbf)
154 LOGP(DRLCMAC, LOGL_INFO, "No paging, because no TBF\n");
155
156 return 0;
157}
158
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200159/* search for active downlink or uplink tbf */
160gprs_rlcmac_tbf *BTS::tbf_by_tlli(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
161{
162 struct gprs_rlcmac_tbf *tbf;
163 if (dir == GPRS_RLCMAC_UL_TBF) {
164 llist_for_each_entry(tbf, &m_bts.ul_tbfs, list) {
165 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
166 && tbf->tlli == tlli && tbf->tlli_valid)
167 return tbf;
168 }
169 } else {
170 llist_for_each_entry(tbf, &m_bts.dl_tbfs, list) {
171 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
172 && tbf->tlli == tlli)
173 return tbf;
174 }
175 }
176 return NULL;
177}
178
179gprs_rlcmac_tbf *BTS::tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
180{
181 struct gprs_rlcmac_tbf *tbf;
182
183 /* only one TBF can poll on specific TS/FN, because scheduler can only
184 * schedule one downlink control block (with polling) at a FN per TS */
185 llist_for_each_entry(tbf, &m_bts.ul_tbfs, list) {
186 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
187 && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
188 && tbf->poll_fn == fn && tbf->trx_no == trx
189 && tbf->control_ts == ts)
190 return tbf;
191 }
192 llist_for_each_entry(tbf, &m_bts.dl_tbfs, list) {
193 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)
194 && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
195 && tbf->poll_fn == fn && tbf->trx_no == trx
196 && tbf->control_ts == ts)
197 return tbf;
198 }
199 return NULL;
200}
201
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200202void gprs_rlcmac_pdch::enable()
203{
204 /* TODO: Check if there are still allocated resources.. */
205 INIT_LLIST_HEAD(&paging_list);
206 m_is_enabled = 1;
207}
208
209void gprs_rlcmac_pdch::disable()
210{
211 /* TODO.. kick free_resources once we know the TRX/TS we are on */
212 m_is_enabled = 0;
213}
214
Holger Hans Peter Freythercedf8902013-10-19 20:47:12 +0200215/* TODO: kill the parameter and make a pdch belong to a trx.. to a bts.. */
216void gprs_rlcmac_pdch::free_resources(BTS *bts, uint8_t trx, uint8_t ts)
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200217{
218 struct gprs_rlcmac_paging *pag;
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200219
220 /* we are not enabled. there should be no resources */
221 if (!is_enabled())
222 return;
223
224 /* kick all TBF on slot */
225 gprs_rlcmac_tbf::free_all(this);
226
227 /* flush all pending paging messages */
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200228 while ((pag = dequeue_paging()))
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200229 talloc_free(pag);
230
Holger Hans Peter Freythercedf8902013-10-19 20:47:12 +0200231 bts->sba()->free_resources(trx, ts);
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200232}
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200233
234struct gprs_rlcmac_paging *gprs_rlcmac_pdch::dequeue_paging()
235{
236 struct gprs_rlcmac_paging *pag;
237
238 if (llist_empty(&paging_list))
239 return NULL;
240 pag = llist_entry(paging_list.next, struct gprs_rlcmac_paging, list);
241 llist_del(&pag->list);
242
243 return pag;
244}
245
246struct msgb *gprs_rlcmac_pdch::packet_paging_request()
247{
248 struct gprs_rlcmac_paging *pag;
249 struct msgb *msg;
250 unsigned wp = 0, len;
251
252 /* no paging, no message */
253 pag = dequeue_paging();
254 if (!pag)
255 return NULL;
256
257 LOGP(DRLCMAC, LOGL_DEBUG, "Scheduling paging\n");
258
259 /* alloc message */
260 msg = msgb_alloc(23, "pag ctrl block");
261 if (!msg) {
262 talloc_free(pag);
263 return NULL;
264 }
265 bitvec *pag_vec = bitvec_alloc(23);
266 if (!pag_vec) {
267 msgb_free(msg);
268 talloc_free(pag);
269 return NULL;
270 }
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +0200271 wp = Encoding::write_packet_paging_request(pag_vec);
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200272
273 /* loop until message is full */
274 while (pag) {
275 /* try to add paging */
276 if ((pag->identity_lv[1] & 0x07) == 4) {
277 /* TMSI */
278 LOGP(DRLCMAC, LOGL_DEBUG, "- TMSI=0x%08x\n",
279 ntohl(*((uint32_t *)(pag->identity_lv + 1))));
280 len = 1 + 1 + 1 + 32 + 2 + 1;
281 if (pag->identity_lv[0] != 5) {
282 LOGP(DRLCMAC, LOGL_ERROR, "TMSI paging with "
283 "MI != 5 octets!\n");
284 goto continue_next;
285 }
286 } else {
287 /* MI */
288 LOGP(DRLCMAC, LOGL_DEBUG, "- MI=%s\n",
289 osmo_hexdump(pag->identity_lv + 1,
290 pag->identity_lv[0]));
291 len = 1 + 1 + 1 + 4 + (pag->identity_lv[0]<<3) + 2 + 1;
292 if (pag->identity_lv[0] > 8) {
293 LOGP(DRLCMAC, LOGL_ERROR, "Paging with "
294 "MI > 8 octets!\n");
295 goto continue_next;
296 }
297 }
298 if (wp + len > 184) {
299 LOGP(DRLCMAC, LOGL_DEBUG, "- Does not fit, so schedule "
300 "next time\n");
301 /* put back paging record, because does not fit */
302 llist_add_tail(&pag->list, &paging_list);
303 break;
304 }
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +0200305 Encoding::write_repeated_page_info(pag_vec, wp, pag->identity_lv[0],
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200306 pag->identity_lv + 1, pag->chan_needed);
307
308continue_next:
309 talloc_free(pag);
310 pag = dequeue_paging();
311 }
312
313 bitvec_pack(pag_vec, msgb_put(msg, 23));
314 RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
315 LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n");
316 decode_gsm_rlcmac_downlink(pag_vec, mac_control_block);
317 LOGPC(DCSN1, LOGL_NOTICE, "\n");
318 LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n");
319 bitvec_free(pag_vec);
320 talloc_free(mac_control_block);
321
322 return msg;
323}
324
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200325void gprs_rlcmac_pdch::add_paging(struct gprs_rlcmac_paging *pag)
326{
327 llist_add(&pag->list, &paging_list);
328}