21baa97bb74ec07dba07be2a62eac3236041f07c
[lcr.git] / bootstrap.c
1 /* Bootstrapping GSM - taken from bsc_hack.c */
2
3 /* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
4  * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (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 along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <time.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32
33 #ifndef _GNU_SOURCE
34 #define _GNU_SOURCE
35 #endif
36 #include <getopt.h>
37
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 #include <openbsc/gsm_data.h>
42 #include <openbsc/gsm_04_08.h>
43 #include <openbsc/db.h>
44 #include <openbsc/timer.h>
45 #include <openbsc/select.h>
46 #include <openbsc/abis_rsl.h>
47 #include <openbsc/abis_nm.h>
48 #include <openbsc/debug.h>
49 #include <openbsc/misdn.h>
50 #include <openbsc/telnet_interface.h>
51 #include <openbsc/paging.h>
52 #include <openbsc/e1_input.h>
53
54 /* The following definitions are for OM and NM packets that we cannot yet
55  * generate by code but we just pass on */
56
57 // BTS Site Manager, SET ATTRIBUTES
58
59 /*
60   Object Class: BTS Site Manager
61   Instance 1: FF
62   Instance 2: FF
63   Instance 3: FF
64 SET ATTRIBUTES
65   sAbisExternalTime: 2007/09/08   14:36:11
66   omLAPDRelTimer: 30sec
67   shortLAPDIntTimer: 5sec
68   emergencyTimer1: 10 minutes
69   emergencyTimer2: 0 minutes
70 */
71
72 unsigned char msg_1[] = 
73 {
74         0xD0, 0x00, 0xFF, 0xFF, 0xFF, 
75                 NM_ATT_BS11_ABIS_EXT_TIME, 0x07, 0xD7, 0x09, 0x08, 0x0E, 0x24, 0x0B, 0xCE, 
76                 0x02, 0x00, 0x1E, 
77                 0xE8, 0x01, 0x05,
78                 0x42, 0x02, 0x00, 0x0A, 
79                 0x44, 0x02, 0x00, 0x00
80 };
81
82 // BTS, SET BTS ATTRIBUTES
83
84 /*
85   Object Class: BTS
86   BTS relat. Number: 0 
87   Instance 2: FF
88   Instance 3: FF
89 SET BTS ATTRIBUTES
90   bsIdentityCode / BSIC:
91     PLMN_colour_code: 7h
92     BS_colour_code:   7h
93   BTS Air Timer T3105: 4  ,unit 10 ms
94   btsIsHopping: FALSE
95   periodCCCHLoadIndication: 1sec
96   thresholdCCCHLoadIndication: 0%
97   cellAllocationNumber: 00h = GSM 900
98   enableInterferenceClass: 00h =  Disabled
99   fACCHQual: 6 (FACCH stealing flags minus 1)
100   intaveParameter: 31 SACCH multiframes
101   interferenceLevelBoundaries:
102     Interference Boundary 1: 0Ah 
103     Interference Boundary 2: 0Fh
104     Interference Boundary 3: 14h
105     Interference Boundary 4: 19h
106     Interference Boundary 5: 1Eh
107   mSTxPwrMax: 11
108       GSM range:     2=39dBm, 15=13dBm, stepsize 2 dBm 
109       DCS1800 range: 0=30dBm, 15=0dBm, stepsize 2 dBm 
110       PCS1900 range: 0=30dBm, 15=0dBm, stepsize 2 dBm 
111                     30=33dBm, 31=32dBm 
112   ny1:
113     Maximum number of repetitions for PHYSICAL INFORMATION message (GSM 04.08): 20
114   powerOutputThresholds:
115     Out Power Fault Threshold:     -10 dB
116     Red Out Power Threshold:       - 6 dB
117     Excessive Out Power Threshold:   5 dB
118   rACHBusyThreshold: -127 dBm 
119   rACHLoadAveragingSlots: 250 ,number of RACH burst periods
120   rfResourceIndicationPeriod: 125  SACCH multiframes 
121   T200:
122     SDCCH:                044 in  5 ms
123     FACCH/Full rate:      031 in  5 ms
124     FACCH/Half rate:      041 in  5 ms
125     SACCH with TCH SAPI0: 090 in 10 ms
126     SACCH with SDCCH:     090 in 10 ms
127     SDCCH with SAPI3:     090 in  5 ms
128     SACCH with TCH SAPI3: 135 in 10 ms
129   tSync: 9000 units of 10 msec
130   tTrau: 9000 units of 10 msec
131   enableUmLoopTest: 00h =  disabled
132   enableExcessiveDistance: 00h =  Disabled
133   excessiveDistance: 64km
134   hoppingMode: 00h = baseband hopping
135   cellType: 00h =  Standard Cell
136   BCCH ARFCN / bCCHFrequency: 1
137 */
138
139 unsigned char msg_2[] = 
140 {
141         0x41, 0x01, 0x00, 0xFF, 0xFF,
142                 NM_ATT_BSIC, 0x3F,
143                 NM_ATT_BTS_AIR_TIMER, 0x04,
144                 NM_ATT_BS11_BTSLS_HOPPING, 0x00,
145                 NM_ATT_CCCH_L_I_P, 0x01,
146                 NM_ATT_CCCH_L_T, 0x00,
147                 NM_ATT_BS11_CELL_ALLOC_NR, 0x00,
148                 NM_ATT_BS11_ENA_INTERF_CLASS, 0x00,
149                 NM_ATT_BS11_FACCH_QUAL, 0x06,
150                 NM_ATT_INTAVE_PARAM, 0x1F, 
151                 NM_ATT_INTERF_BOUND, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x7B,
152                 NM_ATT_CCCH_L_T, 0x23,
153                 NM_ATT_GSM_TIME, 0x28, 0x00,
154                 NM_ATT_ADM_STATE, 0x03,
155                 NM_ATT_RACH_B_THRESH, 0x7F,
156                 NM_ATT_LDAVG_SLOTS, 0x00, 0xFA,
157                 NM_ATT_BS11_RF_RES_IND_PER, 0x7D,
158                 NM_ATT_T200, 0x2C, 0x1F, 0x29, 0x5A, 0x5A, 0x5A, 0x87,
159                 NM_ATT_BS11_TSYNC, 0x23, 0x28,
160                 NM_ATT_BS11_TTRAU, 0x23, 0x28, 
161                 NM_ATT_TEST_DUR, 0x01, 0x00,
162                 NM_ATT_OUTST_ALARM, 0x01, 0x00,
163                 NM_ATT_BS11_EXCESSIVE_DISTANCE, 0x01, 0x40,
164                 NM_ATT_BS11_HOPPING_MODE, 0x01, 0x00,
165                 NM_ATT_BS11_PLL, 0x01, 0x00, 
166                 NM_ATT_BCCH_ARFCN, 0x00, HARDCODED_ARFCN/*0x01*/, 
167 };
168
169 // Handover Recognition, SET ATTRIBUTES
170
171 /*
172 Illegal Contents GSM Formatted O&M Msg 
173   Object Class: Handover Recognition
174   BTS relat. Number: 0 
175   Instance 2: FF
176   Instance 3: FF
177 SET ATTRIBUTES
178   enableDelayPowerBudgetHO: 00h = Disabled
179   enableDistanceHO: 00h =  Disabled
180   enableInternalInterCellHandover: 00h = Disabled
181   enableInternalIntraCellHandover: 00h =  Disabled
182   enablePowerBudgetHO: 00h = Disabled
183   enableRXLEVHO: 00h =  Disabled
184   enableRXQUALHO: 00h =  Disabled
185   hoAveragingDistance: 8  SACCH multiframes 
186   hoAveragingLev:
187     A_LEV_HO: 8  SACCH multiframes 
188     W_LEV_HO: 1  SACCH multiframes 
189   hoAveragingPowerBudget:  16  SACCH multiframes 
190   hoAveragingQual:
191     A_QUAL_HO: 8  SACCH multiframes 
192     W_QUAL_HO: 2  SACCH multiframes 
193   hoLowerThresholdLevDL: (10 - 110) dBm
194   hoLowerThresholdLevUL: (5 - 110) dBm
195   hoLowerThresholdQualDL: 06h =   6.4% < BER < 12.8%
196   hoLowerThresholdQualUL: 06h =   6.4% < BER < 12.8%
197   hoThresholdLevDLintra : (20 - 110) dBm
198   hoThresholdLevULintra: (20 - 110) dBm
199   hoThresholdMsRangeMax: 20 km 
200   nCell: 06h
201   timerHORequest: 3  ,unit 2 SACCH multiframes 
202 */
203
204 unsigned char msg_3[] = 
205 {
206         0xD0, 0xA1, 0x00, 0xFF, 0xFF, 
207                 0xD0, 0x00,
208                 0x64, 0x00,
209                 0x67, 0x00,
210                 0x68, 0x00,
211                 0x6A, 0x00,
212                 0x6C, 0x00,
213                 0x6D, 0x00,
214                 0x6F, 0x08,
215                 0x70, 0x08, 0x01,
216                 0x71, 0x10, 0x10, 0x10,
217                 0x72, 0x08, 0x02,
218                 0x73, 0x0A,
219                 0x74, 0x05,
220                 0x75, 0x06,
221                 0x76, 0x06,
222                 0x78, 0x14,
223                 0x79, 0x14,
224                 0x7A, 0x14,
225                 0x7D, 0x06,
226                 0x92, 0x03, 0x20, 0x01, 0x00,
227                 0x45, 0x01, 0x00,
228                 0x48, 0x01, 0x00,
229                 0x5A, 0x01, 0x00,
230                 0x5B, 0x01, 0x05,
231                 0x5E, 0x01, 0x1A,
232                 0x5F, 0x01, 0x20,
233                 0x9D, 0x01, 0x00,
234                 0x47, 0x01, 0x00,
235                 0x5C, 0x01, 0x64,
236                 0x5D, 0x01, 0x1E,
237                 0x97, 0x01, 0x20,
238                 0xF7, 0x01, 0x3C,
239 };
240
241 // Power Control, SET ATTRIBUTES
242
243 /*
244   Object Class: Power Control
245   BTS relat. Number: 0 
246   Instance 2: FF
247   Instance 3: FF
248 SET ATTRIBUTES
249   enableMsPowerControl: 00h =  Disabled
250   enablePowerControlRLFW: 00h =  Disabled
251   pcAveragingLev:
252     A_LEV_PC: 4  SACCH multiframes 
253     W_LEV_PC: 1  SACCH multiframes 
254   pcAveragingQual:
255     A_QUAL_PC: 4  SACCH multiframes 
256     W_QUAL_PC: 2  SACCH multiframes 
257   pcLowerThresholdLevDL: 0Fh
258   pcLowerThresholdLevUL: 0Ah
259   pcLowerThresholdQualDL: 05h =   3.2% < BER <  6.4%
260   pcLowerThresholdQualUL: 05h =   3.2% < BER <  6.4%
261   pcRLFThreshold: 0Ch
262   pcUpperThresholdLevDL: 14h
263   pcUpperThresholdLevUL: 0Fh
264   pcUpperThresholdQualDL: 04h =   1.6% < BER <  3.2%
265   pcUpperThresholdQualUL: 04h =   1.6% < BER <  3.2%
266   powerConfirm: 2  ,unit 2 SACCH multiframes 
267   powerControlInterval: 2  ,unit 2 SACCH multiframes 
268   powerIncrStepSize: 02h = 4 dB
269   powerRedStepSize: 01h = 2 dB
270   radioLinkTimeoutBs: 64  SACCH multiframes 
271   enableBSPowerControl: 00h =  disabled
272 */
273
274 unsigned char msg_4[] = 
275 {
276         0xD0, 0xA2, 0x00, 0xFF, 0xFF, 
277                 NM_ATT_BS11_ENA_MS_PWR_CTRL, 0x00,
278                 NM_ATT_BS11_ENA_PWR_CTRL_RLFW, 0x00,
279                 0x7E, 0x04, 0x01,
280                 0x7F, 0x04, 0x02,
281                 0x80, 0x0F,
282                 0x81, 0x0A,
283                 0x82, 0x05,
284                 0x83, 0x05,
285                 0x84, 0x0C, 
286                 0x85, 0x14, 
287                 0x86, 0x0F, 
288                 0x87, 0x04,
289                 0x88, 0x04,
290                 0x89, 0x02,
291                 0x8A, 0x02,
292                 0x8B, 0x02,
293                 0x8C, 0x01,
294                 0x8D, 0x40,
295                 0x65, 0x01, 0x00 // set to 0x01 to enable BSPowerControl
296 };
297
298
299 // Transceiver, SET TRX ATTRIBUTES (TRX 0)
300
301 /*
302   Object Class: Transceiver
303   BTS relat. Number: 0 
304   Tranceiver number: 0 
305   Instance 3: FF
306 SET TRX ATTRIBUTES
307   aRFCNList (HEX):  0001
308   txPwrMaxReduction: 00h =   30dB
309   radioMeasGran: 254  SACCH multiframes 
310   radioMeasRep: 01h =  enabled
311   memberOfEmergencyConfig: 01h =  TRUE
312   trxArea: 00h = TRX doesn't belong to a concentric cell
313 */
314
315 unsigned char msg_6[] = 
316 {
317         0x44, 0x02, 0x00, 0x00, 0xFF, 
318                 NM_ATT_ARFCN_LIST, 0x01, 0x00, HARDCODED_ARFCN /*0x01*/,
319                 NM_ATT_RF_MAXPOWR_R, 0x00,
320                 NM_ATT_BS11_RADIO_MEAS_GRAN, 0x01, 0xFE, 
321                 NM_ATT_BS11_RADIO_MEAS_REP, 0x01, 0x01,
322                 NM_ATT_BS11_EMRG_CFG_MEMBER, 0x01, 0x01,
323                 NM_ATT_BS11_TRX_AREA, 0x01, 0x00, 
324 };
325
326 static unsigned char nanobts_attr_bts[] = {
327         NM_ATT_INTERF_BOUND, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73,
328         NM_ATT_INTAVE_PARAM, 0x06,
329         NM_ATT_CONN_FAIL_CRIT, 0x00, 0x02, 0x01, 0x10, 
330         NM_ATT_T200, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21, 0xa8,
331         NM_ATT_MAX_TA, 0x3f,
332         NM_ATT_OVERL_PERIOD, 0x00, 0x01, 10, /* seconds */
333         NM_ATT_CCCH_L_T, 10, /* percent */
334         NM_ATT_CCCH_L_I_P, 1, /* seconds */
335         NM_ATT_RACH_B_THRESH, 0x0a,
336         NM_ATT_LDAVG_SLOTS, 0x03, 0xe8,
337         NM_ATT_BTS_AIR_TIMER, 0x80,
338         NM_ATT_NY1, 0x0a,
339         NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
340         NM_ATT_BSIC, 0x20,
341 };
342
343 static unsigned char nanobts_attr_radio[] = {
344         NM_ATT_RF_MAXPOWR_R, 0x0c,
345         NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
346 };
347
348 static unsigned char nanobts_attr_e0[] = {
349         0x85, 0x00,
350         0x81, 0x0b, 0xbb,       /* TCP PORT for RSL */
351 };
352
353 int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
354                    struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
355 {
356         struct gsm_bts *bts;
357         struct gsm_bts_trx *trx;
358         struct gsm_bts_trx_ts *ts;
359
360         /* This is currently only required on nanoBTS */
361
362         switch (evt) {
363         case EVT_STATECHG_OPER:
364                 switch (obj_class) {
365                 case NM_OC_SITE_MANAGER:
366                         bts = container_of(obj, struct gsm_bts, site_mgr);
367                         if (old_state->operational != 2 && new_state->operational == 2) {
368                                 abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
369                         }
370                         break;
371                 case NM_OC_BTS:
372                         bts = (struct gsm_bts *)obj;
373                         if (new_state->availability == 5) {
374                                 abis_nm_set_bts_attr(bts, nanobts_attr_bts,
375                                                         sizeof(nanobts_attr_bts));
376                                 abis_nm_opstart(bts, NM_OC_BTS,
377                                                 bts->nr, 0xff, 0xff);
378                                 abis_nm_chg_adm_state(bts, NM_OC_BTS,
379                                                       bts->nr, 0xff, 0xff,
380                                                       NM_STATE_UNLOCKED);
381                         }
382                         break;
383                 case NM_OC_RADIO_CARRIER:
384                         trx = (struct gsm_bts_trx *)obj;
385                         if (new_state->availability == 3) {
386                                 abis_nm_set_radio_attr(trx, nanobts_attr_radio,
387                                                         sizeof(nanobts_attr_radio));
388                                 abis_nm_opstart(trx->bts, NM_OC_RADIO_CARRIER,
389                                                 trx->bts->nr, trx->nr, 0xff);
390                                 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
391                                                       trx->bts->nr, trx->nr, 0xff,
392                                                       NM_STATE_UNLOCKED);
393                         }
394                         break;
395                 case NM_OC_CHANNEL:
396                         ts = (struct gsm_bts_trx_ts *)obj;
397                         trx = (struct gsm_bts_trx *)ts->trx;
398                         if (new_state->availability == 5) {
399                                 if (ts->nr == 0 && trx == trx->bts->c0)
400                                         abis_nm_set_channel_attr(ts, NM_CHANC_BCCH_CBCH);
401                                 else
402                                         abis_nm_set_channel_attr(ts, NM_CHANC_TCHFull);
403                                 abis_nm_opstart(trx->bts, NM_OC_CHANNEL,
404                                                 trx->bts->nr, trx->nr, ts->nr);
405                                 abis_nm_chg_adm_state(trx->bts, NM_OC_CHANNEL,
406                                                       trx->bts->nr, trx->nr, ts->nr,
407                                                       NM_STATE_UNLOCKED);
408                         }
409                         break;
410                 case NM_OC_BASEB_TRANSC:
411                         trx = container_of(obj, struct gsm_bts_trx, bb_transc);
412                         if (new_state->availability == 5) {
413                                 abis_nm_ipaccess_msg(trx->bts, 0xe0, NM_OC_BASEB_TRANSC,
414                                                      trx->bts->nr, trx->nr, 0xff,
415                                                      nanobts_attr_e0, sizeof(nanobts_attr_e0));
416                                 abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC, 
417                                                 trx->bts->nr, trx->nr, 0xff);
418                                 abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC, 
419                                                         trx->bts->nr, trx->nr, 0xff,
420                                                         NM_STATE_UNLOCKED);
421                         }
422                         break;
423                 }
424                 break;
425         case EVT_STATECHG_ADM:
426                 DEBUGP(DMM, "Unhandled state change in %s:%d\n", __func__, __LINE__);
427                 break;
428         }
429         return 0;
430 }
431
432 static void bootstrap_om_nanobts(struct gsm_bts *bts)
433 {
434         /* We don't do callback based bootstrapping, but event driven (see above) */
435 }
436
437 static void bootstrap_om_bs11(struct gsm_bts *bts)
438 {
439         struct gsm_bts_trx *trx = &bts->trx[0];
440
441         /* stop sending event reports */
442         abis_nm_event_reports(bts, 0);
443
444         /* begin DB transmission */
445         abis_nm_bs11_db_transmission(bts, 1);
446
447         /* end DB transmission */
448         abis_nm_bs11_db_transmission(bts, 0);
449
450         /* Reset BTS Site manager resource */
451         abis_nm_bs11_reset_resource(bts);
452
453         /* begin DB transmission */
454         abis_nm_bs11_db_transmission(bts, 1);
455
456         abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/
457         abis_nm_raw_msg(bts, sizeof(msg_2), msg_2); /* set BTS attr */
458         abis_nm_raw_msg(bts, sizeof(msg_3), msg_3); /* set BTS handover attr */
459         abis_nm_raw_msg(bts, sizeof(msg_4), msg_4); /* set BTS power control attr */
460
461         /* Connect signalling of bts0/trx0 to e1_0/ts1/64kbps */
462         abis_nm_conn_terr_sign(trx, 0, 1, 0xff);
463         abis_nm_raw_msg(bts, sizeof(msg_6), msg_6); /* SET TRX ATTRIBUTES */
464
465         /* Use TEI 1 for signalling */
466         abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x01);
467         abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_SDCCH_CBCH);
468
469 #ifdef HAVE_TRX1
470         /* TRX 1 */
471         abis_nm_conn_terr_sign(&bts->trx[1], 0, 1, 0xff);
472         /* FIXME: TRX ATTRIBUTE */
473         abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x02);
474 #endif
475
476         /* SET CHANNEL ATTRIBUTE TS1 */
477         abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull);
478         /* Connect traffic of bts0/trx0/ts1 to e1_0/ts2/b */
479         abis_nm_conn_terr_traf(&trx->ts[1], 0, 2, 1);
480         
481         /* SET CHANNEL ATTRIBUTE TS2 */
482         abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull);
483         /* Connect traffic of bts0/trx0/ts2 to e1_0/ts2/c */
484         abis_nm_conn_terr_traf(&trx->ts[2], 0, 2, 2);
485
486         /* SET CHANNEL ATTRIBUTE TS3 */
487         abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull);
488         /* Connect traffic of bts0/trx0/ts3 to e1_0/ts2/d */
489         abis_nm_conn_terr_traf(&trx->ts[3], 0, 2, 3);
490
491         /* SET CHANNEL ATTRIBUTE TS4 */
492         abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull);
493         /* Connect traffic of bts0/trx0/ts4 to e1_0/ts3/a */
494         abis_nm_conn_terr_traf(&trx->ts[4], 0, 3, 0);
495
496         /* SET CHANNEL ATTRIBUTE TS5 */
497         abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull);
498         /* Connect traffic of bts0/trx0/ts5 to e1_0/ts3/b */
499         abis_nm_conn_terr_traf(&trx->ts[5], 0, 3, 1);
500
501         /* SET CHANNEL ATTRIBUTE TS6 */
502         abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull);
503         /* Connect traffic of bts0/trx0/ts6 to e1_0/ts3/c */
504         abis_nm_conn_terr_traf(&trx->ts[6], 0, 3, 2);
505
506         /* SET CHANNEL ATTRIBUTE TS7 */
507         abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull);
508         /* Connect traffic of bts0/trx0/ts7 to e1_0/ts3/d */
509         abis_nm_conn_terr_traf(&trx->ts[7], 0, 3, 3);
510
511         /* end DB transmission */
512         abis_nm_bs11_db_transmission(bts, 0);
513
514         /* Reset BTS Site manager resource */
515         abis_nm_bs11_reset_resource(bts);
516
517         /* restart sending event reports */
518         abis_nm_event_reports(bts, 1);
519 }
520
521 static void bootstrap_om(struct gsm_bts *bts)
522 {
523         fprintf(stdout, "bootstrapping OML\n");
524
525         switch (bts->type) {
526         case GSM_BTS_TYPE_BS11:
527                 bootstrap_om_bs11(bts);
528                 break;
529         case GSM_BTS_TYPE_NANOBTS_900:
530         case GSM_BTS_TYPE_NANOBTS_1800:
531                 bootstrap_om_nanobts(bts);
532                 break;
533         default:
534                 fprintf(stderr, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type);
535         }
536 }
537
538 static int shutdown_om(struct gsm_bts *bts)
539 {
540         /* stop sending event reports */
541         abis_nm_event_reports(bts, 0);
542
543         /* begin DB transmission */
544         abis_nm_bs11_db_transmission(bts, 1);
545
546         /* end DB transmission */
547         abis_nm_bs11_db_transmission(bts, 0);
548
549         /* Reset BTS Site manager resource */
550         abis_nm_bs11_reset_resource(bts);
551
552         return 0;
553 }
554
555 struct bcch_info {
556         u_int8_t type;
557         u_int8_t len;
558         const u_int8_t *data;
559 };
560
561 /*
562 SYSTEM INFORMATION TYPE 1
563   Cell channel description
564     Format-ID bit map 0
565     CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
566   RACH Control Parameters
567     maximum 7 retransmissions
568     8 slots used to spread transmission
569     cell not barred for access
570     call reestablishment not allowed
571     Access Control Class = 0000
572 */
573 static u_int8_t si1[] = {
574         /* header */0x55, 0x06, 0x19,
575         /* ccdesc */0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/,
577         /* rach */0xD5, 0x00, 0x00,
578         /* s1 reset*/0x2B
579 };
580
581 static u_int8_t *gsm48_si1(u_int8_t *arfcn_list, int arfcn_len, int max_trans, int tx_integer, int cell_barr, int re, int ec, u_int8_t *ac_list, int ac_len)
582 {
583         static u_int8_t si[23];
584         int i, bit, octet;
585
586         memset(&si, 0, sizeof(si));
587
588         /* header */
589         si[0] = 0x55;
590         si[1] = 0x06;
591         si[2] = 0x19;
592         /* ccdesc */
593         for (i = 0; i < arfcn_len; i++) {
594                 if (arfcn_list[i] <= 124 && arfcn_list[i] > 0) {
595                         bit = (arfcn_list[i] - 1) & 7;
596                         octet = (arfcn_list[i] -1) / 8;
597                         si[18 - octet] |= (1 << bit);
598                 }
599         }
600         /* rach */
601         si[19] = (max_trans << 6);
602         si[19] |= (tx_integer << 2);
603         si[19] |= (cell_barr << 1);
604         si[19] |= re;
605         si[20] = (ec << 2);
606         for (i = 0; i < ac_len; i++) {
607                 if (ac_list[i] <= 15 && ac_list[i] != 10) {
608                         bit = ac_list[i] & 7;
609                         octet = ac_list[i] / 8;
610                         si[21 - octet] |= (1 << bit);
611                 }
612         }
613         /* s1 rest */
614         si[22] = 0x2B;
615
616         /* testig */
617         if (memcmp(&si1, &si, sizeof(si)))
618                 printf("SI1 does not match default template.\n");
619
620         return si;
621 }
622
623 /*
624  SYSTEM INFORMATION TYPE 2
625   Neighbour Cells Description
626     EXT-IND: Carries the complete BA
627     BA-IND = 0
628     Format-ID bit map 0
629     CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
630   NCC permitted (NCC) = FF
631   RACH Control Parameters
632     maximum 7 retransmissions
633     8 slots used to spread transmission
634     cell not barred for access
635     call reestablishment not allowed
636     Access Control Class = 0000
637 */
638 static u_int8_t si2[] = {
639         /* header */0x59, 0x06, 0x1A,
640         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642         /* ncc */0xFF,
643         /* rach*/0xD5, 0x00, 0x00
644 };
645
646 static u_int8_t *gsm48_si2(int ba, u_int8_t *arfcn_list, int arfcn_len, u_int8_t ncc, int max_trans, int tx_integer, int cell_barr, int re, int ec, u_int8_t *ac_list, int ac_len)
647 {
648         static u_int8_t si[23];
649         int i, bit, octet;
650
651         memset(&si, 0, sizeof(si));
652
653         /* header */
654         si[0] = 0x59;
655         si[1] = 0x06;
656         si[2] = 0x1A;
657         /* ncdesc */
658         si[3] = (ba << 4);
659         for (i = 0; i < arfcn_len; i++) {
660                 if (arfcn_list[i] <= 124 && arfcn_list[i] > 0) {
661                         bit = (arfcn_list[i] - 1) & 7;
662                         octet = (arfcn_list[i] -1) / 8;
663                         si[18 - octet] |= (1 << bit);
664                 }
665         }
666         /* ncc */
667         si[19] = ncc;
668         /* rach */
669         si[20] = (max_trans << 6);
670         si[20] |= (tx_integer << 2);
671         si[20] |= (cell_barr << 1);
672         si[20] |= re;
673         si[21] = (ec << 2);
674         for (i = 0; i < ac_len; i++) {
675                 if (ac_list[i] <= 15 && ac_list[i] != 10) {
676                         bit = ac_list[i] & 7;
677                         octet = ac_list[i] / 8;
678                         si[22 - octet] |= (1 << bit);
679                 }
680         }
681
682         /* testig */
683         if (memcmp(&si2, &si, sizeof(si)))
684                 printf("SI2 does not match default template.\n");
685
686         return si;
687 }
688
689 /*
690 SYSTEM INFORMATION TYPE 3
691   Cell identity = 00001 (1h)
692   Location area identification
693     Mobile Country Code (MCC): 001
694     Mobile Network Code (MNC): 01
695     Location Area Code  (LAC): 00001 (1h)
696   Control Channel Description
697     Attach-detach: MSs in the cell are not allowed to apply IMSI attach /detach
698     0 blocks reserved for access grant
699     1 channel used for CCCH, with SDCCH
700     5 multiframes period for PAGING REQUEST
701     Time-out T3212 = 0
702   Cell Options BCCH
703     Power control indicator: not set
704     MSs shall not use uplink DTX
705     Radio link timeout = 36
706   Cell Selection Parameters
707     Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection
708     max.TX power level MS may use for CCH = 2 <- according to GSM05.05 39dBm (max)
709     Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters
710     Half rate support (NECI): New establishment causes are not supported
711     min.RX signal level for MS = 0
712   RACH Control Parameters
713     maximum 7 retransmissions
714     8 slots used to spread transmission
715     cell not barred for access
716     call reestablishment not allowed
717     Access Control Class = 0000
718   SI 3 Rest Octets
719     Cell Bar Qualify (CBQ): 0
720     Cell Reselect Offset = 0 dB
721     Temporary Offset = 0 dB
722     Penalty Time = 20 s
723     System Information 2ter Indicator (2TI): 0 = not available
724     Early Classmark Sending Control (ECSC):  0 = forbidden
725     Scheduling Information is not sent in SYSTEM INFORMATION TYPE 9 on the BCCH
726 */
727 static u_int8_t si3[] = {
728         /* header */0x49, 0x06, 0x1B,
729         /* cell */0x00, 0x01,
730         /* lai  */0x00, 0xF1, 0x10, 0x00, 0x01,
731         /* desc */0x01, 0x03, 0x00,
732         /* option*/0x28,
733         /* selection*/0x62, 0x00,
734         /* rach */0xD5, 0x00, 0x00,
735         /* reset*/0x80, 0x00, 0x00, 0x2B
736 };
737
738 /*
739 SYSTEM INFORMATION TYPE 4
740   Location area identification
741     Mobile Country Code (MCC): 001
742     Mobile Network Code (MNC): 01
743     Location Area Code  (LAC): 00001 (1h)
744   Cell Selection Parameters
745     Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection
746     max.TX power level MS may use for CCH = 2
747     Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters
748     Half rate support (NECI): New establishment causes are not supported
749     min.RX signal level for MS = 0
750   RACH Control Parameters
751     maximum 7 retransmissions
752     8 slots used to spread transmission
753     cell not barred for access
754     call reestablishment not allowed
755     Access Control Class = 0000
756   Channel Description
757     Type = SDCCH/4[2]
758     Timeslot Number: 0
759     Training Sequence Code: 7h
760     ARFCN: 1
761   SI Rest Octets
762     Cell Bar Qualify (CBQ): 0
763     Cell Reselect Offset = 0 dB
764     Temporary Offset = 0 dB
765     Penalty Time = 20 s
766 */
767 static u_int8_t si4[] = {
768         /* header */0x41, 0x06, 0x1C,
769         /* lai */0x00, 0xF1, 0x10, 0x00, 0x01,
770         /* sel */0x62, 0x00,
771         /* rach*/0xD5, 0x00, 0x00,
772         /* var */0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/, 0x80, 0x00, 0x00,
773         0x2B, 0x2B, 0x2B
774 };
775
776 /*
777  SYSTEM INFORMATION TYPE 5
778   Neighbour Cells Description
779     EXT-IND: Carries the complete BA
780     BA-IND = 0
781     Format-ID bit map 0
782     CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
783 */
784
785 static u_int8_t si5[] = {
786         /* header without l2 len*/0x06, 0x1D,
787         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
789 };
790
791 static u_int8_t *gsm48_si5(int ba, u_int8_t *arfcn_list, int arfcn_len)
792 {
793         static u_int8_t si[18];
794         int i, bit, octet;
795
796         memset(&si, 0, sizeof(si));
797
798         /* header */
799         si[0] = 0x06;
800         si[1] = 0x1D;
801         /* ncdesc */
802         si[2] = (ba << 4);
803         for (i = 0; i < arfcn_len; i++) {
804                 if (arfcn_list[i] <= 124 && arfcn_list[i] > 0) {
805                         bit = (arfcn_list[i] - 1) & 7;
806                         octet = (arfcn_list[i] -1) / 8;
807                         si[17 - octet] |= (1 << bit);
808                 }
809         }
810
811         /* testig */
812         if (memcmp(&si3, &si, sizeof(si)))
813                 printf("SI3 does not match default template.\n");
814
815         return si;
816 }
817
818 // SYSTEM INFORMATION TYPE 6
819
820 /*
821 SACCH FILLING
822   System Info Type: SYSTEM INFORMATION 6
823   L3 Information (Hex): 06 1E 00 01 xx xx 10 00 01 28 FF
824
825 SYSTEM INFORMATION TYPE 6
826   Cell identity = 00001 (1h)
827   Location area identification
828     Mobile Country Code (MCC): 001
829     Mobile Network Code (MNC): 01
830     Location Area Code  (LAC): 00001 (1h)
831   Cell Options SACCH
832     Power control indicator: not set
833     MSs shall not use uplink DTX on a TCH-F. MS shall not use uplink DTX on TCH-H.
834     Radio link timeout = 36
835   NCC permitted (NCC) = FF
836 */
837
838 static u_int8_t si6[] = {
839         /* header */0x06, 0x1E,
840         /* cell id*/ 0x00, 0x01,
841         /* lai */ 0x00, 0xF1, 0x10, 0x00, 0x01,
842         /* options */ 0x28,
843         /* ncc */ 0xFF,
844 };
845
846
847
848 static const struct bcch_info bcch_infos[] = {
849         {
850                 RSL_SYSTEM_INFO_1,
851                 sizeof(si1),
852                 si1,
853         }, {
854                 RSL_SYSTEM_INFO_2,
855                 sizeof(si2),
856                 si2,
857         }, {
858                 RSL_SYSTEM_INFO_3,
859                 sizeof(si3),
860                 si3,
861         }, {
862                 RSL_SYSTEM_INFO_4,
863                 sizeof(si4),
864                 si4,
865         },
866 };
867
868 static_assert(sizeof(si1) == sizeof(struct gsm48_system_information_type_1), type1)
869 static_assert(sizeof(si2) == sizeof(struct gsm48_system_information_type_2), type2)
870 static_assert(sizeof(si3) == sizeof(struct gsm48_system_information_type_3), type3)
871 static_assert(sizeof(si4) >= sizeof(struct gsm48_system_information_type_4), type4)
872 static_assert(sizeof(si5) == sizeof(struct gsm48_system_information_type_5), type5)
873 static_assert(sizeof(si6) >= sizeof(struct gsm48_system_information_type_6), type6)
874
875 /* set all system information types */
876 static int set_system_infos(struct gsm_bts_trx *trx)
877 {
878         unsigned int i;
879         u_int8_t *_si1;
880         u_int8_t *_si2;
881         u_int8_t *_si5;
882         u_int8_t arfcn_list[8];
883
884         arfcn_list[0] = trx->arfcn;
885         _si1 = gsm48_si1(arfcn_list, 1, 3, 5, 0, 1, 0, NULL, 0);
886
887         memset(arfcn_list, 0, sizeof(arfcn_list));
888         arfcn_list[0] = trx->arfcn;
889         arfcn_list[1] = 112;
890         arfcn_list[2] = 62;
891         arfcn_list[3] = 99;
892         arfcn_list[4] = 77;
893         arfcn_list[5] = 64;
894         arfcn_list[6] = 54;
895         arfcn_list[7] = 51;
896         _si2 = gsm48_si2(0, arfcn_list, 8, 0xff, 3, 5, 0, 1, 0, NULL, 0);
897         _si5 = gsm48_si5(0, arfcn_list, 8);
898
899         rsl_bcch_info(trx, RSL_SYSTEM_INFO_1, _si1, 23);
900         rsl_bcch_info(trx, RSL_SYSTEM_INFO_2, _si2, 23);
901 //      rsl_bcch_info(trx, RSL_SYSTEM_INFO_3, _si3, );
902 //      rsl_bcch_info(trx, RSL_SYSTEM_INFO_4, _si4, );
903
904         for (i = 2; i < ARRAY_SIZE(bcch_infos); i++) {
905                 rsl_bcch_info(trx, bcch_infos[i].type,
906                               bcch_infos[i].data,
907                               bcch_infos[i].len);
908         }
909         rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, _si5, 18);
910         rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6));
911
912         return 0;
913 }
914
915 /*
916  * Patch the various SYSTEM INFORMATION tables to update
917  * the LAI
918  */
919 static void patch_tables(struct gsm_bts *bts)
920 {
921 #warning todo
922         u_int8_t arfcn_low = bts->trx[0].arfcn & 0xff;
923         u_int8_t arfcn_high = (bts->trx[0].arfcn >> 8) & 0x0f;
924         /* covert the raw packet to the struct */
925         struct gsm48_system_information_type_3 *type_3 =
926                 (struct gsm48_system_information_type_3*)&si3;
927         struct gsm48_system_information_type_4 *type_4 =
928                 (struct gsm48_system_information_type_4*)&si4;
929         struct gsm48_system_information_type_6 *type_6 =
930                 (struct gsm48_system_information_type_6*)&si6;
931         struct gsm48_loc_area_id lai;
932
933         gsm0408_generate_lai(&lai, bts->network->country_code,
934                                 bts->network->network_code, bts->location_area_code);
935
936         /* assign the MCC and MNC */
937         type_3->lai = lai;
938         type_4->lai = lai;
939         type_6->lai = lai;
940
941         /* patch ARFCN into BTS Attributes */
942         msg_2[74] &= 0xf0;
943         msg_2[74] |= arfcn_high;
944         msg_2[75] = arfcn_low;
945         nanobts_attr_bts[42] &= 0xf0;
946         nanobts_attr_bts[42] |= arfcn_high;
947         nanobts_attr_bts[43] = arfcn_low;
948
949         /* patch ARFCN into TRX Attributes */
950         msg_6[7] &= 0xf0;
951         msg_6[7] |= arfcn_high;
952         msg_6[8] = arfcn_low;
953         nanobts_attr_radio[5] &= 0xf0;
954         nanobts_attr_radio[5] |= arfcn_high;
955         nanobts_attr_radio[6] = arfcn_low;
956
957         type_4->data[2] &= 0xf0;
958         type_4->data[2] |= arfcn_high;
959         type_4->data[3] = arfcn_low;
960
961         /* patch Control Channel Description 10.5.2.11 */
962         type_3->control_channel_desc = bts->chan_desc;
963 }
964
965
966 static void bootstrap_rsl(struct gsm_bts_trx *trx)
967 {
968         fprintf(stdout, "bootstrapping RSL MCC=%u MNC=%u\n", trx->bts->network->country_code, trx->bts->network->network_code);
969         set_system_infos(trx);
970 }
971
972 void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
973 {
974         switch (event) {
975         case EVT_E1_TEI_UP:
976                 switch (type) {
977                 case E1INP_SIGN_OML:
978                         bootstrap_om(trx->bts);
979                         break;
980                 case E1INP_SIGN_RSL:
981                         bootstrap_rsl(trx);
982                         break;
983                 default:
984                         break;
985                 }
986                 break;
987         case EVT_E1_TEI_DN:
988                 fprintf(stderr, "Lost some E1 TEI link\n");
989                 /* FIXME: deal with TEI or L1 link loss */
990                 break;
991         default:
992                 break;
993         }
994 }
995
996 static int bootstrap_bts(struct gsm_bts *bts, int lac, int arfcn)
997 {
998         bts->location_area_code = lac;
999         bts->trx[0].arfcn = arfcn;
1000
1001         /* Control Channel Description */
1002         memset(&bts->chan_desc, 0, sizeof(struct gsm48_control_channel_descr));
1003         bts->chan_desc.att = 1;
1004         bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
1005         bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
1006         bts->chan_desc.t3212 = 0;
1007
1008         patch_tables(bts);
1009
1010         paging_init(bts);
1011
1012         if (bts->type == GSM_BTS_TYPE_BS11) {
1013                 struct gsm_bts_trx *trx = &bts->trx[0];
1014                 set_ts_e1link(&trx->ts[0], 0, 1, 0xff);
1015                 set_ts_e1link(&trx->ts[1], 0, 2, 1);
1016                 set_ts_e1link(&trx->ts[2], 0, 2, 2);
1017                 set_ts_e1link(&trx->ts[3], 0, 2, 3);
1018                 set_ts_e1link(&trx->ts[4], 0, 3, 0);
1019                 set_ts_e1link(&trx->ts[5], 0, 3, 1);
1020                 set_ts_e1link(&trx->ts[6], 0, 3, 2);
1021                 set_ts_e1link(&trx->ts[7], 0, 3, 3);
1022 #ifdef HAVE_TRX1
1023                 /* TRX 1 */
1024                 trx = &bts->trx[1];
1025                 set_ts_e1link(&trx->ts[0], 0, 1, 0xff);
1026                 set_ts_e1link(&trx->ts[1], 0, 2, 1);
1027                 set_ts_e1link(&trx->ts[2], 0, 2, 2);
1028                 set_ts_e1link(&trx->ts[3], 0, 2, 3);
1029                 set_ts_e1link(&trx->ts[4], 0, 3, 0);
1030                 set_ts_e1link(&trx->ts[5], 0, 3, 1);
1031                 set_ts_e1link(&trx->ts[6], 0, 3, 2);
1032                 set_ts_e1link(&trx->ts[7], 0, 3, 3);
1033 #endif
1034         }
1035
1036         return 0;
1037 }
1038
1039
1040 struct gsm_network *bootstrap_network(int (*mncc_recv)(struct gsm_network *, int, void *), int bts_type, int mcc, int mnc, int lac, int arfcn, int cardnr, int release_l2, char *name_short, char *name_long, char *hlr, int allow_all)
1041 {
1042         struct gsm_bts *bts;
1043         struct gsm_network *gsmnet;
1044
1045         /* seed the PRNG for TMSI */
1046         srand(time(NULL));
1047
1048         /* initialize our data structures */
1049         gsmnet = gsm_network_init(2, (gsm_bts_type)bts_type, mcc, mnc, mncc_recv);
1050         if (!gsmnet)
1051                 return 0;
1052
1053         /* open database */
1054         if (db_init(hlr, gsmnet)) {
1055                 fprintf(stderr, "DB: Failed to init HLR database '%s'. Please check the option settings.\n", hlr);
1056                 return NULL;
1057         }        
1058         if (db_prepare()) {
1059                 fprintf(stderr, "DB: Failed to prepare database.\n");
1060                 return NULL;
1061         }
1062
1063         gsmnet->name_long = name_long;
1064         gsmnet->name_short = name_short;
1065         bts = &gsmnet->bts[0];
1066         bootstrap_bts(bts, lac, arfcn);
1067
1068         /* Control Channel Description */
1069         memset(&bts->chan_desc, 0, sizeof(struct gsm48_control_channel_descr));
1070         bts->chan_desc.att = 1;
1071         bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
1072         bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
1073         bts->chan_desc.t3212 = 0;
1074
1075         patch_tables(bts);
1076
1077         paging_init(bts);
1078
1079         telnet_init(gsmnet, 4242);
1080
1081         /* E1 mISDN input setup */
1082         if (bts_type == GSM_BTS_TYPE_BS11) {
1083                 gsmnet->num_bts = 1;
1084                 if (e1_config(bts, cardnr, release_l2))
1085                         return NULL;
1086         } else {
1087                 bts->ip_access.site_id = 1801;
1088                 bts->ip_access.bts_id = 0;
1089                 bts = &gsmnet->bts[1];
1090                 bootstrap_bts(bts, lac, arfcn);
1091                 bts->ip_access.site_id = 1800;
1092                 bts->ip_access.bts_id = 0;
1093                 if (ipaccess_setup(gsmnet))
1094                         return NULL;
1095
1096         }
1097
1098         if (allow_all)
1099                 gsm0408_allow_everyone(1);
1100
1101         return gsmnet;
1102 }
1103
1104 int shutdown_net(struct gsm_network *network)
1105 {
1106         struct gsm_network *net = (struct gsm_network *)network;
1107         unsigned int i;
1108         for (i = 0; i < net->num_bts; i++) {
1109                 int rc;
1110                 rc = shutdown_om(&net->bts[i]);
1111                 if (rc < 0)
1112                         return rc;
1113         }
1114
1115         return 0;
1116 }
1117
1118 #ifdef __cplusplus
1119 }
1120 #endif