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