blob: 353451c6f416069f7121ded7bcafe729bb201344 [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 Freytherf0984892013-10-19 18:28:59 +020041static llist_head *gprs_rlcmac_tbfs_lists[] = {
42 &gprs_rlcmac_ul_tbfs,
43 &gprs_rlcmac_dl_tbfs,
44 NULL
45};
46
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020047static BTS s_bts;
48
49BTS* BTS::main_bts()
50{
51 return &s_bts;
52}
53
54struct gprs_rlcmac_bts *BTS::bts_data()
55{
56 return &m_bts;
57}
58
59struct gprs_rlcmac_bts *bts_main_data()
60{
61 return BTS::main_bts()->bts_data();
62}
63
64BTS::BTS()
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020065 : m_cur_fn(0)
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020066 , m_pollController(*this)
Holger Hans Peter Freythercedf8902013-10-19 20:47:12 +020067 , m_sba(*this)
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020068{
69 memset(&m_bts, 0, sizeof(m_bts));
70 m_bts.bts = this;
71}
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020072
73void BTS::set_current_frame_number(int fn)
74{
75 m_cur_fn = fn;
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020076 m_pollController.expireTimedout(m_cur_fn);
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020077}
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020078
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +020079int BTS::add_paging(uint8_t chan_needed, uint8_t *identity_lv)
80{
81 uint8_t l, trx, ts, any_tbf = 0;
82 struct gprs_rlcmac_tbf *tbf;
83 struct gprs_rlcmac_paging *pag;
84 uint8_t slot_mask[8];
85 int8_t first_ts; /* must be signed */
86
87 LOGP(DRLCMAC, LOGL_INFO, "Add RR paging: chan-needed=%d MI=%s\n",
88 chan_needed, osmo_hexdump(identity_lv + 1, identity_lv[0]));
89
90 /* collect slots to page
91 * Mark slots for every TBF, but only mark one of it.
92 * Mark only the first slot found.
93 * Don't mark, if TBF uses a different slot that is already marked. */
94 memset(slot_mask, 0, sizeof(slot_mask));
95 for (l = 0; gprs_rlcmac_tbfs_lists[l]; l++) {
96 llist_for_each_entry(tbf, gprs_rlcmac_tbfs_lists[l], list) {
97 first_ts = -1;
98 for (ts = 0; ts < 8; ts++) {
99 if (tbf->pdch[ts]) {
100 /* remember the first slot found */
101 if (first_ts < 0)
102 first_ts = ts;
103 /* break, if we already marked a slot */
104 if ((slot_mask[tbf->trx_no] & (1 << ts)))
105 break;
106 }
107 }
108 /* mark first slot found, if none is marked already */
109 if (ts == 8 && first_ts >= 0) {
110 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
111 "TRX=%d TS=%d, so we mark\n",
112 (tbf->direction == GPRS_RLCMAC_UL_TBF)
113 ? "UL" : "DL",
114 tbf->tfi, tbf->trx_no, first_ts);
115 slot_mask[tbf->trx_no] |= (1 << first_ts);
116 } else
117 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
118 "already marked TRX=%d TS=%d\n",
119 (tbf->direction == GPRS_RLCMAC_UL_TBF)
120 ? "UL" : "DL",
121 tbf->tfi, tbf->trx_no, ts);
122 }
123 }
124
125 /* Now we have a list of marked slots. Every TBF uses at least one
126 * of these slots. */
127
128 /* schedule paging to all marked slots */
129 for (trx = 0; trx < 8; trx++) {
130 if (slot_mask[trx] == 0)
131 continue;
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200132 for (ts = 0; ts < 8; ts++) {
133 if ((slot_mask[trx] & (1 << ts))) {
134 /* schedule */
135 pag = talloc_zero(tall_pcu_ctx,
136 struct gprs_rlcmac_paging);
137 if (!pag)
138 return -ENOMEM;
139 pag->chan_needed = chan_needed;
140 memcpy(pag->identity_lv, identity_lv,
141 identity_lv[0] + 1);
142 m_bts.trx[trx].pdch[ts].add_paging(pag);
143 LOGP(DRLCMAC, LOGL_INFO, "Paging on PACCH of "
144 "TRX=%d TS=%d\n", trx, ts);
Holger Hans Peter Freyther94464852013-10-19 18:33:52 +0200145 any_tbf = 1;
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200146 }
147 }
148 }
149
150 if (!any_tbf)
151 LOGP(DRLCMAC, LOGL_INFO, "No paging, because no TBF\n");
152
153 return 0;
154}
155
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200156void gprs_rlcmac_pdch::enable()
157{
158 /* TODO: Check if there are still allocated resources.. */
159 INIT_LLIST_HEAD(&paging_list);
160 m_is_enabled = 1;
161}
162
163void gprs_rlcmac_pdch::disable()
164{
165 /* TODO.. kick free_resources once we know the TRX/TS we are on */
166 m_is_enabled = 0;
167}
168
Holger Hans Peter Freythercedf8902013-10-19 20:47:12 +0200169/* TODO: kill the parameter and make a pdch belong to a trx.. to a bts.. */
170void gprs_rlcmac_pdch::free_resources(BTS *bts, uint8_t trx, uint8_t ts)
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200171{
172 struct gprs_rlcmac_paging *pag;
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200173
174 /* we are not enabled. there should be no resources */
175 if (!is_enabled())
176 return;
177
178 /* kick all TBF on slot */
179 gprs_rlcmac_tbf::free_all(this);
180
181 /* flush all pending paging messages */
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200182 while ((pag = dequeue_paging()))
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200183 talloc_free(pag);
184
Holger Hans Peter Freythercedf8902013-10-19 20:47:12 +0200185 bts->sba()->free_resources(trx, ts);
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200186}
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200187
188struct gprs_rlcmac_paging *gprs_rlcmac_pdch::dequeue_paging()
189{
190 struct gprs_rlcmac_paging *pag;
191
192 if (llist_empty(&paging_list))
193 return NULL;
194 pag = llist_entry(paging_list.next, struct gprs_rlcmac_paging, list);
195 llist_del(&pag->list);
196
197 return pag;
198}
199
200struct msgb *gprs_rlcmac_pdch::packet_paging_request()
201{
202 struct gprs_rlcmac_paging *pag;
203 struct msgb *msg;
204 unsigned wp = 0, len;
205
206 /* no paging, no message */
207 pag = dequeue_paging();
208 if (!pag)
209 return NULL;
210
211 LOGP(DRLCMAC, LOGL_DEBUG, "Scheduling paging\n");
212
213 /* alloc message */
214 msg = msgb_alloc(23, "pag ctrl block");
215 if (!msg) {
216 talloc_free(pag);
217 return NULL;
218 }
219 bitvec *pag_vec = bitvec_alloc(23);
220 if (!pag_vec) {
221 msgb_free(msg);
222 talloc_free(pag);
223 return NULL;
224 }
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +0200225 wp = Encoding::write_packet_paging_request(pag_vec);
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200226
227 /* loop until message is full */
228 while (pag) {
229 /* try to add paging */
230 if ((pag->identity_lv[1] & 0x07) == 4) {
231 /* TMSI */
232 LOGP(DRLCMAC, LOGL_DEBUG, "- TMSI=0x%08x\n",
233 ntohl(*((uint32_t *)(pag->identity_lv + 1))));
234 len = 1 + 1 + 1 + 32 + 2 + 1;
235 if (pag->identity_lv[0] != 5) {
236 LOGP(DRLCMAC, LOGL_ERROR, "TMSI paging with "
237 "MI != 5 octets!\n");
238 goto continue_next;
239 }
240 } else {
241 /* MI */
242 LOGP(DRLCMAC, LOGL_DEBUG, "- MI=%s\n",
243 osmo_hexdump(pag->identity_lv + 1,
244 pag->identity_lv[0]));
245 len = 1 + 1 + 1 + 4 + (pag->identity_lv[0]<<3) + 2 + 1;
246 if (pag->identity_lv[0] > 8) {
247 LOGP(DRLCMAC, LOGL_ERROR, "Paging with "
248 "MI > 8 octets!\n");
249 goto continue_next;
250 }
251 }
252 if (wp + len > 184) {
253 LOGP(DRLCMAC, LOGL_DEBUG, "- Does not fit, so schedule "
254 "next time\n");
255 /* put back paging record, because does not fit */
256 llist_add_tail(&pag->list, &paging_list);
257 break;
258 }
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +0200259 Encoding::write_repeated_page_info(pag_vec, wp, pag->identity_lv[0],
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200260 pag->identity_lv + 1, pag->chan_needed);
261
262continue_next:
263 talloc_free(pag);
264 pag = dequeue_paging();
265 }
266
267 bitvec_pack(pag_vec, msgb_put(msg, 23));
268 RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
269 LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n");
270 decode_gsm_rlcmac_downlink(pag_vec, mac_control_block);
271 LOGPC(DCSN1, LOGL_NOTICE, "\n");
272 LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n");
273 bitvec_free(pag_vec);
274 talloc_free(mac_control_block);
275
276 return msg;
277}
278
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200279void gprs_rlcmac_pdch::add_paging(struct gprs_rlcmac_paging *pag)
280{
281 llist_add(&pag->list, &paging_list);
282}