blob: 70e8445f02aacd5396a521a672634074bde0c126 [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
77/* per-subscriber configuration */
78DEFUN(cfg_subscr,
79 cfg_subscr_cmd,
80 "subscriber IMSI",
81 "Select a Subscriber to configure\n")
82{
83 const char *imsi = argv[0];
84 struct gsm_subscriber *subscr;
85
86 subscr = subscr_get_by_imsi(gsmnet, imsi);
87 if (!subscr) {
88 vty_out(vty, "%% No subscriber for IMSI %s%s",
89 imsi, VTY_NEWLINE);
90 return CMD_WARNING;
91 }
92
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +010093 /* vty_go_parent should put this subscriber */
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +020094 vty->index = subscr;
95 vty->node = SUBSCR_NODE;
96
97 return CMD_SUCCESS;
98}
99
100/* Subscriber */
101DEFUN(show_subscr,
102 show_subscr_cmd,
103 "show subscriber [IMSI]",
104 SHOW_STR "Display information about a subscriber\n")
105{
106 const char *imsi;
107 struct gsm_subscriber *subscr;
108
109 if (argc >= 1) {
110 imsi = argv[0];
111 subscr = subscr_get_by_imsi(gsmnet, imsi);
112 if (!subscr) {
113 vty_out(vty, "%% unknown subscriber%s",
114 VTY_NEWLINE);
115 return CMD_WARNING;
116 }
117 subscr_dump_vty(vty, subscr);
Holger Hans Peter Freythere33966c2009-10-27 12:47:06 +0100118 subscr_put(subscr);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200119
120 return CMD_SUCCESS;
121 }
122
123 /* FIXME: iterate over all subscribers ? */
124 return CMD_WARNING;
125
126 return CMD_SUCCESS;
127}
128
129DEFUN(show_subscr_cache,
130 show_subscr_cache_cmd,
131 "show subscriber cache",
132 SHOW_STR "Display contents of subscriber cache\n")
133{
134 struct gsm_subscriber *subscr;
135
136 llist_for_each_entry(subscr, &active_subscribers, entry) {
137 vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
138 subscr_dump_vty(vty, subscr);
139 }
140
141 return CMD_SUCCESS;
142}
143
144DEFUN(sms_send_pend,
145 sms_send_pend_cmd,
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100146 "sms send pending",
147 "Send all pending SMS")
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200148{
149 struct gsm_sms *sms;
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100150 int id = 0;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200151
152 while (1) {
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100153 sms = db_sms_get_unsent_by_subscr(gsmnet, id);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200154 if (!sms)
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100155 break;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200156
157 gsm411_send_sms_subscr(sms->receiver, sms);
Sylvain Munautff1f19e2009-12-22 13:22:29 +0100158
159 id = sms->receiver->id + 1;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200160 }
161
162 return CMD_SUCCESS;
163}
164
165struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text)
166{
167 struct gsm_sms *sms = sms_alloc();
168
169 if (!sms)
170 return NULL;
171
172 if (!receiver->lac) {
173 /* subscriber currently not attached, store in database? */
174 return NULL;
175 }
176
177 sms->receiver = subscr_get(receiver);
178 strncpy(sms->text, text, sizeof(sms->text)-1);
179
180 /* FIXME: don't use ID 1 static */
181 sms->sender = subscr_get_by_id(gsmnet, 1);
182 sms->reply_path_req = 0;
183 sms->status_rep_req = 0;
184 sms->ud_hdr_ind = 0;
185 sms->protocol_id = 0; /* implicit */
186 sms->data_coding_scheme = 0; /* default 7bit */
187 strncpy(sms->dest_addr, receiver->extension, sizeof(sms->dest_addr)-1);
188 /* Generate user_data */
189 sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
190
191 return sms;
192}
193
194static int _send_sms_buffer(struct gsm_subscriber *receiver,
Harald Welte793a1352009-11-05 15:51:17 +0900195 struct buffer *b, u_int8_t tp_pid)
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200196{
197 struct gsm_sms *sms;
198
199 sms = sms_from_text(receiver, buffer_getstr(b));
Harald Welte793a1352009-11-05 15:51:17 +0900200 sms->protocol_id = tp_pid;
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200201 gsm411_send_sms_subscr(receiver, sms);
202
203 return CMD_SUCCESS;
204}
205
Harald Welte98f9c752009-11-14 08:00:53 +0100206static struct gsm_subscriber *get_subscr_by_argv(const char *type,
207 const char *id)
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200208{
Harald Welte98f9c752009-11-14 08:00:53 +0100209 if (!strcmp(type, "extension"))
210 return subscr_get_by_extension(gsmnet, id);
211 else if (!strcmp(type, "imsi"))
212 return subscr_get_by_imsi(gsmnet, id);
213 else if (!strcmp(type, "tmsi"))
214 return subscr_get_by_tmsi(gsmnet, atoi(id));
215 else if (!strcmp(type, "id"))
216 return subscr_get_by_id(gsmnet, atoi(id));
217
218 return NULL;
219}
220#define SUBSCR_TYPES "(extension|imsi|tmsi|id)"
221
222DEFUN(subscriber_send_sms,
223 subscriber_send_sms_cmd,
224 "subscriber " SUBSCR_TYPES " EXTEN sms send .LINE",
225 "Select subscriber based on extension")
226{
227 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200228 struct buffer *b;
229 int rc;
230
Harald Welte20f98312009-11-14 10:11:45 +0100231 if (!subscr) {
232 vty_out(vty, "%% No subscriber found for %s %s%s",
233 argv[0], argv[1], VTY_NEWLINE);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200234 return CMD_WARNING;
Harald Welte20f98312009-11-14 10:11:45 +0100235 }
Harald Welte98f9c752009-11-14 08:00:53 +0100236 b = argv_to_buffer(argc, argv, 2);
237 rc = _send_sms_buffer(subscr, b, 0);
Harald Welte793a1352009-11-05 15:51:17 +0900238 buffer_free(b);
239
Harald Welteaf8c7b42009-11-14 10:10:54 +0100240 subscr_put(subscr);
241
Harald Welte793a1352009-11-05 15:51:17 +0900242 return rc;
243}
244
Harald Welte98f9c752009-11-14 08:00:53 +0100245DEFUN(subscriber_silent_sms,
246 subscriber_silent_sms_cmd,
247 "subscriber " SUBSCR_TYPES " EXTEN silent sms send .LINE",
248 "Select subscriber based on extension")
Harald Welte793a1352009-11-05 15:51:17 +0900249{
Harald Welte98f9c752009-11-14 08:00:53 +0100250 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
Harald Welte793a1352009-11-05 15:51:17 +0900251 struct buffer *b;
252 int rc;
253
Harald Welte20f98312009-11-14 10:11:45 +0100254 if (!subscr) {
255 vty_out(vty, "%% No subscriber found for %s %s%s",
256 argv[0], argv[1], VTY_NEWLINE);
Harald Welte793a1352009-11-05 15:51:17 +0900257 return CMD_WARNING;
Harald Welte20f98312009-11-14 10:11:45 +0100258 }
Harald Welte793a1352009-11-05 15:51:17 +0900259
Harald Welte98f9c752009-11-14 08:00:53 +0100260 b = argv_to_buffer(argc, argv, 2);
Harald Welteaf8c7b42009-11-14 10:10:54 +0100261 rc = _send_sms_buffer(subscr, b, 64);
Harald Welte793a1352009-11-05 15:51:17 +0900262 buffer_free(b);
263
Harald Welteaf8c7b42009-11-14 10:10:54 +0100264 subscr_put(subscr);
265
Harald Welte793a1352009-11-05 15:51:17 +0900266 return rc;
267}
268
Harald Weltea1482332009-11-14 10:08:40 +0100269DEFUN(subscriber_silent_call,
270 subscriber_silent_call_cmd,
271 "subscriber " SUBSCR_TYPES " EXTEN silent call (start|stop)",
272 "Send a silent call to a subscriber")
273{
274 struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
275 int rc;
276
277 if (!subscr) {
278 vty_out(vty, "%% No subscriber found for %s %s%s",
Harald Welte20f98312009-11-14 10:11:45 +0100279 argv[0], argv[1], VTY_NEWLINE);
Harald Weltea1482332009-11-14 10:08:40 +0100280 return CMD_WARNING;
281 }
282
283 if (!strcmp(argv[2], "start")) {
284 rc = gsm_silent_call_start(subscr, vty);
285 if (rc <= 0) {
286 vty_out(vty, "%% Subscriber not attached%s",
287 VTY_NEWLINE);
288 return CMD_WARNING;
289 }
290 } else {
291 rc = gsm_silent_call_stop(subscr);
292 if (rc < 0)
293 return CMD_WARNING;
294 }
295
296 subscr_put(subscr);
297
298 return CMD_SUCCESS;
299}
300
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200301DEFUN(cfg_subscr_name,
302 cfg_subscr_name_cmd,
303 "name NAME",
304 "Set the name of the subscriber")
305{
306 const char *name = argv[0];
307 struct gsm_subscriber *subscr = vty->index;
308
309 strncpy(subscr->name, name, sizeof(subscr->name));
310
311 db_sync_subscriber(subscr);
312
313 return CMD_SUCCESS;
314}
315
316DEFUN(cfg_subscr_extension,
317 cfg_subscr_extension_cmd,
318 "extension EXTENSION",
319 "Set the extension of the subscriber")
320{
321 const char *name = argv[0];
322 struct gsm_subscriber *subscr = vty->index;
323
324 strncpy(subscr->extension, name, sizeof(subscr->extension));
325
326 db_sync_subscriber(subscr);
327
328 return CMD_SUCCESS;
329}
330
331DEFUN(cfg_subscr_authorized,
332 cfg_subscr_authorized_cmd,
333 "auth <0-1>",
334 "Set the authorization status of the subscriber")
335{
336 int auth = atoi(argv[0]);
337 struct gsm_subscriber *subscr = vty->index;
338
339 if (auth)
340 subscr->authorized = 1;
341 else
342 subscr->authorized = 0;
343
344 db_sync_subscriber(subscr);
345
346 return CMD_SUCCESS;
347}
348
Harald Weltea1482332009-11-14 10:08:40 +0100349static int scall_cbfn(unsigned int subsys, unsigned int signal,
350 void *handler_data, void *signal_data)
351{
352 struct scall_signal_data *sigdata = signal_data;
353 struct vty *vty = sigdata->data;
354
355 switch (signal) {
356 case S_SCALL_SUCCESS:
357 vty_out(vty, "%% silent call on ARFCN %u timeslot %u%s",
358 sigdata->lchan->ts->trx->arfcn, sigdata->lchan->ts->nr,
359 VTY_NEWLINE);
360 break;
361 case S_SCALL_EXPIRED:
362 vty_out(vty, "%% silent call expired paging%s", VTY_NEWLINE);
363 break;
364 }
365 return 0;
366}
367
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200368int bsc_vty_init_extra(struct gsm_network *net)
369{
370 gsmnet = net;
371
Harald Weltea1482332009-11-14 10:08:40 +0100372 register_signal_handler(SS_SCALL, scall_cbfn, NULL);
373
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200374 install_element(VIEW_NODE, &show_subscr_cmd);
375 install_element(VIEW_NODE, &show_subscr_cache_cmd);
376
377 install_element(VIEW_NODE, &sms_send_pend_cmd);
Harald Welte98f9c752009-11-14 08:00:53 +0100378
379 install_element(VIEW_NODE, &subscriber_send_sms_cmd);
380 install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
Harald Weltea1482332009-11-14 10:08:40 +0100381 install_element(VIEW_NODE, &subscriber_silent_call_cmd);
Holger Hans Peter Freythercfa90d42009-08-10 10:17:50 +0200382
383 install_element(CONFIG_NODE, &cfg_subscr_cmd);
384 install_node(&subscr_node, dummy_config_write);
385
386 install_default(SUBSCR_NODE);
387 install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
388 install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
389 install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
390
391 return 0;
392}