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