blob: b824c3db6aaded68f9f45194ea4d403bc02ff7d6 [file] [log] [blame]
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +02001/* OpenBSC interface to quagga VTY */
2/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +01003 * (C) 2009 by Holger Hans Peter Freyther
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +02004 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#include <stdlib.h>
23#include <unistd.h>
24#include <sys/types.h>
25
26#include <vty/command.h>
27#include <vty/buffer.h>
28#include <vty/vty.h>
29
30#include <arpa/inet.h>
31
Harald Weltedfe6c7d2010-02-20 16:24:02 +010032#include <osmocore/linuxlist.h>
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020033#include <openbsc/gsm_data.h>
34#include <openbsc/gsm_subscriber.h>
Harald Welteb54d9502009-11-17 06:00:23 +010035#include <openbsc/silent_call.h>
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020036#include <openbsc/gsm_04_11.h>
37#include <openbsc/e1_input.h>
38#include <openbsc/abis_nm.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010039#include <osmocore/gsm_utils.h>
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020040#include <openbsc/db.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010041#include <osmocore/talloc.h>
Harald Weltea1482332009-11-14 10:08:40 +010042#include <openbsc/signal.h>
Holger Hans Peter Freyther424c4f02010-01-06 06:00:40 +010043#include <openbsc/debug.h>
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020044
45static struct gsm_network *gsmnet;
46
47struct cmd_node subscr_node = {
48 SUBSCR_NODE,
49 "%s(subscriber)#",
50 1,
51};
52
53static int dummy_config_write(struct vty *v)
54{
55 return CMD_SUCCESS;
56}
57
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020058static struct buffer *argv_to_buffer(int argc, const char *argv[], int base)
59{
60 struct buffer *b = buffer_new(1024);
61 int i;
62
63 if (!b)
64 return NULL;
65
66 for (i = base; i < argc; i++) {
67 buffer_putstr(b, argv[i]);
68 buffer_putc(b, ' ');
69 }
70 buffer_putc(b, '\0');
71
72 return b;
73}
74
Sylvain Munaut99792902009-12-27 19:30:46 +010075static int hexparse(const char *str, u_int8_t *b, int max_len)
76
77{
78 int i, l, v;
79
80 l = strlen(str);
81 if ((l&1) || ((l>>1) > max_len))
82 return -1;
83
84 memset(b, 0x00, max_len);
85
86 for (i=0; i<l; i++) {
87 char c = str[i];
88 if (c >= '0' && c <= '9')
89 v = c - '0';
90 else if (c >= 'a' && c <= 'f')
91 v = 10 + (c - 'a');
92 else if (c >= 'A' && c <= 'F')
93 v = 10 + (c - 'a');
94 else
95 return -1;
96 b[i>>1] |= v << (i&1 ? 0 : 4);
97 }
98
99 return i>>1;
100}
101
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200102/* per-subscriber configuration */
103DEFUN(cfg_subscr,
104 cfg_subscr_cmd,
105 "subscriber IMSI",
106 "Select a Subscriber to configure\n")
107{
108 const char *imsi = argv[0];
109 struct gsm_subscriber *subscr;
110
111 subscr = subscr_get_by_imsi(gsmnet, imsi);
112 if (!subscr) {
113 vty_out(vty, "%% No subscriber for IMSI %s%s",
114 imsi, VTY_NEWLINE);
115 return CMD_WARNING;
116 }
117
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +0100118 /* vty_go_parent should put this subscriber */
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200119 vty->index = subscr;
120 vty->node = SUBSCR_NODE;
121
122 return CMD_SUCCESS;
123}
124
Holger Hans Peter Freyther424c4f02010-01-06 06:00:40 +0100125static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
126{
127 int rc;
128 struct gsm_auth_info ainfo;
129 struct gsm_auth_tuple atuple;
130
131 vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
132 subscr->authorized, VTY_NEWLINE);
133 if (subscr->name)
134 vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
135 if (subscr->extension)
136 vty_out(vty, " Extension: %s%s", subscr->extension,
137 VTY_NEWLINE);
138 if (subscr->imsi)
139 vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
140 if (subscr->tmsi != GSM_RESERVED_TMSI)
141 vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
142 VTY_NEWLINE);
143
144 rc = get_authinfo_by_subscr(&ainfo, subscr);
145 if (!rc) {
146 vty_out(vty, " A3A8 algorithm id: %d%s",
147 ainfo.auth_algo, VTY_NEWLINE);
148 vty_out(vty, " A3A8 Ki: %s%s",
149 hexdump(ainfo.a3a8_ki, ainfo.a3a8_ki_len),
150 VTY_NEWLINE);
151 }
152
153 rc = get_authtuple_by_subscr(&atuple, subscr);
154 if (!rc) {
155 vty_out(vty, " A3A8 last tuple (used %d times):%s",
156 atuple.use_count, VTY_NEWLINE);
157 vty_out(vty, " seq # : %d%s",
158 atuple.key_seq, VTY_NEWLINE);
159 vty_out(vty, " RAND : %s%s",
160 hexdump(atuple.rand, sizeof(atuple.rand)),
161 VTY_NEWLINE);
162 vty_out(vty, " SRES : %s%s",
163 hexdump(atuple.sres, sizeof(atuple.sres)),
164 VTY_NEWLINE);
165 vty_out(vty, " Kc : %s%s",
166 hexdump(atuple.kc, sizeof(atuple.kc)),
167 VTY_NEWLINE);
168 }
169
170 vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
171}
172
173
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200174/* Subscriber */
175DEFUN(show_subscr,
176 show_subscr_cmd,
177 "show subscriber [IMSI]",
178 SHOW_STR "Display information about a subscriber\n")
179{
180 const char *imsi;
181 struct gsm_subscriber *subscr;
182
183 if (argc >= 1) {
184 imsi = argv[0];
185 subscr = subscr_get_by_imsi(gsmnet, imsi);
186 if (!subscr) {
187 vty_out(vty, "%% unknown subscriber%s",
188 VTY_NEWLINE);
189 return CMD_WARNING;
190 }
Holger Hans Peter Freyther424c4f02010-01-06 06:00:40 +0100191 subscr_dump_full_vty(vty, subscr);
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +0100192 subscr_put(subscr);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200193
194 return CMD_SUCCESS;
195 }
196
197 /* FIXME: iterate over all subscribers ? */
198 return CMD_WARNING;
199
200 return CMD_SUCCESS;
201}
202
203DEFUN(show_subscr_cache,
204 show_subscr_cache_cmd,
205 "show subscriber cache",
206 SHOW_STR "Display contents of subscriber cache\n")
207{
208 struct gsm_subscriber *subscr;
209
210 llist_for_each_entry(subscr, &active_subscribers, entry) {
211 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
Holger Hans Peter Freyther424c4f02010-01-06 06:00:40 +0100212 subscr_dump_full_vty(vty, subscr);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200213 }
214
215 return CMD_SUCCESS;
216}
217
218DEFUN(sms_send_pend,
219 sms_send_pend_cmd,
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100220 "sms send pending",
221 "Send all pending SMS")
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200222{
223 struct gsm_sms *sms;
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100224 int id = 0;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200225
226 while (1) {
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100227 sms = db_sms_get_unsent_by_subscr(gsmnet, id);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200228 if (!sms)
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100229 break;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200230
231 gsm411_send_sms_subscr(sms->receiver, sms);
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100232
233 id = sms->receiver->id + 1;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200234 }
235
236 return CMD_SUCCESS;
237}
238
239struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text)
240{
241 struct gsm_sms *sms = sms_alloc();
242
243 if (!sms)
244 return NULL;
245
246 if (!receiver->lac) {
247 /* subscriber currently not attached, store in database? */
248 return NULL;
249 }
250
251 sms->receiver = subscr_get(receiver);
252 strncpy(sms->text, text, sizeof(sms->text)-1);
253
254 /* FIXME: don't use ID 1 static */
255 sms->sender = subscr_get_by_id(gsmnet, 1);
256 sms->reply_path_req = 0;
257 sms->status_rep_req = 0;
258 sms->ud_hdr_ind = 0;
259 sms->protocol_id = 0; /* implicit */
260 sms->data_coding_scheme = 0; /* default 7bit */
261 strncpy(sms->dest_addr, receiver->extension, sizeof(sms->dest_addr)-1);
262 /* Generate user_data */
263 sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
264
265 return sms;
266}
267
268static int _send_sms_buffer(struct gsm_subscriber *receiver,
Harald Welte793a1352009-11-05 15:51:17 +0900269 struct buffer *b, u_int8_t tp_pid)
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200270{
271 struct gsm_sms *sms;
272
273 sms = sms_from_text(receiver, buffer_getstr(b));
Harald Welte793a1352009-11-05 15:51:17 +0900274 sms->protocol_id = tp_pid;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200275 gsm411_send_sms_subscr(receiver, sms);
276
277 return CMD_SUCCESS;
278}
279
Harald Welte98f9c752009-11-14 08:00:53 +0100280static struct gsm_subscriber *get_subscr_by_argv(const char *type,
281 const char *id)
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200282{
Harald Welte98f9c752009-11-14 08:00:53 +0100283 if (!strcmp(type, "extension"))
284 return subscr_get_by_extension(gsmnet, id);
285 else if (!strcmp(type, "imsi"))
286 return subscr_get_by_imsi(gsmnet, id);
287 else if (!strcmp(type, "tmsi"))
288 return subscr_get_by_tmsi(gsmnet, atoi(id));
289 else if (!strcmp(type, "id"))
290 return subscr_get_by_id(gsmnet, atoi(id));
291
292 return NULL;
293}
294#define SUBSCR_TYPES "(extension|imsi|tmsi|id)"
295
296DEFUN(subscriber_send_sms,
297 subscriber_send_sms_cmd,
298 "subscriber " SUBSCR_TYPES " EXTEN sms send .LINE",
299 "Select subscriber based on extension")
300{
301 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200302 struct buffer *b;
303 int rc;
304
Harald Welte20f98312009-11-14 10:11:45 +0100305 if (!subscr) {
306 vty_out(vty, "%% No subscriber found for %s %s%s",
307 argv[0], argv[1], VTY_NEWLINE);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200308 return CMD_WARNING;
Harald Welte20f98312009-11-14 10:11:45 +0100309 }
Harald Welte98f9c752009-11-14 08:00:53 +0100310 b = argv_to_buffer(argc, argv, 2);
311 rc = _send_sms_buffer(subscr, b, 0);
Harald Welte793a1352009-11-05 15:51:17 +0900312 buffer_free(b);
313
Harald Welteaf8c7b42009-11-14 10:10:54 +0100314 subscr_put(subscr);
315
Harald Welte793a1352009-11-05 15:51:17 +0900316 return rc;
317}
318
Harald Welte98f9c752009-11-14 08:00:53 +0100319DEFUN(subscriber_silent_sms,
320 subscriber_silent_sms_cmd,
321 "subscriber " SUBSCR_TYPES " EXTEN silent sms send .LINE",
322 "Select subscriber based on extension")
Harald Welte793a1352009-11-05 15:51:17 +0900323{
Harald Welte98f9c752009-11-14 08:00:53 +0100324 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
Harald Welte793a1352009-11-05 15:51:17 +0900325 struct buffer *b;
326 int rc;
327
Harald Welte20f98312009-11-14 10:11:45 +0100328 if (!subscr) {
329 vty_out(vty, "%% No subscriber found for %s %s%s",
330 argv[0], argv[1], VTY_NEWLINE);
Harald Welte793a1352009-11-05 15:51:17 +0900331 return CMD_WARNING;
Harald Welte20f98312009-11-14 10:11:45 +0100332 }
Harald Welte793a1352009-11-05 15:51:17 +0900333
Harald Welte98f9c752009-11-14 08:00:53 +0100334 b = argv_to_buffer(argc, argv, 2);
Harald Welteaf8c7b42009-11-14 10:10:54 +0100335 rc = _send_sms_buffer(subscr, b, 64);
Harald Welte793a1352009-11-05 15:51:17 +0900336 buffer_free(b);
337
Harald Welteaf8c7b42009-11-14 10:10:54 +0100338 subscr_put(subscr);
339
Harald Welte793a1352009-11-05 15:51:17 +0900340 return rc;
341}
342
Sylvain Munaut50480702010-01-02 14:29:43 +0100343DEFUN(subscriber_silent_call_start,
344 subscriber_silent_call_start_cmd,
345 "subscriber " SUBSCR_TYPES " EXTEN silent call start (any|tch/f|tch/any|sdcch)",
346 "Start a silent call to a subscriber")
347{
348 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
349 int rc, type;
350
351 if (!subscr) {
352 vty_out(vty, "%% No subscriber found for %s %s%s",
353 argv[0], argv[1], VTY_NEWLINE);
354 return CMD_WARNING;
355 }
356
357 if (!strcmp(argv[2], "tch/f"))
358 type = RSL_CHANNEED_TCH_F;
359 else if (!strcmp(argv[2], "tch/any"))
360 type = RSL_CHANNEED_TCH_ForH;
361 else if (!strcmp(argv[2], "sdcch"))
362 type = RSL_CHANNEED_SDCCH;
363 else
364 type = RSL_CHANNEED_ANY; /* Defaults to ANY */
365
366 rc = gsm_silent_call_start(subscr, vty, type);
367 if (rc <= 0) {
368 vty_out(vty, "%% Subscriber not attached%s",
369 VTY_NEWLINE);
370 subscr_put(subscr);
371 return CMD_WARNING;
372 }
373
374 subscr_put(subscr);
375
376 return CMD_SUCCESS;
377}
378
379DEFUN(subscriber_silent_call_stop,
380 subscriber_silent_call_stop_cmd,
381 "subscriber " SUBSCR_TYPES " EXTEN silent call stop",
382 "Stop a silent call to a subscriber")
Harald Weltea1482332009-11-14 10:08:40 +0100383{
384 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
385 int rc;
386
387 if (!subscr) {
388 vty_out(vty, "%% No subscriber found for %s %s%s",
Harald Welte20f98312009-11-14 10:11:45 +0100389 argv[0], argv[1], VTY_NEWLINE);
Harald Weltea1482332009-11-14 10:08:40 +0100390 return CMD_WARNING;
391 }
392
Sylvain Munaut50480702010-01-02 14:29:43 +0100393 rc = gsm_silent_call_stop(subscr);
394 if (rc < 0) {
395 subscr_put(subscr);
396 return CMD_WARNING;
Harald Weltea1482332009-11-14 10:08:40 +0100397 }
398
399 subscr_put(subscr);
400
401 return CMD_SUCCESS;
402}
403
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200404DEFUN(cfg_subscr_name,
405 cfg_subscr_name_cmd,
406 "name NAME",
407 "Set the name of the subscriber")
408{
409 const char *name = argv[0];
410 struct gsm_subscriber *subscr = vty->index;
411
412 strncpy(subscr->name, name, sizeof(subscr->name));
413
414 db_sync_subscriber(subscr);
415
416 return CMD_SUCCESS;
417}
418
419DEFUN(cfg_subscr_extension,
420 cfg_subscr_extension_cmd,
421 "extension EXTENSION",
422 "Set the extension of the subscriber")
423{
424 const char *name = argv[0];
425 struct gsm_subscriber *subscr = vty->index;
426
427 strncpy(subscr->extension, name, sizeof(subscr->extension));
428
429 db_sync_subscriber(subscr);
430
431 return CMD_SUCCESS;
432}
433
434DEFUN(cfg_subscr_authorized,
435 cfg_subscr_authorized_cmd,
436 "auth <0-1>",
437 "Set the authorization status of the subscriber")
438{
439 int auth = atoi(argv[0]);
440 struct gsm_subscriber *subscr = vty->index;
441
442 if (auth)
443 subscr->authorized = 1;
444 else
445 subscr->authorized = 0;
446
447 db_sync_subscriber(subscr);
448
449 return CMD_SUCCESS;
450}
451
Sylvain Munaut99792902009-12-27 19:30:46 +0100452#define A3A8_ALG_TYPES "(none|comp128v1)"
453
454DEFUN(cfg_subscr_a3a8,
455 cfg_subscr_a3a8_cmd,
456 "a3a8 " A3A8_ALG_TYPES " [KI]",
457 "Set a3a8 parameters for the subscriber")
458{
459 struct gsm_subscriber *subscr = vty->index;
460 const char *alg_str = argv[0];
461 const char *ki_str = argv[1];
462 struct gsm_auth_info ainfo;
463 int rc;
464
465 if (!strcasecmp(alg_str, "none")) {
466 /* Just erase */
467 rc = set_authinfo_for_subscr(NULL, subscr);
468 } else if (!strcasecmp(alg_str, "comp128v1")) {
469 /* Parse hex string Ki */
470 rc = hexparse(ki_str, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
471 if (rc != 16)
472 return CMD_WARNING;
473
474 /* Set the infos */
475 ainfo.auth_algo = AUTH_ALGO_COMP128v1;
476 ainfo.a3a8_ki_len = rc;
477 rc = set_authinfo_for_subscr(&ainfo, subscr);
478 } else {
479 /* Unknown method */
480 return CMD_WARNING;
481 }
482
483 return rc ? CMD_WARNING : CMD_SUCCESS;
484}
485
Harald Weltea1482332009-11-14 10:08:40 +0100486static int scall_cbfn(unsigned int subsys, unsigned int signal,
487 void *handler_data, void *signal_data)
488{
489 struct scall_signal_data *sigdata = signal_data;
490 struct vty *vty = sigdata->data;
491
492 switch (signal) {
493 case S_SCALL_SUCCESS:
494 vty_out(vty, "%% silent call on ARFCN %u timeslot %u%s",
495 sigdata->lchan->ts->trx->arfcn, sigdata->lchan->ts->nr,
496 VTY_NEWLINE);
497 break;
498 case S_SCALL_EXPIRED:
499 vty_out(vty, "%% silent call expired paging%s", VTY_NEWLINE);
500 break;
501 }
502 return 0;
503}
504
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200505int bsc_vty_init_extra(struct gsm_network *net)
506{
507 gsmnet = net;
508
Harald Weltea1482332009-11-14 10:08:40 +0100509 register_signal_handler(SS_SCALL, scall_cbfn, NULL);
510
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200511 install_element(VIEW_NODE, &show_subscr_cmd);
512 install_element(VIEW_NODE, &show_subscr_cache_cmd);
513
514 install_element(VIEW_NODE, &sms_send_pend_cmd);
Harald Welte98f9c752009-11-14 08:00:53 +0100515
516 install_element(VIEW_NODE, &subscriber_send_sms_cmd);
517 install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
Sylvain Munaut50480702010-01-02 14:29:43 +0100518 install_element(VIEW_NODE, &subscriber_silent_call_start_cmd);
519 install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200520
521 install_element(CONFIG_NODE, &cfg_subscr_cmd);
522 install_node(&subscr_node, dummy_config_write);
523
524 install_default(SUBSCR_NODE);
525 install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
526 install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
527 install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
Sylvain Munaut99792902009-12-27 19:30:46 +0100528 install_element(SUBSCR_NODE, &cfg_subscr_a3a8_cmd);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200529
530 return 0;
531}