blob: fa049d6d6718364b41b260c90f96f0662efd3cf4 [file] [log] [blame]
Harald Welte59b04682009-06-10 05:40:52 +08001/* OpenBSC interface to quagga VTY */
2/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21#include <stdlib.h>
22#include <unistd.h>
23#include <sys/types.h>
24
25#include <vty/command.h>
26#include <vty/vty.h>
27
28#include <arpa/inet.h>
29
30#include <openbsc/linuxlist.h>
31#include <openbsc/gsm_data.h>
32#include <openbsc/gsm_subscriber.h>
33#include <openbsc/e1_input.h>
34#include <openbsc/abis_nm.h>
35#include <openbsc/db.h>
36
37static struct gsm_network *gsmnet;
38
39struct cmd_node bts_node = {
40 BTS_NODE,
41 "%s(bts)#",
42 1,
43};
44
45struct cmd_node trx_node = {
46 TRX_NODE,
47 "%s(trx)#",
48 1,
49};
50
51struct cmd_node ts_node = {
52 TS_NODE,
53 "%s(ts)#",
54 1,
55};
56
57struct cmd_node subscr_node = {
58 SUBSCR_NODE,
59 "%s(subscriber)#",
60 1,
61};
62
63static int dummy_config_write(struct vty *v)
64{
65 return CMD_SUCCESS;
66}
67
68static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms)
69{
70 vty_out(vty,"Oper '%s', Admin %u, Avail '%s'%s",
71 nm_opstate_name(nms->operational), nms->administrative,
72 nm_avail_name(nms->availability), VTY_NEWLINE);
73}
74
75static void net_dump_vty(struct vty *vty, struct gsm_network *net)
76{
77 vty_out(vty, "BSC is on Country Code %u, Network Code %u "
78 "and has %u BTS%s", net->country_code, net->network_code,
79 net->num_bts, VTY_NEWLINE);
80 vty_out(vty, " Long network name: '%s'%s",
81 net->name_long, VTY_NEWLINE);
82 vty_out(vty, " Short network name: '%s'%s",
83 net->name_short, VTY_NEWLINE);
84}
85
86DEFUN(show_net, show_net_cmd, "show network",
87 SHOW_STR "Display information about a GSM NETWORK\n")
88{
89 struct gsm_network *net = gsmnet;
90 net_dump_vty(vty, net);
91
92 return CMD_SUCCESS;
93}
94
95static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l)
96{
97 struct e1inp_line *line;
98
99 if (!e1l) {
100 vty_out(vty, " None%s", VTY_NEWLINE);
101 return;
102 }
103
104 line = e1l->ts->line;
105
106 vty_out(vty, " E1 Line %u, Type %s: Timeslot %u, Mode %s%s",
107 line->num, line->driver->name, e1l->ts->num,
108 e1inp_signtype_name(e1l->type), VTY_NEWLINE);
109 vty_out(vty, " E1 TEI %u, SAPI %u%s",
110 e1l->tei, e1l->sapi, VTY_NEWLINE);
111}
112
113static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
114{
Harald Welte91afe4c2009-06-20 18:15:19 +0200115 vty_out(vty, "BTS %u is of %s type in band %s, has LAC %u, "
116 "BSIC %u, TSC %u and %u TRX%s",
117 bts->nr, btstype2str(bts->type), gsm_band_name(bts->band),
118 bts->location_area_code, bts->bsic, bts->tsc,
119 bts->num_trx, VTY_NEWLINE);
Harald Welte59b04682009-06-10 05:40:52 +0800120 if (is_ipaccess_bts(bts))
121 vty_out(vty, " Unit ID: %u/%u/0%s",
122 bts->ip_access.site_id, bts->ip_access.bts_id,
123 VTY_NEWLINE);
124 vty_out(vty, " NM State: ");
125 net_dump_nmstate(vty, &bts->nm_state);
126 vty_out(vty, " Site Mgr NM State: ");
127 net_dump_nmstate(vty, &bts->site_mgr.nm_state);
128 vty_out(vty, " Paging: FIXME pending requests, %u free slots%s",
129 bts->paging.available_slots, VTY_NEWLINE);
130 vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE);
131 e1isl_dump_vty(vty, bts->oml_link);
132 /* FIXME: oml_link, chan_desc */
133}
134
135DEFUN(show_bts, show_bts_cmd, "show bts [number]",
136 SHOW_STR "Display information about a BTS\n"
137 "BTS number")
138{
139 struct gsm_network *net = gsmnet;
140 int bts_nr;
141
142 if (argc != 0) {
143 /* use the BTS number that the user has specified */
144 bts_nr = atoi(argv[0]);
145 if (bts_nr > net->num_bts) {
146 vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
147 VTY_NEWLINE);
148 return CMD_WARNING;
149 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200150 bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
Harald Welte59b04682009-06-10 05:40:52 +0800151 return CMD_SUCCESS;
152 }
153 /* print all BTS's */
154 for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++)
Harald Weltee712a5f2009-06-21 16:17:15 +0200155 bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
Harald Welte59b04682009-06-10 05:40:52 +0800156
157 return CMD_SUCCESS;
158}
159
Harald Welte97ceef92009-08-06 19:06:46 +0200160static void config_write_ts_single(struct vty *vty, struct gsm_bts_trx_ts *ts)
161{
162 vty_out(vty, "\t\tts %u%s", ts->nr, VTY_NEWLINE);
163 vty_out(vty, "\t\t\tphys_chan_config %s%s", gsm_pchan_name(ts->pchan),
164 VTY_NEWLINE);
165 vty_out(vty, "\t\t\te1_subslot %u %u %u%s", ts->e1_link.e1_nr,
166 ts->e1_link.e1_ts, ts->e1_link.e1_ts_ss, VTY_NEWLINE);
167}
168
169static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx)
170{
171 int i;
172
173 vty_out(vty, "\ttrx %u%s", trx->nr, VTY_NEWLINE);
174 vty_out(vty, "\t\tarfcn %u%s", trx->arfcn, VTY_NEWLINE);
175 vty_out(vty, "\t\tmax_power_red %u%s", trx->max_power_red, VTY_NEWLINE);
176
177 for (i = 0; i < TRX_NR_TS; i++)
178 config_write_ts_single(vty, &trx->ts[i]);
179}
180
181static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
182{
183 struct gsm_bts_trx *trx;
184
185 vty_out(vty, "bts %u%s", bts->nr, VTY_NEWLINE);
186 vty_out(vty, "\ttype %s%s", btstype2str(bts->type), VTY_NEWLINE);
187 vty_out(vty, "\tband %s%s", gsm_band_name(bts->band), VTY_NEWLINE);
188 vty_out(vty, "\tlocation_area_code %u%s", bts->location_area_code,
189 VTY_NEWLINE);
190 vty_out(vty, "\ttraining_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
191 vty_out(vty, "\tbase_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
Harald Welte3ffe1b32009-08-07 00:25:23 +0200192 if (is_ipaccess_bts(bts))
193 vty_out(vty, "\tunit_id %u %u%s",
194 bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
Harald Welte97ceef92009-08-06 19:06:46 +0200195
196 llist_for_each_entry(trx, &bts->trx_list, list)
197 config_write_trx_single(vty, trx);
198}
199
200static int config_write_bts(struct vty *v)
201{
202 struct gsm_bts *bts;
203
204 llist_for_each_entry(bts, &gsmnet->bts_list, list)
205 config_write_bts_single(v, bts);
206
207 return CMD_SUCCESS;
208}
209
210
Harald Welte59b04682009-06-10 05:40:52 +0800211static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
212{
213 vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
214 trx->nr, trx->bts->nr, trx->arfcn, VTY_NEWLINE);
Harald Welte91afe4c2009-06-20 18:15:19 +0200215 vty_out(vty, " RF Nominal Power: %d dBm, reduced by %u dB, "
216 "resulting BS power: %d dBm\n",
217 trx->nominal_power, trx->max_power_red,
218 trx->nominal_power - trx->max_power_red);
Harald Welte59b04682009-06-10 05:40:52 +0800219 vty_out(vty, " NM State: ");
220 net_dump_nmstate(vty, &trx->nm_state);
221 vty_out(vty, " Baseband Transceiver NM State: ");
222 net_dump_nmstate(vty, &trx->bb_transc.nm_state);
223 vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE);
224 e1isl_dump_vty(vty, trx->rsl_link);
225}
226
227DEFUN(show_trx,
228 show_trx_cmd,
229 "show trx [bts_nr] [trx_nr]",
230 SHOW_STR "Display information about a TRX\n")
231{
232 struct gsm_network *net = gsmnet;
233 struct gsm_bts *bts = NULL;
234 struct gsm_bts_trx *trx;
235 int bts_nr, trx_nr;
236
237 if (argc >= 1) {
238 /* use the BTS number that the user has specified */
239 bts_nr = atoi(argv[0]);
240 if (bts_nr >= net->num_bts) {
241 vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
242 VTY_NEWLINE);
243 return CMD_WARNING;
244 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200245 bts = gsm_bts_num(net, bts_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800246 }
247 if (argc >= 2) {
248 trx_nr = atoi(argv[1]);
249 if (trx_nr >= bts->num_trx) {
250 vty_out(vty, "%% can't find TRX '%s'%s", argv[1],
251 VTY_NEWLINE);
252 return CMD_WARNING;
253 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200254 trx = gsm_bts_trx_num(bts, trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800255 trx_dump_vty(vty, trx);
256 return CMD_SUCCESS;
257 }
258 if (bts) {
259 /* print all TRX in this BTS */
260 for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
Harald Weltee712a5f2009-06-21 16:17:15 +0200261 trx = gsm_bts_trx_num(bts, trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800262 trx_dump_vty(vty, trx);
263 }
264 return CMD_SUCCESS;
265 }
266
267 for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
Harald Weltee712a5f2009-06-21 16:17:15 +0200268 bts = gsm_bts_num(net, bts_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800269 for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
Harald Weltee712a5f2009-06-21 16:17:15 +0200270 trx = gsm_bts_trx_num(bts, trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800271 trx_dump_vty(vty, trx);
272 }
273 }
274
275 return CMD_SUCCESS;
276}
277
Harald Welte97ceef92009-08-06 19:06:46 +0200278
Harald Welte59b04682009-06-10 05:40:52 +0800279static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts)
280{
281 struct in_addr ia;
282
283 vty_out(vty, "Timeslot %u of TRX %u in BTS %u, phys cfg %s%s",
284 ts->nr, ts->trx->nr, ts->trx->bts->nr,
285 gsm_pchan_name(ts->pchan), VTY_NEWLINE);
286 vty_out(vty, " NM State: ");
287 net_dump_nmstate(vty, &ts->nm_state);
288 if (is_ipaccess_bts(ts->trx->bts)) {
289 ia.s_addr = ts->abis_ip.bound_ip;
Harald Welte8cdeaad2009-07-12 09:50:35 +0200290 vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s",
Harald Welte59b04682009-06-10 05:40:52 +0800291 inet_ntoa(ia), ts->abis_ip.bound_port,
Harald Welte8cdeaad2009-07-12 09:50:35 +0200292 ts->abis_ip.rtp_payload2, ts->abis_ip.conn_id,
Harald Welte59b04682009-06-10 05:40:52 +0800293 VTY_NEWLINE);
294 } else {
295 vty_out(vty, " E1 Line %u, Timeslot %u, Subslot %u%s",
296 ts->e1_link.e1_nr, ts->e1_link.e1_ts,
297 ts->e1_link.e1_ts_ss, VTY_NEWLINE);
298 }
299}
300
301DEFUN(show_ts,
302 show_ts_cmd,
303 "show timeslot [bts_nr] [trx_nr] [ts_nr]",
304 SHOW_STR "Display information about a TS\n")
305{
306 struct gsm_network *net = gsmnet;
307 struct gsm_bts *bts;
308 struct gsm_bts_trx *trx;
309 struct gsm_bts_trx_ts *ts;
310 int bts_nr, trx_nr, ts_nr;
311
312 if (argc >= 1) {
313 /* use the BTS number that the user has specified */
314 bts_nr = atoi(argv[0]);
315 if (bts_nr >= net->num_bts) {
316 vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
317 VTY_NEWLINE);
318 return CMD_WARNING;
319 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200320 bts = gsm_bts_num(net, bts_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800321 }
322 if (argc >= 2) {
323 trx_nr = atoi(argv[1]);
324 if (trx_nr >= bts->num_trx) {
325 vty_out(vty, "%% can't find TRX '%s'%s", argv[1],
326 VTY_NEWLINE);
327 return CMD_WARNING;
328 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200329 trx = gsm_bts_trx_num(bts, trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800330 }
331 if (argc >= 3) {
332 ts_nr = atoi(argv[2]);
333 if (ts_nr >= TRX_NR_TS) {
334 vty_out(vty, "%% can't find TS '%s'%s", argv[2],
335 VTY_NEWLINE);
336 return CMD_WARNING;
337 }
338 ts = &trx->ts[ts_nr];
339 ts_dump_vty(vty, ts);
340 return CMD_SUCCESS;
341 }
342 for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
Harald Weltee712a5f2009-06-21 16:17:15 +0200343 bts = gsm_bts_num(net, bts_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800344 for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
Harald Weltee712a5f2009-06-21 16:17:15 +0200345 trx = gsm_bts_trx_num(bts, trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800346 for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
347 ts = &trx->ts[ts_nr];
348 ts_dump_vty(vty, ts);
349 }
350 }
351 }
352
353 return CMD_SUCCESS;
354}
355
356static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
357{
Harald Welte91afe4c2009-06-20 18:15:19 +0200358 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
Harald Welte59b04682009-06-10 05:40:52 +0800359 subscr->authorized, VTY_NEWLINE);
360 if (subscr->name)
361 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
362 if (subscr->extension)
363 vty_out(vty, " Extension: %s%s", subscr->extension,
364 VTY_NEWLINE);
365 if (subscr->imsi)
366 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
367 if (subscr->tmsi)
368 vty_out(vty, " TMSI: %s%s", subscr->tmsi, VTY_NEWLINE);
369}
370
371static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
372{
373 vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s",
374 lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
375 lchan->ts->trx->bts->nr, gsm_lchan_name(lchan->type),
376 VTY_NEWLINE);
377 vty_out(vty, " Use Count: %u%s", lchan->use_count, VTY_NEWLINE);
378 vty_out(vty, " BS Power %u, MS Power %u%s", lchan->bs_power,
379 lchan->ms_power, VTY_NEWLINE);
380 if (lchan->subscr) {
381 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
382 subscr_dump_vty(vty, lchan->subscr);
383 } else
384 vty_out(vty, " No Subscriber%s", VTY_NEWLINE);
385}
386
Harald Welte03740842009-06-10 23:11:52 +0800387#if 0
388TODO: callref and remote callref of call must be resolved to get gsm_trans object
Harald Welte59b04682009-06-10 05:40:52 +0800389static void call_dump_vty(struct vty *vty, struct gsm_call *call)
390{
391 vty_out(vty, "Call Type %u, State %u, Transaction ID %u%s",
392 call->type, call->state, call->transaction_id, VTY_NEWLINE);
393
394 if (call->local_lchan) {
395 vty_out(vty, "Call Local Channel:%s", VTY_NEWLINE);
396 lchan_dump_vty(vty, call->local_lchan);
397 } else
398 vty_out(vty, "Call has no Local Channel%s", VTY_NEWLINE);
399
400 if (call->remote_lchan) {
401 vty_out(vty, "Call Remote Channel:%s", VTY_NEWLINE);
402 lchan_dump_vty(vty, call->remote_lchan);
403 } else
404 vty_out(vty, "Call has no Remote Channel%s", VTY_NEWLINE);
405
406 if (call->called_subscr) {
407 vty_out(vty, "Called Subscriber:%s", VTY_NEWLINE);
408 subscr_dump_vty(vty, call->called_subscr);
409 } else
410 vty_out(vty, "Call has no Called Subscriber%s", VTY_NEWLINE);
411}
Harald Welte03740842009-06-10 23:11:52 +0800412#endif
Harald Welte59b04682009-06-10 05:40:52 +0800413
414DEFUN(show_lchan,
415 show_lchan_cmd,
416 "show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
417 SHOW_STR "Display information about a logical channel\n")
418{
419 struct gsm_network *net = gsmnet;
420 struct gsm_bts *bts;
421 struct gsm_bts_trx *trx;
422 struct gsm_bts_trx_ts *ts;
423 struct gsm_lchan *lchan;
424 int bts_nr, trx_nr, ts_nr, lchan_nr;
425
426 if (argc >= 1) {
427 /* use the BTS number that the user has specified */
428 bts_nr = atoi(argv[0]);
429 if (bts_nr >= net->num_bts) {
430 vty_out(vty, "%% can't find BTS %s%s", argv[0],
431 VTY_NEWLINE);
432 return CMD_WARNING;
433 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200434 bts = gsm_bts_num(net, bts_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800435 }
436 if (argc >= 2) {
437 trx_nr = atoi(argv[1]);
438 if (trx_nr >= bts->num_trx) {
439 vty_out(vty, "%% can't find TRX %s%s", argv[1],
440 VTY_NEWLINE);
441 return CMD_WARNING;
442 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200443 trx = gsm_bts_trx_num(bts, trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800444 }
445 if (argc >= 3) {
446 ts_nr = atoi(argv[2]);
447 if (ts_nr >= TRX_NR_TS) {
448 vty_out(vty, "%% can't find TS %s%s", argv[2],
449 VTY_NEWLINE);
450 return CMD_WARNING;
451 }
452 ts = &trx->ts[ts_nr];
453 }
454 if (argc >= 4) {
455 lchan_nr = atoi(argv[3]);
456 if (lchan_nr >= TS_MAX_LCHAN) {
457 vty_out(vty, "%% can't find LCHAN %s%s", argv[3],
458 VTY_NEWLINE);
459 return CMD_WARNING;
460 }
461 lchan = &ts->lchan[lchan_nr];
462 lchan_dump_vty(vty, lchan);
463 return CMD_SUCCESS;
464 }
465 for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
Harald Weltee712a5f2009-06-21 16:17:15 +0200466 bts = gsm_bts_num(net, bts_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800467 for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
Harald Weltee712a5f2009-06-21 16:17:15 +0200468 trx = gsm_bts_trx_num(bts, trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800469 for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
470 ts = &trx->ts[ts_nr];
471 for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN;
472 lchan_nr++) {
473 lchan = &ts->lchan[lchan_nr];
474 if (lchan->type == GSM_LCHAN_NONE)
475 continue;
476 lchan_dump_vty(vty, lchan);
477 }
478 }
479 }
480 }
481
482 return CMD_SUCCESS;
483}
484
485static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
486{
487 vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
488}
489
490DEFUN(show_e1drv,
491 show_e1drv_cmd,
492 "show e1_driver",
493 SHOW_STR "Display information about available E1 drivers\n")
494{
495 struct e1inp_driver *drv;
496
497 llist_for_each_entry(drv, &e1inp_driver_list, list)
498 e1drv_dump_vty(vty, drv);
499
500 return CMD_SUCCESS;
501}
502
503static void e1line_dump_vty(struct vty *vty, struct e1inp_line *line)
504{
505 vty_out(vty, "E1 Line Number %u, Name %s, Driver %s%s",
506 line->num, line->name ? line->name : "",
507 line->driver->name, VTY_NEWLINE);
508}
509
510DEFUN(show_e1line,
511 show_e1line_cmd,
512 "show e1_line [line_nr]",
513 SHOW_STR "Display information about a E1 line\n")
514{
515 struct e1inp_line *line;
516
517 if (argc >= 1) {
518 int num = atoi(argv[0]);
519 llist_for_each_entry(line, &e1inp_line_list, list) {
520 if (line->num == num) {
521 e1line_dump_vty(vty, line);
522 return CMD_SUCCESS;
523 }
524 }
525 return CMD_WARNING;
526 }
527
528 llist_for_each_entry(line, &e1inp_line_list, list)
529 e1line_dump_vty(vty, line);
530
531 return CMD_SUCCESS;
532}
533
534static void e1ts_dump_vty(struct vty *vty, struct e1inp_ts *ts)
535{
536 vty_out(vty, "E1 Timeslot %2u of Line %u is Type %s%s",
537 ts->num, ts->line->num, e1inp_tstype_name(ts->type),
538 VTY_NEWLINE);
539}
540
541DEFUN(show_e1ts,
542 show_e1ts_cmd,
543 "show e1_timeslot [line_nr] [ts_nr]",
544 SHOW_STR "Display information about a E1 timeslot\n")
545{
546 struct e1inp_line *line;
547 struct e1inp_ts *ts;
548 int ts_nr;
549
550 if (argc == 0) {
551 llist_for_each_entry(line, &e1inp_line_list, list) {
552 for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
553 ts = &line->ts[ts_nr];
554 e1ts_dump_vty(vty, ts);
555 }
556 }
557 return CMD_SUCCESS;
558 }
559 if (argc >= 1) {
560 int num = atoi(argv[0]);
561 llist_for_each_entry(line, &e1inp_line_list, list) {
562 if (line->num == num)
563 break;
564 }
565 if (!line || line->num != num) {
566 vty_out(vty, "E1 line %s is invalid%s",
567 argv[0], VTY_NEWLINE);
568 return CMD_WARNING;
569 }
570 }
571 if (argc >= 2) {
572 ts_nr = atoi(argv[1]);
573 if (ts_nr > NUM_E1_TS) {
574 vty_out(vty, "E1 timeslot %s is invalid%s",
575 argv[1], VTY_NEWLINE);
576 return CMD_WARNING;
577 }
578 ts = &line->ts[ts_nr];
579 e1ts_dump_vty(vty, ts);
580 return CMD_SUCCESS;
581 } else {
582 for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
583 ts = &line->ts[ts_nr];
584 e1ts_dump_vty(vty, ts);
585 }
586 return CMD_SUCCESS;
587 }
588 return CMD_SUCCESS;
589}
590
591static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag)
592{
593 vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE);
594 subscr_dump_vty(vty, pag->subscr);
595}
596
597static void bts_paging_dump_vty(struct vty *vty, struct gsm_bts *bts)
598{
599 struct gsm_paging_request *pag;
600
601 llist_for_each_entry(pag, &bts->paging.pending_requests, entry)
602 paging_dump_vty(vty, pag);
603}
604
605DEFUN(show_paging,
606 show_paging_cmd,
607 "show paging [bts_nr]",
608 SHOW_STR "Display information about paging reuqests of a BTS\n")
609{
610 struct gsm_network *net = gsmnet;
611 struct gsm_bts *bts;
612 int bts_nr;
613
614 if (argc >= 1) {
615 /* use the BTS number that the user has specified */
616 bts_nr = atoi(argv[0]);
617 if (bts_nr >= net->num_bts) {
618 vty_out(vty, "%% can't find BTS %s%s", argv[0],
619 VTY_NEWLINE);
620 return CMD_WARNING;
621 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200622 bts = gsm_bts_num(net, bts_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800623 bts_paging_dump_vty(vty, bts);
624
625 return CMD_SUCCESS;
626 }
627 for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
Harald Weltee712a5f2009-06-21 16:17:15 +0200628 bts = gsm_bts_num(net, bts_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800629 bts_paging_dump_vty(vty, bts);
630 }
631
632 return CMD_SUCCESS;
633}
634
635/* per-subscriber configuration */
636DEFUN(cfg_subscr,
637 cfg_subscr_cmd,
638 "subscriber IMSI",
639 "Select a Subscriber to configure\n")
640{
641 const char *imsi = argv[0];
642 struct gsm_subscriber *subscr;
643
Harald Welteaae7a522009-07-23 19:21:02 +0200644 subscr = subscr_get_by_imsi(gsmnet, imsi);
Harald Welte59b04682009-06-10 05:40:52 +0800645 if (!subscr) {
646 vty_out(vty, "%% No subscriber for IMSI %s%s",
647 imsi, VTY_NEWLINE);
648 return CMD_WARNING;
649 }
650
651 vty->index = subscr;
652 vty->node = SUBSCR_NODE;
653
654 return CMD_SUCCESS;
655}
656
657
658/* per-BTS configuration */
659DEFUN(cfg_bts,
660 cfg_bts_cmd,
661 "bts BTS_NR",
662 "Select a BTS to configure\n")
663{
664 int bts_nr = atoi(argv[0]);
665 struct gsm_bts *bts;
666
Harald Weltee712a5f2009-06-21 16:17:15 +0200667 if (bts_nr > gsmnet->num_bts) {
668 vty_out(vty, "%% The next unused BTS number is %u%s",
669 gsmnet->num_bts, VTY_NEWLINE);
Harald Welte59b04682009-06-10 05:40:52 +0800670 return CMD_WARNING;
Harald Weltee712a5f2009-06-21 16:17:15 +0200671 } else if (bts_nr == gsmnet->num_bts) {
672 /* allocate a new one */
673 bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_UNKNOWN,
674 HARDCODED_TSC, HARDCODED_BSIC);
675 } else
676 bts = gsm_bts_num(gsmnet, bts_nr);
677
678 if (!bts)
679 return CMD_WARNING;
Harald Welte59b04682009-06-10 05:40:52 +0800680
681 vty->index = bts;
682 vty->node = BTS_NODE;
683
684 return CMD_SUCCESS;
685}
686
687DEFUN(cfg_bts_type,
688 cfg_bts_type_cmd,
689 "type TYPE",
690 "Set the BTS type\n")
691{
692 struct gsm_bts *bts = vty->index;
693
Harald Welte3ffe1b32009-08-07 00:25:23 +0200694 bts->type = parse_btstype(argv[0]);
695
Harald Welte59b04682009-06-10 05:40:52 +0800696 return CMD_SUCCESS;
697}
698
Harald Welte91afe4c2009-06-20 18:15:19 +0200699DEFUN(cfg_bts_band,
700 cfg_bts_band_cmd,
701 "band BAND",
702 "Set the frequency band of this BTS\n")
703{
704 struct gsm_bts *bts = vty->index;
705 int band = gsm_band_parse(atoi(argv[0]));
706
707 if (band < 0) {
708 vty_out(vty, "%% BAND %d is not a valid GSM band%s",
709 band, VTY_NEWLINE);
710 return CMD_WARNING;
711 }
712
713 bts->band = band;
714
715 return CMD_SUCCESS;
716}
717
Harald Welte59b04682009-06-10 05:40:52 +0800718DEFUN(cfg_bts_lac,
719 cfg_bts_lac_cmd,
720 "location_area_code <0-255>",
721 "Set the Location Area Code (LAC) of this BTS\n")
722{
723 struct gsm_bts *bts = vty->index;
724 int lac = atoi(argv[0]);
725
726 if (lac < 0 || lac > 0xff) {
727 vty_out(vty, "%% LAC %d is not in the valid range (0-255)%s",
728 lac, VTY_NEWLINE);
729 return CMD_WARNING;
730 }
731 bts->location_area_code = lac;
732
733 return CMD_SUCCESS;
734}
735
736DEFUN(cfg_bts_tsc,
737 cfg_bts_tsc_cmd,
738 "training_sequence_code <0-255>",
739 "Set the Training Sequence Code (TSC) of this BTS\n")
740{
741 struct gsm_bts *bts = vty->index;
742 int tsc = atoi(argv[0]);
743
744 if (tsc < 0 || tsc > 0xff) {
745 vty_out(vty, "%% TSC %d is not in the valid range (0-255)%s",
746 tsc, VTY_NEWLINE);
747 return CMD_WARNING;
748 }
749 bts->tsc = tsc;
750
751 return CMD_SUCCESS;
752}
753
754DEFUN(cfg_bts_bsic,
755 cfg_bts_bsic_cmd,
756 "base_station_id_code <0-63>",
757 "Set the Base Station Identity Code (BSIC) of this BTS\n")
758{
759 struct gsm_bts *bts = vty->index;
760 int bsic = atoi(argv[0]);
761
762 if (bsic < 0 || bsic > 0x3f) {
763 vty_out(vty, "%% TSC %d is not in the valid range (0-255)%s",
764 bsic, VTY_NEWLINE);
765 return CMD_WARNING;
766 }
767 bts->bsic = bsic;
768
769 return CMD_SUCCESS;
770}
771
772
773DEFUN(cfg_bts_unit_id,
774 cfg_bts_unit_id_cmd,
Harald Weltef515aa02009-08-07 13:27:09 +0200775 "ip.access unit_id <0-65534> <0-255>",
776 "Set the ip.access BTS Unit ID of this BTS\n")
Harald Welte59b04682009-06-10 05:40:52 +0800777{
778 struct gsm_bts *bts = vty->index;
779 int site_id = atoi(argv[0]);
780 int bts_id = atoi(argv[1]);
781
782 if (site_id < 0 || site_id > 65534) {
783 vty_out(vty, "%% Site ID %d is not in the valid range%s",
784 site_id, VTY_NEWLINE);
785 return CMD_WARNING;
786 }
787 if (site_id < 0 || site_id > 255) {
788 vty_out(vty, "%% BTS ID %d is not in the valid range%s",
789 bts_id, VTY_NEWLINE);
790 return CMD_WARNING;
791 }
Harald Weltef515aa02009-08-07 13:27:09 +0200792
793 if (!is_ipaccess_bts(bts)) {
794 vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE);
795 return CMD_WARNING;
796 }
797
Harald Welte59b04682009-06-10 05:40:52 +0800798 bts->ip_access.site_id = site_id;
799 bts->ip_access.bts_id = bts_id;
800
801 return CMD_SUCCESS;
802}
803
804/* per TRX configuration */
805DEFUN(cfg_trx,
806 cfg_trx_cmd,
807 "trx TRX_NR",
808 "Select a TRX to configure")
809{
810 int trx_nr = atoi(argv[0]);
811 struct gsm_bts *bts = vty->index;
812 struct gsm_bts_trx *trx;
813
Harald Weltee712a5f2009-06-21 16:17:15 +0200814 if (trx_nr > bts->num_trx) {
815 vty_out(vty, "%% The next unused TRX number in this BTS is %u%s",
816 bts->num_trx, VTY_NEWLINE);
Harald Welte59b04682009-06-10 05:40:52 +0800817 return CMD_WARNING;
Harald Weltee712a5f2009-06-21 16:17:15 +0200818 } else if (trx_nr == bts->num_trx) {
819 /* we need to allocate a new one */
820 trx = gsm_bts_trx_alloc(bts);
821 } else
822 trx = gsm_bts_trx_num(bts, trx_nr);
823
824 if (!trx)
825 return CMD_WARNING;
Harald Welte59b04682009-06-10 05:40:52 +0800826
827 vty->index = trx;
828 vty->node = TRX_NODE;
829
830 return CMD_SUCCESS;
831}
832
833DEFUN(cfg_trx_arfcn,
834 cfg_trx_arfcn_cmd,
835 "arfcn <1-1024>",
836 "Set the ARFCN for this TRX\n")
837{
838 int arfcn = atoi(argv[0]);
839 struct gsm_bts_trx *trx = vty->index;
840
841 /* FIXME: check if this ARFCN is supported by this TRX */
842
843 trx->arfcn = arfcn;
844
845 /* FIXME: patch ARFCN into SYSTEM INFORMATION */
846 /* FIXME: use OML layer to update the ARFCN */
847 /* FIXME: use RSL layer to update SYSTEM INFORMATION */
848
849 return CMD_SUCCESS;
850}
851
Harald Welte91afe4c2009-06-20 18:15:19 +0200852DEFUN(cfg_trx_max_power_red,
853 cfg_trx_max_power_red_cmd,
854 "max_power_red <0-100>",
855 "Reduction of maximum BS RF Power in dB\n")
856{
857 int maxpwr_r = atoi(argv[0]);
858 struct gsm_bts_trx *trx = vty->index;
859 int upper_limit = 12; /* default 12.21 max power red. */
860
861 /* FIXME: check if our BTS type supports more than 12 */
862 if (maxpwr_r < 0 || maxpwr_r > upper_limit) {
863 vty_out(vty, "%% Power %d dB is not in the valid range%s",
864 maxpwr_r, VTY_NEWLINE);
865 return CMD_WARNING;
866 }
867 if (maxpwr_r & 1) {
868 vty_out(vty, "%% Power %d dB is not an even value%s",
869 maxpwr_r, VTY_NEWLINE);
870 return CMD_WARNING;
871 }
872
873 trx->max_power_red = maxpwr_r;
874
875 /* FIXME: make sure we update this using OML */
876
877 return CMD_SUCCESS;
878}
879
Harald Welte59b04682009-06-10 05:40:52 +0800880/* per TS configuration */
881DEFUN(cfg_ts,
882 cfg_ts_cmd,
883 "timeslot TS_NR",
884 "Select a Timeslot to configure")
885{
886 int ts_nr = atoi(argv[0]);
887 struct gsm_bts_trx *trx = vty->index;
888 struct gsm_bts_trx_ts *ts;
889
890 if (ts_nr >= TRX_NR_TS) {
891 vty_out(vty, "%% A GSM TRX only has %u Timeslots per TRX%s",
892 TRX_NR_TS, VTY_NEWLINE);
893 return CMD_WARNING;
894 }
895
896 ts = &trx->ts[ts_nr];
897
898 vty->index = ts;
899 vty->node = TS_NODE;
900
901 return CMD_SUCCESS;
902}
903
Harald Welte3ffe1b32009-08-07 00:25:23 +0200904DEFUN(cfg_ts_pchan,
905 cfg_ts_pchan_cmd,
906 "phys_chan_config PCHAN",
907 "Physical Channel configuration (TCH/SDCCH/...)")
908{
909 struct gsm_bts_trx_ts *ts = vty->index;
910 int pchanc;
911
912 pchanc = gsm_pchan_parse(argv[0]);
913 if (pchanc < 0)
914 return CMD_WARNING;
915
916 ts->pchan = pchanc;
917
918 return CMD_SUCCESS;
919}
920
921DEFUN(cfg_ts_e1_subslot,
922 cfg_ts_e1_subslot_cmd,
923 "e1_subslot E1_IF <1-31> <0-4>",
924 "E1 sub-slot connected to this on-air timeslot")
925{
926 struct gsm_bts_trx_ts *ts = vty->index;
927
928 ts->e1_link.e1_nr = atoi(argv[0]);
929 ts->e1_link.e1_ts = atoi(argv[1]);
930 ts->e1_link.e1_ts_ss = atoi(argv[2]);
931
932 return CMD_SUCCESS;
933}
Harald Welte59b04682009-06-10 05:40:52 +0800934
935/* Subscriber */
936DEFUN(show_subscr,
937 show_subscr_cmd,
938 "show subscriber [IMSI]",
939 SHOW_STR "Display information about a subscriber\n")
940{
941 const char *imsi;
942 struct gsm_subscriber *subscr;
943
944 if (argc >= 1) {
945 imsi = argv[0];
Harald Welteaae7a522009-07-23 19:21:02 +0200946 subscr = subscr_get_by_imsi(gsmnet, imsi);
Harald Welte59b04682009-06-10 05:40:52 +0800947 if (!subscr) {
948 vty_out(vty, "%% unknown subscriber%s",
949 VTY_NEWLINE);
950 return CMD_WARNING;
951 }
952 subscr_dump_vty(vty, subscr);
953
954 return CMD_SUCCESS;
955 }
956
957 /* FIXME: iterate over all subscribers ? */
958 return CMD_WARNING;
959
960 return CMD_SUCCESS;
961}
962
963DEFUN(cfg_subscr_name,
964 cfg_subscr_name_cmd,
965 "name NAME",
966 "Set the name of the subscriber")
967{
968 const char *name = argv[0];
969 struct gsm_subscriber *subscr = vty->index;
970
971 strncpy(subscr->name, name, sizeof(subscr->name));
972
973 db_sync_subscriber(subscr);
974
975 return CMD_SUCCESS;
976}
977
978DEFUN(cfg_subscr_extension,
979 cfg_subscr_extension_cmd,
980 "extension EXTENSION",
981 "Set the extension of the subscriber")
982{
983 const char *name = argv[0];
984 struct gsm_subscriber *subscr = vty->index;
985
986 strncpy(subscr->extension, name, sizeof(subscr->extension));
987
988 db_sync_subscriber(subscr);
989
990 return CMD_SUCCESS;
991}
992
993DEFUN(cfg_subscr_authorized,
994 cfg_subscr_authorized_cmd,
995 "auth <0-1>",
996 "Set the authorization status of the subscriber")
997{
998 int auth = atoi(argv[0]);
999 struct gsm_subscriber *subscr = vty->index;
1000
1001 if (auth)
1002 subscr->authorized = 1;
1003 else
1004 subscr->authorized = 0;
1005
1006 db_sync_subscriber(subscr);
1007
1008 return CMD_SUCCESS;
1009}
1010
1011int bsc_vty_init(struct gsm_network *net)
1012{
1013 gsmnet = net;
1014
1015 cmd_init(1);
1016 vty_init();
1017
1018 install_element(VIEW_NODE, &show_net_cmd);
1019 install_element(VIEW_NODE, &show_bts_cmd);
1020 install_element(VIEW_NODE, &show_trx_cmd);
1021 install_element(VIEW_NODE, &show_ts_cmd);
1022 install_element(VIEW_NODE, &show_lchan_cmd);
1023
1024 install_element(VIEW_NODE, &show_e1drv_cmd);
1025 install_element(VIEW_NODE, &show_e1line_cmd);
1026 install_element(VIEW_NODE, &show_e1ts_cmd);
1027
1028 install_element(VIEW_NODE, &show_paging_cmd);
1029
1030 install_element(VIEW_NODE, &show_subscr_cmd);
1031
1032 install_element(CONFIG_NODE, &cfg_bts_cmd);
Harald Welte97ceef92009-08-06 19:06:46 +02001033 install_node(&bts_node, config_write_bts);
Harald Welte59b04682009-06-10 05:40:52 +08001034 install_default(BTS_NODE);
1035 install_element(BTS_NODE, &cfg_bts_type_cmd);
Harald Welte91afe4c2009-06-20 18:15:19 +02001036 install_element(BTS_NODE, &cfg_bts_band_cmd);
Harald Welte59b04682009-06-10 05:40:52 +08001037 install_element(BTS_NODE, &cfg_bts_lac_cmd);
1038 install_element(BTS_NODE, &cfg_bts_tsc_cmd);
1039 install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
1040
1041 install_element(BTS_NODE, &cfg_trx_cmd);
1042 install_node(&trx_node, dummy_config_write);
1043 install_default(TRX_NODE);
1044 install_element(TRX_NODE, &cfg_trx_arfcn_cmd);
Harald Welte7f597bc2009-06-20 22:36:12 +02001045 install_element(TRX_NODE, &cfg_trx_max_power_red_cmd);
Harald Welte59b04682009-06-10 05:40:52 +08001046
1047 install_element(TRX_NODE, &cfg_ts_cmd);
1048 install_node(&ts_node, dummy_config_write);
1049 install_default(TS_NODE);
Harald Welte3ffe1b32009-08-07 00:25:23 +02001050 install_element(TS_NODE, &cfg_ts_pchan_cmd);
1051 install_element(TS_NODE, &cfg_ts_e1_subslot_cmd);
Harald Welte59b04682009-06-10 05:40:52 +08001052
1053 install_element(CONFIG_NODE, &cfg_subscr_cmd);
1054 install_node(&subscr_node, dummy_config_write);
1055 install_default(SUBSCR_NODE);
1056 install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
1057 install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
1058 install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
1059
1060 return 0;
1061}