blob: 6efd47515e63ce586719881774da3ab9ff15a006 [file] [log] [blame]
Harald Weltea43f7892009-12-01 18:04:30 +05301/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface,
2 * rest octet handling according to
3 * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
4
5/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
6 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <string.h>
26#include <stdlib.h>
27#include <errno.h>
28
29#include <openbsc/gsm_data.h>
30#include <openbsc/bitvec.h>
31#include <openbsc/rest_octets.h>
32
33/* generate SI1 rest octets */
34int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
35{
36 struct bitvec bv;
37
38 memset(&bv, 0, sizeof(bv));
39 bv.data = data;
40 bv.data_len = 2;
41
42 if (nch_pos) {
43 bitvec_set_bit(&bv, H);
44 bitvec_set_uint(&bv, *nch_pos, 5);
45 } else
46 bitvec_set_bit(&bv, L);
47
48 bitvec_spare_padding(&bv, 15);
49 return 0;
50}
51
52/* Append selection parameters to bitvec */
53static void append_selection_params(struct bitvec *bv,
54 const struct gsm48_si_selection_params *sp)
55{
56 if (sp->present) {
57 bitvec_set_bit(bv, H);
58 bitvec_set_bit(bv, sp->cbq);
59 bitvec_set_uint(bv, sp->cell_resel_off, 6);
60 bitvec_set_uint(bv, sp->temp_offs, 3);
61 bitvec_set_uint(bv, sp->penalty_time, 5);
62 } else
63 bitvec_set_bit(bv, L);
64}
65
66/* Append power offset to bitvec */
67static void append_power_offset(struct bitvec *bv,
68 const struct gsm48_si_power_offset *po)
69{
70 if (po->present) {
71 bitvec_set_bit(bv, H);
72 bitvec_set_uint(bv, po->power_offset, 2);
73 } else
74 bitvec_set_bit(bv, L);
75}
76
77/* Append GPRS indicator to bitvec */
78static void append_gprs_ind(struct bitvec *bv,
79 const struct gsm48_si3_gprs_ind *gi)
80{
81 if (gi->present) {
82 bitvec_set_bit(bv, H);
83 bitvec_set_uint(bv, gi->ra_colour, 3);
84 /* 0 == SI13 in BCCH Norm, 1 == SI13 sent on BCCH Ext */
85 bitvec_set_bit(bv, gi->si13_position);
86 } else
87 bitvec_set_bit(bv, L);
88}
89
90
91/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */
92int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3)
93{
94 struct bitvec bv;
95
96 memset(&bv, 0, sizeof(bv));
97 bv.data = data;
98 bv.data_len = 5;
99
100 /* Optional Selection Parameters */
101 append_selection_params(&bv, &si3->selection_params);
102
103 /* Optional Power Offset */
104 append_power_offset(&bv, &si3->power_offset);
105
106 /* Do we have a SI2ter on the BCCH? */
107 if (si3->si2ter_indicator)
108 bitvec_set_bit(&bv, H);
109 else
110 bitvec_set_bit(&bv, L);
111
112 /* Early Classmark Sending Control */
113 if (si3->early_cm_ctrl)
114 bitvec_set_bit(&bv, H);
115 else
116 bitvec_set_bit(&bv, L);
117
118 /* Do we have a SI Type 9 on the BCCH? */
119 if (si3->scheduling.present) {
120 bitvec_set_bit(&bv, H);
121 bitvec_set_uint(&bv, si3->scheduling.where, 3);
122 } else
123 bitvec_set_bit(&bv, L);
124
125 /* GPRS Indicator */
126 append_gprs_ind(&bv, &si3->gprs_ind);
127
128 return bitvec_spare_padding(&bv, (bv.data_len*8)-1);
129}
130
131static int append_lsa_params(struct bitvec *bv,
132 const struct gsm48_lsa_params *lsa_params)
133{
134 /* FIXME */
135}
136
137/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
138int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4)
139{
140 struct bitvec bv;
141
142 memset(&bv, 0, sizeof(bv));
143 bv.data = data;
144 bv.data_len = 11; /* FIXME: up to ? */
145
146 /* SI4 Rest Octets O */
147 append_selection_params(&bv, &si4->selection_params);
148 append_power_offset(&bv, &si4->power_offset);
149 append_gprs_ind(&bv, &si4->gprs_ind);
150
151 if (0 /* FIXME */) {
152 /* H and SI4 Rest Octets S */
153 bitvec_set_bit(&bv, H);
154
155 /* LSA Parameters */
156 if (si4->lsa_params.present) {
157 bitvec_set_bit(&bv, H);
158 append_lsa_params(&bv, &si4->lsa_params);
159 } else
160 bitvec_set_bit(&bv, L);
161
162 /* Cell Identity */
163 if (1) {
164 bitvec_set_bit(&bv, H);
165 bitvec_set_uint(&bv, si4->cell_id, 16);
166 } else
167 bitvec_set_bit(&bv, L);
168
169 /* LSA ID Information */
170 if (0) {
171 bitvec_set_bit(&bv, H);
172 /* FIXME */
173 } else
174 bitvec_set_bit(&bv, L);
175 } else {
176 /* L and break indicator */
177 bitvec_set_bit(&bv, L);
178 bitvec_set_bit(&bv, si4->break_ind ? H : L);
179 }
180
181 return 0;
182}
183
184/* GPRS Mobile Allocation as per TS 04.60 Chapter 12.10a:
185 < GPRS Mobile Allocation IE > ::=
186 < HSN : bit (6) >
187 { 0 | 1 < RFL number list : < RFL number list struct > > }
188 { 0 < MA_LENGTH : bit (6) >
189 < MA_BITMAP: bit (val(MA_LENGTH) + 1) >
190 | 1 { 0 | 1 <ARFCN index list : < ARFCN index list struct > > } } ;
191
192 < RFL number list struct > :: =
193 < RFL_NUMBER : bit (4) >
194 { 0 | 1 < RFL number list struct > } ;
195 < ARFCN index list struct > ::=
196 < ARFCN_INDEX : bit(6) >
197 { 0 | 1 < ARFCN index list struct > } ;
198 */
199static int append_gprs_mobile_alloc(struct bitvec *bv)
200{
201 /* Hopping Sequence Number */
202 bitvec_set_uint(bv, 0, 6);
203
204 if (0) {
205 /* We want to use a RFL number list */
206 bitvec_set_bit(bv, 1);
207 /* FIXME: RFL number list */
208 } else
209 bitvec_set_bit(bv, 0);
210
211 if (0) {
212 /* We want to use a MA_BITMAP */
213 bitvec_set_bit(bv, 0);
214 /* FIXME: MA_LENGTH, MA_BITMAP, ... */
215 } else {
216 bitvec_set_bit(bv, 1);
217 if (0) {
218 /* We want to provide an ARFCN index list */
219 bitvec_set_bit(bv, 1);
220 /* FIXME */
221 } else
222 bitvec_set_bit(bv, 0);
223 }
224 return 0;
225}
226
227static int encode_t3192(unsigned int t3192)
228{
229 if (t3192 == 0)
230 return 3;
231 else if (t3192 <= 80)
232 return 4;
233 else if (t3192 <= 120)
234 return 5;
235 else if (t3192 <= 160)
236 return 6;
237 else if (t3192 <= 200)
238 return 7;
239 else if (t3192 <= 500)
240 return 0;
241 else if (t3192 <= 1000)
242 return 1;
243 else if (t3192 <= 1500)
244 return 2;
245 else
246 return -EINVAL;
247}
248
249static int encode_drx_timer(unsigned int drx)
250{
251 if (drx == 0)
252 return 0;
253 else if (drx == 1)
254 return 1;
255 else if (drx == 2)
256 return 2;
257 else if (drx <= 4)
258 return 3;
259 else if (drx <= 8)
260 return 4;
261 else if (drx <= 16)
262 return 5;
263 else if (drx <= 32)
264 return 6;
265 else if (drx <= 64)
266 return 7;
267 else
268 return -EINVAL;
269}
270
271/* GPRS Cell Options as per TS 04.60 Chapter 12.24
272 < GPRS Cell Options IE > ::=
273 < NMO : bit(2) >
274 < T3168 : bit(3) >
275 < T3192 : bit(3) >
276 < DRX_TIMER_MAX: bit(3) >
277 < ACCESS_BURST_TYPE: bit >
278 < CONTROL_ACK_TYPE : bit >
279 < BS_CV_MAX: bit(4) >
280 { 0 | 1 < PAN_DEC : bit(3) >
281 < PAN_INC : bit(3) >
282 < PAN_MAX : bit(3) >
283 { 0 | 1 < Extension Length : bit(6) >
284 < bit (val(Extension Length) + 1
285 & { < Extension Information > ! { bit ** = <no string> } } ;
286 < Extension Information > ::=
287 { 0 | 1 < EGPRS_PACKET_CHANNEL_REQUEST : bit >
288 < BEP_PERIOD : bit(4) > }
289 < PFC_FEATURE_MODE : bit >
290 < DTM_SUPPORT : bit >
291 <BSS_PAGING_COORDINATION: bit >
292 <spare bit > ** ;
293 */
294static int append_gprs_cell_opt(struct bitvec *bv, struct gprs_cell_options *gco)
295{
296 int t3192, drx_timer_max;
297
298 t3192 = encode_t3192(gco->t3192);
299 if (t3192 < 0)
300 return t3192;
301
302 drx_timer_max = encode_drx_timer(gco->drx_timer_max);
303 if (drx_timer_max < 0)
304 return drx_timer_max;
305
306 bitvec_set_uint(bv, gco->nmo, 2);
307 bitvec_set_uint(bv, gco->t3168 / 500, 3);
308 bitvec_set_uint(bv, t3192, 3);
309 bitvec_set_uint(bv, drx_timer_max, 3);
310 /* ACCESS_BURST_TYPE: Hard-code 8bit */
311 bitvec_set_bit(bv, 0);
312 /* CONTROL_ACK_TYPE: Hard-code to RLC/MAC control block */
313 bitvec_set_bit(bv, 1);
314 bitvec_set_uint(bv, gco->bs_cv_max, 4);
315
316 /* hard-code no PAN_{DEC,INC,MAX} */
317 bitvec_set_bit(bv, 0);
318
319 /* no extension information (EDGE) */
320 bitvec_set_bit(bv, 0);
321
322 return 0;
323}
324
325static void append_gprs_pwr_ctrl_pars(struct bitvec *bv,
326 struct gprs_power_ctrl_pars *pcp)
327{
328 bitvec_set_uint(bv, pcp->alpha, 4);
329 bitvec_set_uint(bv, pcp->t_avg_w, 5);
330 bitvec_set_uint(bv, pcp->t_avg_t, 5);
331 bitvec_set_uint(bv, pcp->pc_meas_chan, 1);
332 bitvec_set_uint(bv, pcp->n_avg_i, 4);
333}
334
335/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */
336int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
337{
338 struct bitvec bv;
339
340 memset(&bv, 0, sizeof(bv));
341 bv.data = data;
342 bv.data_len = 21;
343
344 if (0) {
345 /* No rest octets */
346 bitvec_set_bit(&bv, L);
347 } else {
348 bitvec_set_bit(&bv, H);
349 bitvec_set_uint(&bv, si13->bcch_change_mark, 3);
350 bitvec_set_uint(&bv, si13->si_change_field, 4);
351 if (0) {
352 bitvec_set_bit(&bv, 0);
353 } else {
354 bitvec_set_bit(&bv, 1);
355 bitvec_set_uint(&bv, si13->bcch_change_mark, 2);
356 append_gprs_mobile_alloc(&bv);
357 }
358 if (!si13->pbcch_present) {
359 /* PBCCH not present in cell */
360 bitvec_set_bit(&bv, 0);
361 bitvec_set_uint(&bv, si13->no_pbcch.rac, 8);
362 bitvec_set_bit(&bv, si13->no_pbcch.spgc_ccch_sup);
363 bitvec_set_uint(&bv, si13->no_pbcch.prio_acc_thr, 3);
364 bitvec_set_uint(&bv, si13->no_pbcch.net_ctrl_ord, 2);
365 append_gprs_cell_opt(&bv, &si13->cell_opts);
366 append_gprs_pwr_ctrl_pars(&bv, &si13->pwr_ctrl_pars);
367 } else {
368 /* PBCCH present in cell */
369 bitvec_set_bit(&bv, 1);
370 bitvec_set_uint(&bv, si13->pbcch.psi1_rep_per, 4);
371 /* PBCCH Descripiton */
372 bitvec_set_uint(&bv, si13->pbcch.pb, 4);
373 bitvec_set_uint(&bv, si13->pbcch.tsc, 3);
374 bitvec_set_uint(&bv, si13->pbcch.tn, 3);
375 switch (si13->pbcch.carrier_type) {
376 case PBCCH_BCCH:
377 bitvec_set_bit(&bv, 0);
378 bitvec_set_bit(&bv, 0);
379 break;
380 case PBCCH_ARFCN:
381 bitvec_set_bit(&bv, 0);
382 bitvec_set_bit(&bv, 1);
383 bitvec_set_uint(&bv, si13->pbcch.arfcn, 10);
384 break;
385 case PBCCH_MAIO:
386 bitvec_set_bit(&bv, 1);
387 bitvec_set_uint(&bv, si13->pbcch.maio, 6);
388 break;
389 }
390 }
391 }
392 return bitvec_spare_padding(&bv, (bv.data_len*8)-1);
393}