blob: b63a13d03ca652a0b61c8b06f7febcd106bbacdb [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>
24
25#include <gprs_rlcmac.h>
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +020026#include <gprs_debug.h>
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020027
28extern "C" {
29 #include <osmocom/core/talloc.h>
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +020030 #include <osmocom/core/msgb.h>
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020031}
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020032
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +020033#include <arpa/inet.h>
34
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +020035#include <errno.h>
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020036#include <string.h>
37
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +020038extern void *tall_pcu_ctx;
39
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +020040static llist_head *gprs_rlcmac_tbfs_lists[] = {
41 &gprs_rlcmac_ul_tbfs,
42 &gprs_rlcmac_dl_tbfs,
43 NULL
44};
45
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020046static BTS s_bts;
47
48BTS* BTS::main_bts()
49{
50 return &s_bts;
51}
52
53struct gprs_rlcmac_bts *BTS::bts_data()
54{
55 return &m_bts;
56}
57
58struct gprs_rlcmac_bts *bts_main_data()
59{
60 return BTS::main_bts()->bts_data();
61}
62
63BTS::BTS()
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020064 : m_cur_fn(0)
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020065 , m_pollController(*this)
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020066{
67 memset(&m_bts, 0, sizeof(m_bts));
68 m_bts.bts = this;
69}
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020070
71void BTS::set_current_frame_number(int fn)
72{
73 m_cur_fn = fn;
Holger Hans Peter Freytherb78adcd2013-10-17 20:12:37 +020074 m_pollController.expireTimedout(m_cur_fn);
Holger Hans Peter Freyther9b30c7f2013-10-17 19:59:56 +020075}
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +020076
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +020077int BTS::add_paging(uint8_t chan_needed, uint8_t *identity_lv)
78{
79 uint8_t l, trx, ts, any_tbf = 0;
80 struct gprs_rlcmac_tbf *tbf;
81 struct gprs_rlcmac_paging *pag;
82 uint8_t slot_mask[8];
83 int8_t first_ts; /* must be signed */
84
85 LOGP(DRLCMAC, LOGL_INFO, "Add RR paging: chan-needed=%d MI=%s\n",
86 chan_needed, osmo_hexdump(identity_lv + 1, identity_lv[0]));
87
88 /* collect slots to page
89 * Mark slots for every TBF, but only mark one of it.
90 * Mark only the first slot found.
91 * Don't mark, if TBF uses a different slot that is already marked. */
92 memset(slot_mask, 0, sizeof(slot_mask));
93 for (l = 0; gprs_rlcmac_tbfs_lists[l]; l++) {
94 llist_for_each_entry(tbf, gprs_rlcmac_tbfs_lists[l], list) {
95 first_ts = -1;
96 for (ts = 0; ts < 8; ts++) {
97 if (tbf->pdch[ts]) {
98 /* remember the first slot found */
99 if (first_ts < 0)
100 first_ts = ts;
101 /* break, if we already marked a slot */
102 if ((slot_mask[tbf->trx_no] & (1 << ts)))
103 break;
104 }
105 }
106 /* mark first slot found, if none is marked already */
107 if (ts == 8 && first_ts >= 0) {
108 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
109 "TRX=%d TS=%d, so we mark\n",
110 (tbf->direction == GPRS_RLCMAC_UL_TBF)
111 ? "UL" : "DL",
112 tbf->tfi, tbf->trx_no, first_ts);
113 slot_mask[tbf->trx_no] |= (1 << first_ts);
114 } else
115 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
116 "already marked TRX=%d TS=%d\n",
117 (tbf->direction == GPRS_RLCMAC_UL_TBF)
118 ? "UL" : "DL",
119 tbf->tfi, tbf->trx_no, ts);
120 }
121 }
122
123 /* Now we have a list of marked slots. Every TBF uses at least one
124 * of these slots. */
125
126 /* schedule paging to all marked slots */
127 for (trx = 0; trx < 8; trx++) {
128 if (slot_mask[trx] == 0)
129 continue;
130 any_tbf = 1;
131 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);
144 }
145 }
146 }
147
148 if (!any_tbf)
149 LOGP(DRLCMAC, LOGL_INFO, "No paging, because no TBF\n");
150
151 return 0;
152}
153
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200154void gprs_rlcmac_pdch::enable()
155{
156 /* TODO: Check if there are still allocated resources.. */
157 INIT_LLIST_HEAD(&paging_list);
158 m_is_enabled = 1;
159}
160
161void gprs_rlcmac_pdch::disable()
162{
163 /* TODO.. kick free_resources once we know the TRX/TS we are on */
164 m_is_enabled = 0;
165}
166
167void gprs_rlcmac_pdch::free_resources(uint8_t trx, uint8_t ts)
168{
169 struct gprs_rlcmac_paging *pag;
170 struct gprs_rlcmac_sba *sba, *sba2;
171
172 /* we are not enabled. there should be no resources */
173 if (!is_enabled())
174 return;
175
176 /* kick all TBF on slot */
177 gprs_rlcmac_tbf::free_all(this);
178
179 /* flush all pending paging messages */
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200180 while ((pag = dequeue_paging()))
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200181 talloc_free(pag);
182
183 llist_for_each_entry_safe(sba, sba2, &gprs_rlcmac_sbas, list) {
184 if (sba->trx == trx && sba->ts == ts) {
185 llist_del(&sba->list);
186 talloc_free(sba);
187 }
188 }
189}
Holger Hans Peter Freyther24e98d02013-10-19 18:15:44 +0200190
191struct gprs_rlcmac_paging *gprs_rlcmac_pdch::dequeue_paging()
192{
193 struct gprs_rlcmac_paging *pag;
194
195 if (llist_empty(&paging_list))
196 return NULL;
197 pag = llist_entry(paging_list.next, struct gprs_rlcmac_paging, list);
198 llist_del(&pag->list);
199
200 return pag;
201}
202
203struct msgb *gprs_rlcmac_pdch::packet_paging_request()
204{
205 struct gprs_rlcmac_paging *pag;
206 struct msgb *msg;
207 unsigned wp = 0, len;
208
209 /* no paging, no message */
210 pag = dequeue_paging();
211 if (!pag)
212 return NULL;
213
214 LOGP(DRLCMAC, LOGL_DEBUG, "Scheduling paging\n");
215
216 /* alloc message */
217 msg = msgb_alloc(23, "pag ctrl block");
218 if (!msg) {
219 talloc_free(pag);
220 return NULL;
221 }
222 bitvec *pag_vec = bitvec_alloc(23);
223 if (!pag_vec) {
224 msgb_free(msg);
225 talloc_free(pag);
226 return NULL;
227 }
228 wp = write_packet_paging_request(pag_vec);
229
230 /* loop until message is full */
231 while (pag) {
232 /* try to add paging */
233 if ((pag->identity_lv[1] & 0x07) == 4) {
234 /* TMSI */
235 LOGP(DRLCMAC, LOGL_DEBUG, "- TMSI=0x%08x\n",
236 ntohl(*((uint32_t *)(pag->identity_lv + 1))));
237 len = 1 + 1 + 1 + 32 + 2 + 1;
238 if (pag->identity_lv[0] != 5) {
239 LOGP(DRLCMAC, LOGL_ERROR, "TMSI paging with "
240 "MI != 5 octets!\n");
241 goto continue_next;
242 }
243 } else {
244 /* MI */
245 LOGP(DRLCMAC, LOGL_DEBUG, "- MI=%s\n",
246 osmo_hexdump(pag->identity_lv + 1,
247 pag->identity_lv[0]));
248 len = 1 + 1 + 1 + 4 + (pag->identity_lv[0]<<3) + 2 + 1;
249 if (pag->identity_lv[0] > 8) {
250 LOGP(DRLCMAC, LOGL_ERROR, "Paging with "
251 "MI > 8 octets!\n");
252 goto continue_next;
253 }
254 }
255 if (wp + len > 184) {
256 LOGP(DRLCMAC, LOGL_DEBUG, "- Does not fit, so schedule "
257 "next time\n");
258 /* put back paging record, because does not fit */
259 llist_add_tail(&pag->list, &paging_list);
260 break;
261 }
262 write_repeated_page_info(pag_vec, wp, pag->identity_lv[0],
263 pag->identity_lv + 1, pag->chan_needed);
264
265continue_next:
266 talloc_free(pag);
267 pag = dequeue_paging();
268 }
269
270 bitvec_pack(pag_vec, msgb_put(msg, 23));
271 RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
272 LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n");
273 decode_gsm_rlcmac_downlink(pag_vec, mac_control_block);
274 LOGPC(DCSN1, LOGL_NOTICE, "\n");
275 LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n");
276 bitvec_free(pag_vec);
277 talloc_free(mac_control_block);
278
279 return msg;
280}
281
Holger Hans Peter Freytherf0984892013-10-19 18:28:59 +0200282void gprs_rlcmac_pdch::add_paging(struct gprs_rlcmac_paging *pag)
283{
284 llist_add(&pag->list, &paging_list);
285}