blob: bc2bfaa6c88c17a1240b0f69b0026670ed3aaa85 [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
32#include <openbsc/linuxlist.h>
33#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>
39#include <openbsc/gsm_utils.h>
40#include <openbsc/db.h>
41#include <openbsc/talloc.h>
Harald Weltea1482332009-11-14 10:08:40 +010042#include <openbsc/signal.h>
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020043
44/* forward declarations */
45void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr);
46
47static struct gsm_network *gsmnet;
48
49struct cmd_node subscr_node = {
50 SUBSCR_NODE,
51 "%s(subscriber)#",
52 1,
53};
54
55static int dummy_config_write(struct vty *v)
56{
57 return CMD_SUCCESS;
58}
59
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020060static struct buffer *argv_to_buffer(int argc, const char *argv[], int base)
61{
62 struct buffer *b = buffer_new(1024);
63 int i;
64
65 if (!b)
66 return NULL;
67
68 for (i = base; i < argc; i++) {
69 buffer_putstr(b, argv[i]);
70 buffer_putc(b, ' ');
71 }
72 buffer_putc(b, '\0');
73
74 return b;
75}
76
Sylvain Munaut99792902009-12-27 19:30:46 +010077static int hexparse(const char *str, u_int8_t *b, int max_len)
78
79{
80 int i, l, v;
81
82 l = strlen(str);
83 if ((l&1) || ((l>>1) > max_len))
84 return -1;
85
86 memset(b, 0x00, max_len);
87
88 for (i=0; i<l; i++) {
89 char c = str[i];
90 if (c >= '0' && c <= '9')
91 v = c - '0';
92 else if (c >= 'a' && c <= 'f')
93 v = 10 + (c - 'a');
94 else if (c >= 'A' && c <= 'F')
95 v = 10 + (c - 'a');
96 else
97 return -1;
98 b[i>>1] |= v << (i&1 ? 0 : 4);
99 }
100
101 return i>>1;
102}
103
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200104/* per-subscriber configuration */
105DEFUN(cfg_subscr,
106 cfg_subscr_cmd,
107 "subscriber IMSI",
108 "Select a Subscriber to configure\n")
109{
110 const char *imsi = argv[0];
111 struct gsm_subscriber *subscr;
112
113 subscr = subscr_get_by_imsi(gsmnet, imsi);
114 if (!subscr) {
115 vty_out(vty, "%% No subscriber for IMSI %s%s",
116 imsi, VTY_NEWLINE);
117 return CMD_WARNING;
118 }
119
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +0100120 /* vty_go_parent should put this subscriber */
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200121 vty->index = subscr;
122 vty->node = SUBSCR_NODE;
123
124 return CMD_SUCCESS;
125}
126
127/* Subscriber */
128DEFUN(show_subscr,
129 show_subscr_cmd,
130 "show subscriber [IMSI]",
131 SHOW_STR "Display information about a subscriber\n")
132{
133 const char *imsi;
134 struct gsm_subscriber *subscr;
135
136 if (argc >= 1) {
137 imsi = argv[0];
138 subscr = subscr_get_by_imsi(gsmnet, imsi);
139 if (!subscr) {
140 vty_out(vty, "%% unknown subscriber%s",
141 VTY_NEWLINE);
142 return CMD_WARNING;
143 }
144 subscr_dump_vty(vty, subscr);
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +0100145 subscr_put(subscr);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200146
147 return CMD_SUCCESS;
148 }
149
150 /* FIXME: iterate over all subscribers ? */
151 return CMD_WARNING;
152
153 return CMD_SUCCESS;
154}
155
156DEFUN(show_subscr_cache,
157 show_subscr_cache_cmd,
158 "show subscriber cache",
159 SHOW_STR "Display contents of subscriber cache\n")
160{
161 struct gsm_subscriber *subscr;
162
163 llist_for_each_entry(subscr, &active_subscribers, entry) {
164 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
165 subscr_dump_vty(vty, subscr);
166 }
167
168 return CMD_SUCCESS;
169}
170
171DEFUN(sms_send_pend,
172 sms_send_pend_cmd,
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100173 "sms send pending",
174 "Send all pending SMS")
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200175{
176 struct gsm_sms *sms;
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100177 int id = 0;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200178
179 while (1) {
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100180 sms = db_sms_get_unsent_by_subscr(gsmnet, id);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200181 if (!sms)
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100182 break;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200183
184 gsm411_send_sms_subscr(sms->receiver, sms);
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100185
186 id = sms->receiver->id + 1;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200187 }
188
189 return CMD_SUCCESS;
190}
191
192struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text)
193{
194 struct gsm_sms *sms = sms_alloc();
195
196 if (!sms)
197 return NULL;
198
199 if (!receiver->lac) {
200 /* subscriber currently not attached, store in database? */
201 return NULL;
202 }
203
204 sms->receiver = subscr_get(receiver);
205 strncpy(sms->text, text, sizeof(sms->text)-1);
206
207 /* FIXME: don't use ID 1 static */
208 sms->sender = subscr_get_by_id(gsmnet, 1);
209 sms->reply_path_req = 0;
210 sms->status_rep_req = 0;
211 sms->ud_hdr_ind = 0;
212 sms->protocol_id = 0; /* implicit */
213 sms->data_coding_scheme = 0; /* default 7bit */
214 strncpy(sms->dest_addr, receiver->extension, sizeof(sms->dest_addr)-1);
215 /* Generate user_data */
216 sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
217
218 return sms;
219}
220
221static int _send_sms_buffer(struct gsm_subscriber *receiver,
Harald Welte793a1352009-11-05 15:51:17 +0900222 struct buffer *b, u_int8_t tp_pid)
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200223{
224 struct gsm_sms *sms;
225
226 sms = sms_from_text(receiver, buffer_getstr(b));
Harald Welte793a1352009-11-05 15:51:17 +0900227 sms->protocol_id = tp_pid;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200228 gsm411_send_sms_subscr(receiver, sms);
229
230 return CMD_SUCCESS;
231}
232
Harald Welte98f9c752009-11-14 08:00:53 +0100233static struct gsm_subscriber *get_subscr_by_argv(const char *type,
234 const char *id)
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200235{
Harald Welte98f9c752009-11-14 08:00:53 +0100236 if (!strcmp(type, "extension"))
237 return subscr_get_by_extension(gsmnet, id);
238 else if (!strcmp(type, "imsi"))
239 return subscr_get_by_imsi(gsmnet, id);
240 else if (!strcmp(type, "tmsi"))
241 return subscr_get_by_tmsi(gsmnet, atoi(id));
242 else if (!strcmp(type, "id"))
243 return subscr_get_by_id(gsmnet, atoi(id));
244
245 return NULL;
246}
247#define SUBSCR_TYPES "(extension|imsi|tmsi|id)"
248
249DEFUN(subscriber_send_sms,
250 subscriber_send_sms_cmd,
251 "subscriber " SUBSCR_TYPES " EXTEN sms send .LINE",
252 "Select subscriber based on extension")
253{
254 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200255 struct buffer *b;
256 int rc;
257
Harald Welte20f98312009-11-14 10:11:45 +0100258 if (!subscr) {
259 vty_out(vty, "%% No subscriber found for %s %s%s",
260 argv[0], argv[1], VTY_NEWLINE);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200261 return CMD_WARNING;
Harald Welte20f98312009-11-14 10:11:45 +0100262 }
Harald Welte98f9c752009-11-14 08:00:53 +0100263 b = argv_to_buffer(argc, argv, 2);
264 rc = _send_sms_buffer(subscr, b, 0);
Harald Welte793a1352009-11-05 15:51:17 +0900265 buffer_free(b);
266
Harald Welteaf8c7b42009-11-14 10:10:54 +0100267 subscr_put(subscr);
268
Harald Welte793a1352009-11-05 15:51:17 +0900269 return rc;
270}
271
Harald Welte98f9c752009-11-14 08:00:53 +0100272DEFUN(subscriber_silent_sms,
273 subscriber_silent_sms_cmd,
274 "subscriber " SUBSCR_TYPES " EXTEN silent sms send .LINE",
275 "Select subscriber based on extension")
Harald Welte793a1352009-11-05 15:51:17 +0900276{
Harald Welte98f9c752009-11-14 08:00:53 +0100277 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
Harald Welte793a1352009-11-05 15:51:17 +0900278 struct buffer *b;
279 int rc;
280
Harald Welte20f98312009-11-14 10:11:45 +0100281 if (!subscr) {
282 vty_out(vty, "%% No subscriber found for %s %s%s",
283 argv[0], argv[1], VTY_NEWLINE);
Harald Welte793a1352009-11-05 15:51:17 +0900284 return CMD_WARNING;
Harald Welte20f98312009-11-14 10:11:45 +0100285 }
Harald Welte793a1352009-11-05 15:51:17 +0900286
Harald Welte98f9c752009-11-14 08:00:53 +0100287 b = argv_to_buffer(argc, argv, 2);
Harald Welteaf8c7b42009-11-14 10:10:54 +0100288 rc = _send_sms_buffer(subscr, b, 64);
Harald Welte793a1352009-11-05 15:51:17 +0900289 buffer_free(b);
290
Harald Welteaf8c7b42009-11-14 10:10:54 +0100291 subscr_put(subscr);
292
Harald Welte793a1352009-11-05 15:51:17 +0900293 return rc;
294}
295
Sylvain Munaut50480702010-01-02 14:29:43 +0100296DEFUN(subscriber_silent_call_start,
297 subscriber_silent_call_start_cmd,
298 "subscriber " SUBSCR_TYPES " EXTEN silent call start (any|tch/f|tch/any|sdcch)",
299 "Start a silent call to a subscriber")
300{
301 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
302 int rc, type;
303
304 if (!subscr) {
305 vty_out(vty, "%% No subscriber found for %s %s%s",
306 argv[0], argv[1], VTY_NEWLINE);
307 return CMD_WARNING;
308 }
309
310 if (!strcmp(argv[2], "tch/f"))
311 type = RSL_CHANNEED_TCH_F;
312 else if (!strcmp(argv[2], "tch/any"))
313 type = RSL_CHANNEED_TCH_ForH;
314 else if (!strcmp(argv[2], "sdcch"))
315 type = RSL_CHANNEED_SDCCH;
316 else
317 type = RSL_CHANNEED_ANY; /* Defaults to ANY */
318
319 rc = gsm_silent_call_start(subscr, vty, type);
320 if (rc <= 0) {
321 vty_out(vty, "%% Subscriber not attached%s",
322 VTY_NEWLINE);
323 subscr_put(subscr);
324 return CMD_WARNING;
325 }
326
327 subscr_put(subscr);
328
329 return CMD_SUCCESS;
330}
331
332DEFUN(subscriber_silent_call_stop,
333 subscriber_silent_call_stop_cmd,
334 "subscriber " SUBSCR_TYPES " EXTEN silent call stop",
335 "Stop a silent call to a subscriber")
Harald Weltea1482332009-11-14 10:08:40 +0100336{
337 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
338 int rc;
339
340 if (!subscr) {
341 vty_out(vty, "%% No subscriber found for %s %s%s",
Harald Welte20f98312009-11-14 10:11:45 +0100342 argv[0], argv[1], VTY_NEWLINE);
Harald Weltea1482332009-11-14 10:08:40 +0100343 return CMD_WARNING;
344 }
345
Sylvain Munaut50480702010-01-02 14:29:43 +0100346 rc = gsm_silent_call_stop(subscr);
347 if (rc < 0) {
348 subscr_put(subscr);
349 return CMD_WARNING;
Harald Weltea1482332009-11-14 10:08:40 +0100350 }
351
352 subscr_put(subscr);
353
354 return CMD_SUCCESS;
355}
356
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200357DEFUN(cfg_subscr_name,
358 cfg_subscr_name_cmd,
359 "name NAME",
360 "Set the name of the subscriber")
361{
362 const char *name = argv[0];
363 struct gsm_subscriber *subscr = vty->index;
364
365 strncpy(subscr->name, name, sizeof(subscr->name));
366
367 db_sync_subscriber(subscr);
368
369 return CMD_SUCCESS;
370}
371
372DEFUN(cfg_subscr_extension,
373 cfg_subscr_extension_cmd,
374 "extension EXTENSION",
375 "Set the extension of the subscriber")
376{
377 const char *name = argv[0];
378 struct gsm_subscriber *subscr = vty->index;
379
380 strncpy(subscr->extension, name, sizeof(subscr->extension));
381
382 db_sync_subscriber(subscr);
383
384 return CMD_SUCCESS;
385}
386
387DEFUN(cfg_subscr_authorized,
388 cfg_subscr_authorized_cmd,
389 "auth <0-1>",
390 "Set the authorization status of the subscriber")
391{
392 int auth = atoi(argv[0]);
393 struct gsm_subscriber *subscr = vty->index;
394
395 if (auth)
396 subscr->authorized = 1;
397 else
398 subscr->authorized = 0;
399
400 db_sync_subscriber(subscr);
401
402 return CMD_SUCCESS;
403}
404
Sylvain Munaut99792902009-12-27 19:30:46 +0100405#define A3A8_ALG_TYPES "(none|comp128v1)"
406
407DEFUN(cfg_subscr_a3a8,
408 cfg_subscr_a3a8_cmd,
409 "a3a8 " A3A8_ALG_TYPES " [KI]",
410 "Set a3a8 parameters for the subscriber")
411{
412 struct gsm_subscriber *subscr = vty->index;
413 const char *alg_str = argv[0];
414 const char *ki_str = argv[1];
415 struct gsm_auth_info ainfo;
416 int rc;
417
418 if (!strcasecmp(alg_str, "none")) {
419 /* Just erase */
420 rc = set_authinfo_for_subscr(NULL, subscr);
421 } else if (!strcasecmp(alg_str, "comp128v1")) {
422 /* Parse hex string Ki */
423 rc = hexparse(ki_str, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
424 if (rc != 16)
425 return CMD_WARNING;
426
427 /* Set the infos */
428 ainfo.auth_algo = AUTH_ALGO_COMP128v1;
429 ainfo.a3a8_ki_len = rc;
430 rc = set_authinfo_for_subscr(&ainfo, subscr);
431 } else {
432 /* Unknown method */
433 return CMD_WARNING;
434 }
435
436 return rc ? CMD_WARNING : CMD_SUCCESS;
437}
438
Harald Weltea1482332009-11-14 10:08:40 +0100439static int scall_cbfn(unsigned int subsys, unsigned int signal,
440 void *handler_data, void *signal_data)
441{
442 struct scall_signal_data *sigdata = signal_data;
443 struct vty *vty = sigdata->data;
444
445 switch (signal) {
446 case S_SCALL_SUCCESS:
447 vty_out(vty, "%% silent call on ARFCN %u timeslot %u%s",
448 sigdata->lchan->ts->trx->arfcn, sigdata->lchan->ts->nr,
449 VTY_NEWLINE);
450 break;
451 case S_SCALL_EXPIRED:
452 vty_out(vty, "%% silent call expired paging%s", VTY_NEWLINE);
453 break;
454 }
455 return 0;
456}
457
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200458int bsc_vty_init_extra(struct gsm_network *net)
459{
460 gsmnet = net;
461
Harald Weltea1482332009-11-14 10:08:40 +0100462 register_signal_handler(SS_SCALL, scall_cbfn, NULL);
463
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200464 install_element(VIEW_NODE, &show_subscr_cmd);
465 install_element(VIEW_NODE, &show_subscr_cache_cmd);
466
467 install_element(VIEW_NODE, &sms_send_pend_cmd);
Harald Welte98f9c752009-11-14 08:00:53 +0100468
469 install_element(VIEW_NODE, &subscriber_send_sms_cmd);
470 install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
Sylvain Munaut50480702010-01-02 14:29:43 +0100471 install_element(VIEW_NODE, &subscriber_silent_call_start_cmd);
472 install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200473
474 install_element(CONFIG_NODE, &cfg_subscr_cmd);
475 install_node(&subscr_node, dummy_config_write);
476
477 install_default(SUBSCR_NODE);
478 install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
479 install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
480 install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
Sylvain Munaut99792902009-12-27 19:30:46 +0100481 install_element(SUBSCR_NODE, &cfg_subscr_a3a8_cmd);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200482
483 return 0;
484}