blob: 4adcfbac27b6c7bd79dcf89c4592be313a0402ea [file] [log] [blame]
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001/* gprs_rlcmac.cpp
2 *
3 * Copyright (C) 2012 Ivan Klyuchnikov
Andreas Eversberg5dac2f02012-06-27 15:52:04 +02004 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
Holger Hans Peter Freytherd6bd91e2013-08-24 21:16:55 +02005 * Copyright (C) 2013 by Holger Hans Peter Freyther
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22#include <gprs_bssgp_pcu.h>
23#include <pcu_l1_if.h>
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +040024#include <gprs_rlcmac.h>
Holger Hans Peter Freyther67ed34e2013-10-17 17:01:54 +020025#include <bts.h>
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +020026#include <encoding.h>
Holger Hans Peter Freyther099535a2013-10-16 17:42:31 +020027#include <tbf.h>
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +040028
Andreas Eversberg53f47252012-07-15 07:10:10 +020029
Andreas Eversberg6681bb82012-07-25 08:48:44 +020030extern void *tall_pcu_ctx;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +040031
Andreas Eversbergb83e2a72012-10-07 15:26:00 +020032#ifdef DEBUG_DIAGRAM
33struct timeval diagram_time = {0,0};
34struct timeval diagram_last_tv = {0,0};
35
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020036void debug_diagram(BTS *bts, int diag, const char *format, ...)
Andreas Eversbergb83e2a72012-10-07 15:26:00 +020037{
38 va_list ap;
39 char debug[128];
40 char line[1024];
41 struct gprs_rlcmac_tbf *tbf, *tbf_a[16];
42 int max_diag = -1, i;
43 uint64_t diff = 0;
44
45 va_start(ap, format);
46 vsnprintf(debug, sizeof(debug) - 1, format, ap);
47 debug[19] = ' ';
48 debug[20] = '\0';
49 va_end(ap);
50
51 memset(tbf_a, 0, sizeof(tbf_a));
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020052 llist_for_each_entry(tbf, &bts->bts_data()->ul_tbfs, list) {
Andreas Eversbergb83e2a72012-10-07 15:26:00 +020053 if (tbf->diag < 16) {
54 if (tbf->diag > max_diag)
55 max_diag = tbf->diag;
56 tbf_a[tbf->diag] = tbf;
57 }
58 }
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020059 llist_for_each_entry(tbf, &bts->bts_data()->dl_tbfs, list) {
Andreas Eversbergb83e2a72012-10-07 15:26:00 +020060 if (tbf->diag < 16) {
61 if (tbf->diag > max_diag)
62 max_diag = tbf->diag;
63 tbf_a[tbf->diag] = tbf;
64 }
65 }
66
67 if (diagram_last_tv.tv_sec) {
68 diff = (uint64_t)(diagram_time.tv_sec -
69 diagram_last_tv.tv_sec) * 1000;
70 diff += diagram_time.tv_usec / 1000;
71 diff -= diagram_last_tv.tv_usec / 1000;
72 }
73 memcpy(&diagram_last_tv, &diagram_time, sizeof(struct timeval));
74
75 if (diff > 0) {
76 if (diff > 99999)
77 strcpy(line, " ... : ");
78 else
79 sprintf(line, "%3d.%03d: ", (int)(diff / 1000),
80 (int)(diff % 1000));
81 for (i = 0; i <= max_diag; i++) {
82 if (tbf_a[i] == NULL) {
83 strcat(line, " ");
84 continue;
85 }
86 if (tbf_a[i]->diag_new) {
87 strcat(line, " | ");
88 continue;
89 }
90 strcat(line, " ");
91 }
92 puts(line);
93 }
94 strcpy(line, " : ");
95 for (i = 0; i <= max_diag; i++) {
96 if (tbf_a[i] == NULL) {
97 strcat(line, " ");
98 continue;
99 }
100 if (tbf_a[i]->diag != diag) {
101 strcat(line, " | ");
102 continue;
103 }
104 if (strlen(debug) < 19) {
105 strcat(line, " ");
106 memcpy(line + strlen(line) - 11 - strlen(debug) / 2,
107 debug, strlen(debug));
108 } else
109 strcat(line, debug);
110 tbf_a[i]->diag_new = 1;
111 }
112 puts(line);
113}
114#endif
115
Holger Hans Peter Freyther483f77a2013-10-16 16:33:00 +0200116/* FIXME: spread resources over multiple TRX. Also add option to use same
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200117 * TRX in case of existing TBF for TLLI in the other direction. */
Andreas Eversberg02d7cd22013-01-15 08:59:34 +0100118/* search for free TFI and return TFI, TRX */
Holger Hans Peter Freytherd6bd91e2013-08-24 21:16:55 +0200119int tfi_find_free(struct gprs_rlcmac_bts *bts, enum gprs_rlcmac_tbf_direction dir,
Holger Hans Peter Freytherb67a8a32013-07-28 18:55:14 +0200120 uint8_t *_trx, int8_t use_trx)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400121{
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200122 struct gprs_rlcmac_pdch *pdch;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200123 struct gprs_rlcmac_tbf **tbfp;
124 uint8_t trx_from, trx_to, trx, ts, tfi;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400125
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200126 if (use_trx >= 0 && use_trx < 8)
127 trx_from = trx_to = use_trx;
128 else {
129 trx_from = 0;
130 trx_to = 7;
131 }
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200132
133 /* on TRX find first enabled TS */
134 for (trx = trx_from; trx <= trx_to; trx++) {
Andreas Eversberg02d7cd22013-01-15 08:59:34 +0100135 for (ts = 0; ts < 8; ts++) {
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200136 pdch = &bts->trx[trx].pdch[ts];
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200137 if (!pdch->is_enabled())
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200138 continue;
139 break;
140 }
141 if (ts < 8)
142 break;
143 }
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200144 if (trx > trx_to) {
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200145 LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
146 return -EINVAL;
147 }
148
149
150 LOGP(DRLCMAC, LOGL_DEBUG, "Searching for first unallocated TFI: "
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200151 "TRX=%d first TS=%d\n", trx, ts);
152 if (dir == GPRS_RLCMAC_UL_TBF)
Andreas Eversbergadb2f182012-08-07 17:06:08 +0200153 tbfp = bts->trx[trx].ul_tbf;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200154 else
Andreas Eversbergadb2f182012-08-07 17:06:08 +0200155 tbfp = bts->trx[trx].dl_tbf;
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200156 for (tfi = 0; tfi < 32; tfi++) {
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200157 if (!tbfp[tfi])
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200158 break;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400159 }
160
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200161 if (tfi < 32) {
162 LOGP(DRLCMAC, LOGL_DEBUG, " Found TFI=%d.\n", tfi);
163 *_trx = trx;
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200164 return tfi;
165 }
166 LOGP(DRLCMAC, LOGL_NOTICE, "No TFI available.\n");
167
168 return -1;
169}
170
Andreas Eversberge6228b32012-07-03 13:36:03 +0200171/* received RLC/MAC block from L1 */
Holger Hans Peter Freyther698b6122013-10-17 13:44:18 +0200172int gprs_rlcmac_rcv_block(struct gprs_rlcmac_bts *bts,
173 uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len,
Andreas Eversberg570b44b2013-03-16 16:15:01 +0100174 uint32_t fn, int8_t rssi)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400175{
Andreas Eversberge6228b32012-07-03 13:36:03 +0200176 unsigned payload = data[0] >> 6;
177 bitvec *block;
178 int rc = 0;
Ivan Kluchnikov34460b82012-06-27 18:41:04 +0400179
Andreas Eversberge6228b32012-07-03 13:36:03 +0200180 switch (payload) {
181 case GPRS_RLCMAC_DATA_BLOCK:
Holger Hans Peter Freyther698b6122013-10-17 13:44:18 +0200182 rc = gprs_rlcmac_rcv_data_block_acknowledged(bts, trx, ts, data,
Andreas Eversberg570b44b2013-03-16 16:15:01 +0100183 len, rssi);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200184 break;
185 case GPRS_RLCMAC_CONTROL_BLOCK:
186 block = bitvec_alloc(len);
187 if (!block)
188 return -ENOMEM;
189 bitvec_unpack(block, data);
Holger Hans Peter Freyther8d7a6322013-10-17 15:23:49 +0200190 rc = gprs_rlcmac_rcv_control_block(bts, block, trx, ts, fn);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200191 bitvec_free(block);
192 break;
193 case GPRS_RLCMAC_CONTROL_BLOCK_OPT:
194 LOGP(DRLCMAC, LOGL_NOTICE, "GPRS_RLCMAC_CONTROL_BLOCK_OPT block payload is not supported.\n");
Holger Hans Peter Freyther26da8362013-10-16 16:34:09 +0200195 break;
Andreas Eversberge6228b32012-07-03 13:36:03 +0200196 default:
Holger Hans Peter Freyther70862c92013-10-16 16:37:22 +0200197 LOGP(DRLCMAC, LOGL_NOTICE, "Unknown RLCMAC block payload(%u).\n", payload);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200198 rc = -EINVAL;
Ivan Kluchnikov34460b82012-06-27 18:41:04 +0400199 }
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400200
Andreas Eversberge6228b32012-07-03 13:36:03 +0200201 return rc;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400202}
203
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400204/* Send Uplink unit-data to SGSN. */
Andreas Eversberg3e372d52012-07-06 09:28:15 +0200205int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400206{
Andreas Eversberg9a913462012-09-23 06:42:38 +0200207 uint8_t qos_profile[3];
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400208 struct msgb *llc_pdu;
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200209 unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + tbf->llc_index;
Holger Hans Peter Freyther90692f92013-07-13 12:51:16 +0200210 struct bssgp_bvc_ctx *bctx = gprs_bssgp_pcu_current_bctx();
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400211
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200212 LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] TFI: %u TLLI: 0x%08x len=%d\n", tbf->tfi, tbf->tlli, tbf->llc_index);
Andreas Eversberg3e372d52012-07-06 09:28:15 +0200213 if (!bctx) {
214 LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
215 return -EIO;
216 }
Ivan Kluchnikovc320d862012-03-18 15:04:48 +0400217
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400218 llc_pdu = msgb_alloc_headroom(msg_len, msg_len,"llc_pdu");
Andreas Eversberg9a913462012-09-23 06:42:38 +0200219 uint8_t *buf = msgb_push(llc_pdu, TL16V_GROSS_LEN(sizeof(uint8_t)*tbf->llc_index));
220 tl16v_put(buf, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*tbf->llc_index, tbf->llc_frame);
221 qos_profile[0] = QOS_PROFILE >> 16;
222 qos_profile[1] = QOS_PROFILE >> 8;
223 qos_profile[2] = QOS_PROFILE;
224 bssgp_tx_ul_ud(bctx, tbf->tlli, qos_profile, llc_pdu);
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400225
Andreas Eversberg3e372d52012-07-06 09:28:15 +0200226 return 0;
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +0400227}
Andreas Eversberg8c3680d2012-10-08 12:30:56 +0200228
229int gprs_rlcmac_paging_request(uint8_t *ptmsi, uint16_t ptmsi_len,
230 const char *imsi)
231{
232 LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] Paging Request (CCCH)\n");
233 bitvec *paging_request = bitvec_alloc(23);
234 bitvec_unhex(paging_request, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +0200235 int plen = Encoding::write_paging_request(paging_request, ptmsi, ptmsi_len);
Andreas Eversberg8c3680d2012-10-08 12:30:56 +0200236 pcu_l1if_tx_pch(paging_request, plen, (char *)imsi);
237 bitvec_free(paging_request);
238
239 return 0;
240}
Andreas Eversberga004e6a2013-05-13 16:45:21 +0200241
242