blob: fe107030e1c383daa4aec3d614412e7d9f968227 [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>
35#include <openbsc/gsm_04_11.h>
36#include <openbsc/e1_input.h>
37#include <openbsc/abis_nm.h>
38#include <openbsc/gsm_utils.h>
39#include <openbsc/db.h>
40#include <openbsc/talloc.h>
Harald Weltea1482332009-11-14 10:08:40 +010041#include <openbsc/signal.h>
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020042
43/* forward declarations */
44void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr);
45
46static struct gsm_network *gsmnet;
47
48struct cmd_node subscr_node = {
49 SUBSCR_NODE,
50 "%s(subscriber)#",
51 1,
52};
53
54static int dummy_config_write(struct vty *v)
55{
56 return CMD_SUCCESS;
57}
58
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020059static struct buffer *argv_to_buffer(int argc, const char *argv[], int base)
60{
61 struct buffer *b = buffer_new(1024);
62 int i;
63
64 if (!b)
65 return NULL;
66
67 for (i = base; i < argc; i++) {
68 buffer_putstr(b, argv[i]);
69 buffer_putc(b, ' ');
70 }
71 buffer_putc(b, '\0');
72
73 return b;
74}
75
76/* per-subscriber configuration */
77DEFUN(cfg_subscr,
78 cfg_subscr_cmd,
79 "subscriber IMSI",
80 "Select a Subscriber to configure\n")
81{
82 const char *imsi = argv[0];
83 struct gsm_subscriber *subscr;
84
85 subscr = subscr_get_by_imsi(gsmnet, imsi);
86 if (!subscr) {
87 vty_out(vty, "%% No subscriber for IMSI %s%s",
88 imsi, VTY_NEWLINE);
89 return CMD_WARNING;
90 }
91
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +010092 /* vty_go_parent should put this subscriber */
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020093 vty->index = subscr;
94 vty->node = SUBSCR_NODE;
95
96 return CMD_SUCCESS;
97}
98
99/* Subscriber */
100DEFUN(show_subscr,
101 show_subscr_cmd,
102 "show subscriber [IMSI]",
103 SHOW_STR "Display information about a subscriber\n")
104{
105 const char *imsi;
106 struct gsm_subscriber *subscr;
107
108 if (argc >= 1) {
109 imsi = argv[0];
110 subscr = subscr_get_by_imsi(gsmnet, imsi);
111 if (!subscr) {
112 vty_out(vty, "%% unknown subscriber%s",
113 VTY_NEWLINE);
114 return CMD_WARNING;
115 }
116 subscr_dump_vty(vty, subscr);
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +0100117 subscr_put(subscr);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200118
119 return CMD_SUCCESS;
120 }
121
122 /* FIXME: iterate over all subscribers ? */
123 return CMD_WARNING;
124
125 return CMD_SUCCESS;
126}
127
128DEFUN(show_subscr_cache,
129 show_subscr_cache_cmd,
130 "show subscriber cache",
131 SHOW_STR "Display contents of subscriber cache\n")
132{
133 struct gsm_subscriber *subscr;
134
135 llist_for_each_entry(subscr, &active_subscribers, entry) {
136 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
137 subscr_dump_vty(vty, subscr);
138 }
139
140 return CMD_SUCCESS;
141}
142
143DEFUN(sms_send_pend,
144 sms_send_pend_cmd,
145 "sms send pending MIN_ID",
146 "Send all pending SMS starting from MIN_ID")
147{
148 struct gsm_sms *sms;
149 int id = atoi(argv[0]);
150
151 while (1) {
152 sms = db_sms_get_unsent(gsmnet, id++);
153 if (!sms)
154 return CMD_WARNING;
155
156 if (!sms->receiver) {
157 sms_free(sms);
158 continue;
159 }
160
161 gsm411_send_sms_subscr(sms->receiver, sms);
162 }
163
164 return CMD_SUCCESS;
165}
166
167struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text)
168{
169 struct gsm_sms *sms = sms_alloc();
170
171 if (!sms)
172 return NULL;
173
174 if (!receiver->lac) {
175 /* subscriber currently not attached, store in database? */
176 return NULL;
177 }
178
179 sms->receiver = subscr_get(receiver);
180 strncpy(sms->text, text, sizeof(sms->text)-1);
181
182 /* FIXME: don't use ID 1 static */
183 sms->sender = subscr_get_by_id(gsmnet, 1);
184 sms->reply_path_req = 0;
185 sms->status_rep_req = 0;
186 sms->ud_hdr_ind = 0;
187 sms->protocol_id = 0; /* implicit */
188 sms->data_coding_scheme = 0; /* default 7bit */
189 strncpy(sms->dest_addr, receiver->extension, sizeof(sms->dest_addr)-1);
190 /* Generate user_data */
191 sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
192
193 return sms;
194}
195
196static int _send_sms_buffer(struct gsm_subscriber *receiver,
Harald Welte793a1352009-11-05 15:51:17 +0900197 struct buffer *b, u_int8_t tp_pid)
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200198{
199 struct gsm_sms *sms;
200
201 sms = sms_from_text(receiver, buffer_getstr(b));
Harald Welte793a1352009-11-05 15:51:17 +0900202 sms->protocol_id = tp_pid;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200203 gsm411_send_sms_subscr(receiver, sms);
204
205 return CMD_SUCCESS;
206}
207
Harald Welte98f9c752009-11-14 08:00:53 +0100208static struct gsm_subscriber *get_subscr_by_argv(const char *type,
209 const char *id)
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200210{
Harald Welte98f9c752009-11-14 08:00:53 +0100211 if (!strcmp(type, "extension"))
212 return subscr_get_by_extension(gsmnet, id);
213 else if (!strcmp(type, "imsi"))
214 return subscr_get_by_imsi(gsmnet, id);
215 else if (!strcmp(type, "tmsi"))
216 return subscr_get_by_tmsi(gsmnet, atoi(id));
217 else if (!strcmp(type, "id"))
218 return subscr_get_by_id(gsmnet, atoi(id));
219
220 return NULL;
221}
222#define SUBSCR_TYPES "(extension|imsi|tmsi|id)"
223
224DEFUN(subscriber_send_sms,
225 subscriber_send_sms_cmd,
226 "subscriber " SUBSCR_TYPES " EXTEN sms send .LINE",
227 "Select subscriber based on extension")
228{
229 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200230 struct buffer *b;
231 int rc;
232
Harald Welte20f98312009-11-14 10:11:45 +0100233 if (!subscr) {
234 vty_out(vty, "%% No subscriber found for %s %s%s",
235 argv[0], argv[1], VTY_NEWLINE);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200236 return CMD_WARNING;
Harald Welte20f98312009-11-14 10:11:45 +0100237 }
Harald Welte98f9c752009-11-14 08:00:53 +0100238 b = argv_to_buffer(argc, argv, 2);
239 rc = _send_sms_buffer(subscr, b, 0);
Harald Welte793a1352009-11-05 15:51:17 +0900240 buffer_free(b);
241
Harald Welteaf8c7b42009-11-14 10:10:54 +0100242 subscr_put(subscr);
243
Harald Welte793a1352009-11-05 15:51:17 +0900244 return rc;
245}
246
Harald Welte98f9c752009-11-14 08:00:53 +0100247DEFUN(subscriber_silent_sms,
248 subscriber_silent_sms_cmd,
249 "subscriber " SUBSCR_TYPES " EXTEN silent sms send .LINE",
250 "Select subscriber based on extension")
Harald Welte793a1352009-11-05 15:51:17 +0900251{
Harald Welte98f9c752009-11-14 08:00:53 +0100252 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
Harald Welte793a1352009-11-05 15:51:17 +0900253 struct buffer *b;
254 int rc;
255
Harald Welte20f98312009-11-14 10:11:45 +0100256 if (!subscr) {
257 vty_out(vty, "%% No subscriber found for %s %s%s",
258 argv[0], argv[1], VTY_NEWLINE);
Harald Welte793a1352009-11-05 15:51:17 +0900259 return CMD_WARNING;
Harald Welte20f98312009-11-14 10:11:45 +0100260 }
Harald Welte793a1352009-11-05 15:51:17 +0900261
Harald Welte98f9c752009-11-14 08:00:53 +0100262 b = argv_to_buffer(argc, argv, 2);
Harald Welteaf8c7b42009-11-14 10:10:54 +0100263 rc = _send_sms_buffer(subscr, b, 64);
Harald Welte793a1352009-11-05 15:51:17 +0900264 buffer_free(b);
265
Harald Welteaf8c7b42009-11-14 10:10:54 +0100266 subscr_put(subscr);
267
Harald Welte793a1352009-11-05 15:51:17 +0900268 return rc;
269}
270
Harald Weltea1482332009-11-14 10:08:40 +0100271DEFUN(subscriber_silent_call,
272 subscriber_silent_call_cmd,
273 "subscriber " SUBSCR_TYPES " EXTEN silent call (start|stop)",
274 "Send a silent call to a subscriber")
275{
276 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
277 int rc;
278
279 if (!subscr) {
280 vty_out(vty, "%% No subscriber found for %s %s%s",
Harald Welte20f98312009-11-14 10:11:45 +0100281 argv[0], argv[1], VTY_NEWLINE);
Harald Weltea1482332009-11-14 10:08:40 +0100282 return CMD_WARNING;
283 }
284
285 if (!strcmp(argv[2], "start")) {
286 rc = gsm_silent_call_start(subscr, vty);
287 if (rc <= 0) {
288 vty_out(vty, "%% Subscriber not attached%s",
289 VTY_NEWLINE);
290 return CMD_WARNING;
291 }
292 } else {
293 rc = gsm_silent_call_stop(subscr);
294 if (rc < 0)
295 return CMD_WARNING;
296 }
297
298 subscr_put(subscr);
299
300 return CMD_SUCCESS;
301}
302
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200303DEFUN(cfg_subscr_name,
304 cfg_subscr_name_cmd,
305 "name NAME",
306 "Set the name of the subscriber")
307{
308 const char *name = argv[0];
309 struct gsm_subscriber *subscr = vty->index;
310
311 strncpy(subscr->name, name, sizeof(subscr->name));
312
313 db_sync_subscriber(subscr);
314
315 return CMD_SUCCESS;
316}
317
318DEFUN(cfg_subscr_extension,
319 cfg_subscr_extension_cmd,
320 "extension EXTENSION",
321 "Set the extension of the subscriber")
322{
323 const char *name = argv[0];
324 struct gsm_subscriber *subscr = vty->index;
325
326 strncpy(subscr->extension, name, sizeof(subscr->extension));
327
328 db_sync_subscriber(subscr);
329
330 return CMD_SUCCESS;
331}
332
333DEFUN(cfg_subscr_authorized,
334 cfg_subscr_authorized_cmd,
335 "auth <0-1>",
336 "Set the authorization status of the subscriber")
337{
338 int auth = atoi(argv[0]);
339 struct gsm_subscriber *subscr = vty->index;
340
341 if (auth)
342 subscr->authorized = 1;
343 else
344 subscr->authorized = 0;
345
346 db_sync_subscriber(subscr);
347
348 return CMD_SUCCESS;
349}
350
Harald Weltea1482332009-11-14 10:08:40 +0100351static int scall_cbfn(unsigned int subsys, unsigned int signal,
352 void *handler_data, void *signal_data)
353{
354 struct scall_signal_data *sigdata = signal_data;
355 struct vty *vty = sigdata->data;
356
357 switch (signal) {
358 case S_SCALL_SUCCESS:
359 vty_out(vty, "%% silent call on ARFCN %u timeslot %u%s",
360 sigdata->lchan->ts->trx->arfcn, sigdata->lchan->ts->nr,
361 VTY_NEWLINE);
362 break;
363 case S_SCALL_EXPIRED:
364 vty_out(vty, "%% silent call expired paging%s", VTY_NEWLINE);
365 break;
366 }
367 return 0;
368}
369
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200370int bsc_vty_init_extra(struct gsm_network *net)
371{
372 gsmnet = net;
373
Harald Weltea1482332009-11-14 10:08:40 +0100374 register_signal_handler(SS_SCALL, scall_cbfn, NULL);
375
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200376 install_element(VIEW_NODE, &show_subscr_cmd);
377 install_element(VIEW_NODE, &show_subscr_cache_cmd);
378
379 install_element(VIEW_NODE, &sms_send_pend_cmd);
Harald Welte98f9c752009-11-14 08:00:53 +0100380
381 install_element(VIEW_NODE, &subscriber_send_sms_cmd);
382 install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
Harald Weltea1482332009-11-14 10:08:40 +0100383 install_element(VIEW_NODE, &subscriber_silent_call_cmd);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200384
385 install_element(CONFIG_NODE, &cfg_subscr_cmd);
386 install_node(&subscr_node, dummy_config_write);
387
388 install_default(SUBSCR_NODE);
389 install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
390 install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
391 install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
392
393 return 0;
394}