Merge commit 'af5ee34c353ea2868a4b04b227bc1b511e1ac42b'
[osmocom-bb.git] / src / host / layer23 / src / mobile / vty_interface.c
1 /*
2  * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
3  *
4  * 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 <string.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27
28 #include <osmocore/gsm48.h>
29
30 #include <osmocom/bb/common/osmocom_data.h>
31 #include <osmocom/bb/common/networks.h>
32 #include <osmocom/bb/mobile/mncc.h>
33 #include <osmocom/bb/mobile/transaction.h>
34 #include <osmocom/bb/mobile/vty.h>
35 #include <osmocom/bb/mobile/gps.h>
36 #include <osmocom/vty/telnet_interface.h>
37
38 int mncc_call(struct osmocom_ms *ms, char *number);
39 int mncc_hangup(struct osmocom_ms *ms);
40 int mncc_answer(struct osmocom_ms *ms);
41 int mncc_hold(struct osmocom_ms *ms);
42 int mncc_retrieve(struct osmocom_ms *ms, int number);
43
44 extern struct llist_head ms_list;
45 extern struct llist_head active_connections;
46
47 struct cmd_node ms_node = {
48         MS_NODE,
49         "%s(ms)#",
50         1
51 };
52
53 struct cmd_node testsim_node = {
54         TESTSIM_NODE,
55         "%s(test-sim)#",
56         1
57 };
58
59 static void print_vty(void *priv, const char *fmt, ...)
60 {
61         char buffer[1000];
62         struct vty *vty = priv;
63         va_list args;
64
65         va_start(args, fmt);
66         vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
67         buffer[sizeof(buffer) - 1] = '\0';
68         va_end(args);
69
70         if (buffer[0]) {
71                 if (buffer[strlen(buffer) - 1] == '\n') {
72                         buffer[strlen(buffer) - 1] = '\0';
73                         vty_out(vty, "%s%s", buffer, VTY_NEWLINE);
74                 } else
75                         vty_out(vty, "%s", buffer);
76         }
77 }
78
79 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
80 {
81         struct osmocom_ms *ms;
82
83         llist_for_each_entry(ms, &ms_list, entity) {
84                 if (!strcmp(ms->name, name))
85                         return ms;
86         }
87         vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
88
89         return NULL;
90 }
91
92 DEFUN(show_ms, show_ms_cmd, "show ms",
93         SHOW_STR "Display available MS entities\n")
94 {
95         struct osmocom_ms *ms;
96
97         llist_for_each_entry(ms, &ms_list, entity) {
98                 struct gsm_settings *set = &ms->settings;
99
100                 vty_out(vty, "MS NAME: %s%s", ms->name, VTY_NEWLINE);
101                 vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE);
102                 vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE);
103                 if (set->imei_random)
104                         vty_out(vty, " IMEI generation: random (%d trailing "
105                                 "digits)%s", set->imei_random, VTY_NEWLINE);
106                 else
107                         vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE);
108                 vty_out(vty, " network selection mode: %s%s",
109                         (set->plmn_mode == PLMN_MODE_AUTO)
110                                 ? "automatic" : "manual", VTY_NEWLINE);
111         }
112
113         return CMD_SUCCESS;
114 }
115
116 DEFUN(show_support, show_support_cmd, "show support [ms_name]",
117         SHOW_STR "Display information about MS support\n"
118         "Name of MS (see \"show ms\")")
119 {
120         struct osmocom_ms *ms;
121
122         if (argc) {
123                 ms = get_ms(argv[0], vty);
124                 if (!ms)
125                         return CMD_WARNING;
126                 gsm_support_dump(&ms->support, print_vty, vty);
127         } else {
128                 llist_for_each_entry(ms, &ms_list, entity) {
129                         gsm_support_dump(&ms->support, print_vty, vty);
130                         vty_out(vty, "%s", VTY_NEWLINE);
131                 }
132         }
133
134         return CMD_SUCCESS;
135 }
136
137 static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty)
138 {
139         struct gsm_trans *trans;
140
141         vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE);
142         if (ms->settings.plmn_mode == PLMN_MODE_AUTO)
143                 vty_out(vty, " automatic network selection: %s%s", 
144                         plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
145         else
146                 vty_out(vty, " manual network selection: %s%s", 
147                         plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
148         vty_out(vty, " cell selection: %s%s", 
149                 cs_state_names[ms->cellsel.state], VTY_NEWLINE);
150         vty_out(vty, " radio ressource layer: %s%s", 
151                 gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
152         vty_out(vty, " mobility management layer: %s", 
153                 gsm48_mm_state_names[ms->mmlayer.state]);
154         if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
155                 vty_out(vty, ", %s", 
156                         gsm48_mm_substate_names[ms->mmlayer.substate]);
157         vty_out(vty, "%s", VTY_NEWLINE);
158         llist_for_each_entry(trans, &ms->trans_list, entry) {
159                 vty_out(vty, " call control: %s%s", 
160                         gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
161         }
162 }
163
164 DEFUN(show_states, show_states_cmd, "show states [ms_name]",
165         SHOW_STR "Display current states of given MS\n"
166         "Name of MS (see \"show ms\")")
167 {
168         struct osmocom_ms *ms;
169
170         if (argc) {
171                 ms = get_ms(argv[0], vty);
172                 if (!ms)
173                         return CMD_WARNING;
174                 gsm_states_dump(ms, vty);
175         } else {
176                 llist_for_each_entry(ms, &ms_list, entity) {
177                         gsm_states_dump(ms, vty);
178                         vty_out(vty, "%s", VTY_NEWLINE);
179                 }
180         }
181
182         return CMD_SUCCESS;
183 }
184
185 DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]",
186         SHOW_STR "Display information about subscriber\n"
187         "Name of MS (see \"show ms\")")
188 {
189         struct osmocom_ms *ms;
190
191         if (argc) {
192                 ms = get_ms(argv[0], vty);
193                 if (!ms)
194                         return CMD_WARNING;
195                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
196         } else {
197                 llist_for_each_entry(ms, &ms_list, entity) {
198                         gsm_subscr_dump(&ms->subscr, print_vty, vty);
199                         vty_out(vty, "%s", VTY_NEWLINE);
200                 }
201         }
202
203         return CMD_SUCCESS;
204 }
205
206 DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
207         SHOW_STR "Display information about received cells\n"
208         "Name of MS (see \"show ms\")")
209 {
210         struct osmocom_ms *ms;
211
212         ms = get_ms(argv[0], vty);
213         if (!ms)
214                 return CMD_WARNING;
215
216         gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
217                 vty);
218
219         return CMD_SUCCESS;
220 }
221
222 DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>",
223         SHOW_STR "Display information about received cell\n"
224         "Name of MS (see \"show ms\")\nRadio frequency number")
225 {
226         struct osmocom_ms *ms;
227         int i;
228         struct gsm48_sysinfo *s;
229
230         ms = get_ms(argv[0], vty);
231         if (!ms)
232                 return CMD_WARNING;
233
234         i = atoi(argv[1]);
235         if (i < 0 || i > 1023) {
236                 vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s",
237                         argv[1], VTY_NEWLINE);
238                 return CMD_WARNING;
239         }
240         s = ms->cellsel.list[i].sysinfo;
241         if (!s) {
242                 vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s",
243                         argv[1], VTY_NEWLINE);
244                 return CMD_SUCCESS;
245         }
246
247         gsm48_sysinfo_dump(s, i, print_vty, vty);
248
249         return CMD_SUCCESS;
250 }
251
252 DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]",
253         SHOW_STR "Display information about band allocations\n"
254         "Name of MS (see \"show ms\")\nMobile Country Code\n"
255         "Mobile Network Code")
256 {
257         struct osmocom_ms *ms;
258         uint16_t mcc = 0, mnc = 0;
259
260         ms = get_ms(argv[0], vty);
261         if (!ms)
262                 return CMD_WARNING;
263
264         if (argc >= 3) {
265                 mcc = gsm_input_mcc((char *)argv[1]);
266                 mnc = gsm_input_mnc((char *)argv[2]);
267                 if (!mcc) {
268                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
269                         return CMD_WARNING;
270                 }
271                 if (!mnc) {
272                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
273                         return CMD_WARNING;
274                 }
275         }
276
277         gsm322_dump_ba_list(&ms->cellsel, mcc, mnc, print_vty, vty);
278
279         return CMD_SUCCESS;
280 }
281
282 DEFUN(show_forb_plmn, show_forb_plmn_cmd, "show forbidden plmn MS_NAME",
283         SHOW_STR "Display information about forbidden cells / networks\n"
284         "Display forbidden PLMNs\nName of MS (see \"show ms\")")
285 {
286         struct osmocom_ms *ms;
287
288         ms = get_ms(argv[0], vty);
289         if (!ms)
290                 return CMD_WARNING;
291
292         gsm_subscr_dump_forbidden_plmn(ms, print_vty, vty);
293
294         return CMD_SUCCESS;
295 }
296
297 DEFUN(show_forb_la, show_forb_la_cmd, "show forbidden location-area MS_NAME",
298         SHOW_STR "Display information about forbidden cells / networks\n"
299         "Display forbidden location areas\nName of MS (see \"show ms\")")
300 {
301         struct osmocom_ms *ms;
302
303         ms = get_ms(argv[0], vty);
304         if (!ms)
305                 return CMD_WARNING;
306
307         gsm322_dump_forbidden_la(ms, print_vty, vty);
308
309         return CMD_SUCCESS;
310 }
311
312 DEFUN(monitor_network, monitor_network_cmd, "monitor network MS_NAME",
313         "Monitor...\nMonitor network information\nName of MS (see \"show ms\")")
314 {
315         struct osmocom_ms *ms;
316
317         ms = get_ms(argv[0], vty);
318         if (!ms)
319                 return CMD_WARNING;
320
321         gsm48_rr_start_monitor(ms);
322
323         return CMD_SUCCESS;
324 }
325
326 DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME",
327         NO_STR "Monitor...\nDeactivate monitor of network information\n"
328         "Name of MS (see \"show ms\")")
329 {
330         struct osmocom_ms *ms;
331
332         ms = get_ms(argv[0], vty);
333         if (!ms)
334                 return CMD_WARNING;
335
336         gsm48_rr_stop_monitor(ms);
337
338         return CMD_SUCCESS;
339 }
340
341 DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]",
342         "SIM actions\nInsert test card\nName of MS (see \"show ms\")\n"
343         "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN")
344 {
345         struct osmocom_ms *ms;
346         uint16_t mcc = 0x001, mnc = 0x01f;
347
348         ms = get_ms(argv[0], vty);
349         if (!ms)
350                 return CMD_WARNING;
351
352         if (ms->subscr.sim_valid) {
353                 vty_out(vty, "SIM already presend, remove first!%s",
354                         VTY_NEWLINE);
355                 return CMD_WARNING;
356         }
357
358         if (argc >= 3) {
359                 mcc = gsm_input_mcc((char *)argv[1]);
360                 mnc = gsm_input_mnc((char *)argv[2]);
361                 if (!mcc) {
362                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
363                         return CMD_WARNING;
364                 }
365                 if (!mnc) {
366                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
367                         return CMD_WARNING;
368                 }
369         }
370
371         gsm_subscr_testcard(ms, mcc, mnc);
372
373         return CMD_SUCCESS;
374 }
375
376 DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
377         "SIM actions\nSelect SIM from reader\nName of MS (see \"show ms\")")
378 {
379         struct osmocom_ms *ms;
380
381         ms = get_ms(argv[0], vty);
382         if (!ms)
383                 return CMD_WARNING;
384
385         if (ms->subscr.sim_valid) {
386                 vty_out(vty, "SIM already presend, remove first!%s",
387                         VTY_NEWLINE);
388                 return CMD_WARNING;
389         }
390
391         gsm_subscr_simcard(ms);
392
393         return CMD_SUCCESS;
394 }
395
396 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
397         "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")")
398 {
399         struct osmocom_ms *ms;
400
401         ms = get_ms(argv[0], vty);
402         if (!ms)
403                 return CMD_WARNING;
404
405         if (!ms->subscr.sim_valid) {
406                 vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
407                 return CMD_WARNING;
408         }
409
410         gsm_subscr_remove(ms);
411
412         return CMD_SUCCESS;
413 }
414
415 DEFUN(sim_pin, sim_pin_cmd, "sim pin MS_NAME PIN",
416         "SIM actions\nEnter PIN for SIM card\nName of MS (see \"show ms\")\n"
417         "PIN number")
418 {
419         struct osmocom_ms *ms;
420
421         ms = get_ms(argv[0], vty);
422         if (!ms)
423                 return CMD_WARNING;
424
425         if (!ms->subscr.sim_pin_required) {
426                 vty_out(vty, "No PIN is required at this time!%s", VTY_NEWLINE);
427                 return CMD_WARNING;
428         }
429
430         gsm_subscr_sim_pin(ms, (char *)argv[1]);
431
432         return CMD_SUCCESS;
433 }
434
435 DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
436         "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
437         "Mobile Country Code\nMobile Network Code")
438 {
439         struct osmocom_ms *ms;
440         struct gsm322_plmn *plmn;
441         struct msgb *nmsg;
442         struct gsm322_msg *ngm;
443         struct gsm322_plmn_list *temp;
444         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
445                  mnc = gsm_input_mnc((char *)argv[2]);
446         int found = 0;
447
448         ms = get_ms(argv[0], vty);
449         if (!ms)
450                 return CMD_WARNING;
451         plmn = &ms->plmn;
452
453         if (!mcc) {
454                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
455                 return CMD_WARNING;
456         }
457         if (!mnc) {
458                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
459                 return CMD_WARNING;
460         }
461
462         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
463                 if (temp->mcc == mcc &&  temp->mnc == mnc)
464                         found = 1;
465         if (!found) {
466                 vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
467                 return CMD_WARNING;
468         }
469
470         nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
471         if (!nmsg)
472                 return CMD_WARNING;
473         ngm = (struct gsm322_msg *) nmsg->data;
474         ngm->mcc = mcc;
475         ngm->mnc = mnc;
476         gsm322_plmn_sendmsg(ms, nmsg);
477
478         return CMD_SUCCESS;
479 }
480
481 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
482         "Make a call\nName of MS (see \"show ms\")\nPhone number to call\n"
483         "Make an emergency call\nAnswer an incomming call\nHangup a call\n"
484         "Hold current active call\n")
485 {
486         struct osmocom_ms *ms;
487
488         ms = get_ms(argv[0], vty);
489         if (!ms)
490                 return CMD_WARNING;
491
492         switch (argv[1][0]) {
493         case 'a':
494                 mncc_answer(ms);
495                 break;
496         case 'h':
497                 if (argv[1][1] == 'a')
498                         mncc_hangup(ms);
499                 else
500                         mncc_hold(ms);
501                 break;
502         default:
503                 mncc_call(ms, (char *)argv[1]);
504         }
505
506         return CMD_SUCCESS;
507 }
508
509 DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]",
510         "Make a call\nName of MS (see \"show ms\")\n"
511         "Retrieve call on hold\nNumber of call to retrieve")
512 {
513         struct osmocom_ms *ms;
514
515         ms = get_ms(argv[0], vty);
516         if (!ms)
517                 return CMD_WARNING;
518
519         mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
520
521         return CMD_SUCCESS;
522 }
523
524 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
525         "Network ...\nShow results of network search (again)\n"
526         "Name of MS (see \"show ms\")")
527 {
528         struct osmocom_ms *ms;
529         struct gsm322_plmn *plmn;
530         struct gsm322_plmn_list *temp;
531
532         ms = get_ms(argv[0], vty);
533         if (!ms)
534                 return CMD_WARNING;
535         plmn = &ms->plmn;
536
537         if (ms->settings.plmn_mode != PLMN_MODE_AUTO
538          && plmn->state != GSM322_M3_NOT_ON_PLMN) {
539                 vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
540                 return CMD_WARNING;
541         }
542
543         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
544                 vty_out(vty, " Network %s, %s (%s, %s)%s",
545                         gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
546                         gsm_get_mcc(temp->mcc),
547                         gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
548
549         return CMD_SUCCESS;
550 }
551
552 DEFUN(network_search, network_search_cmd, "network search MS_NAME",
553         "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
554 {
555         struct osmocom_ms *ms;
556         struct msgb *nmsg;
557
558         ms = get_ms(argv[0], vty);
559         if (!ms)
560                 return CMD_WARNING;
561
562         nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
563         if (!nmsg)
564                 return CMD_WARNING;
565         gsm322_plmn_sendmsg(ms, nmsg);
566
567         return CMD_SUCCESS;
568 }
569
570 DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable",
571         "GPS receiver")
572 {
573         if (gps_open()) {
574                 gps.enable = 1;
575                 vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE);
576                 return CMD_WARNING;
577         }
578         gps.enable = 1;
579
580         return CMD_SUCCESS;
581 }
582
583 DEFUN(cfg_no_gps_enable, cfg_no_gps_enable_cmd, "no gps enable",
584         NO_STR "Disable GPS receiver")
585 {
586         if (gps.enable)
587                 gps_close();
588         gps.enable = 0;
589
590         return CMD_SUCCESS;
591 }
592
593 DEFUN(cfg_gps_device, cfg_gps_device_cmd, "gps device DEVICE",
594         "GPS receiver\nSelect serial device\n"
595         "Full path of serial device including /dev/")
596 {
597         strncpy(gps.device, argv[0], sizeof(gps.device));
598         gps.device[sizeof(gps.device) - 1] = '\0';
599         if (gps.enable) {
600                 gps_close();
601                 if (gps_open()) {
602                         vty_out(vty, "Failed to open GPS device!%s",
603                                 VTY_NEWLINE);
604                         return CMD_WARNING;
605                 }
606         }
607
608         return CMD_SUCCESS;
609 }
610
611 DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate "
612         "(default|4800|""9600|19200|38400|57600|115200)",
613         "GPS receiver\nSelect baud rate\nDefault, don't modify\n\n\n\n\n\n")
614 {
615         if (argv[0][0] == 'd')
616                 gps.baud = 0;
617         else
618                 gps.baud = atoi(argv[0]);
619         if (gps.enable) {
620                 gps_close();
621                 if (gps_open()) {
622                         gps.enable = 0;
623                         vty_out(vty, "Failed to open GPS device!%s",
624                                 VTY_NEWLINE);
625                         return CMD_WARNING;
626                 }
627         }
628
629         return CMD_SUCCESS;
630 }
631
632 /* per MS config */
633 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
634         "Select a mobile station to configure\nName of MS (see \"show ms\")")
635 {
636         struct osmocom_ms *ms;
637
638         ms = get_ms(argv[0], vty);
639         if (!ms)
640                 return CMD_WARNING;
641
642         vty->index = ms;
643         vty->node = MS_NODE;
644
645         return CMD_SUCCESS;
646 }
647
648 static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
649 {
650         struct gsm_settings *set = &ms->settings;
651
652         vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
653         switch(set->sim_type) {
654                 case GSM_SIM_TYPE_NONE:
655                 vty_out(vty, " sim none%s", VTY_NEWLINE);
656                 break;
657                 case GSM_SIM_TYPE_READER:
658                 vty_out(vty, " sim reader%s", VTY_NEWLINE);
659                 break;
660                 case GSM_SIM_TYPE_TEST:
661                 vty_out(vty, " sim test%s", VTY_NEWLINE);
662                 break;
663         }
664         vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
665                         == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
666         vty_out(vty, " imei %s %s%s", set->imei,
667                 set->imeisv + strlen(set->imei), VTY_NEWLINE);
668         if (set->imei_random)
669                 vty_out(vty, " imei-random %d%s", set->imei_random,
670                         VTY_NEWLINE);
671         else
672                 vty_out(vty, " imei-fixed%s", VTY_NEWLINE);
673         if (set->emergency_imsi[0])
674                 vty_out(vty, " emergency-imsi %s%s", set->emergency_imsi,
675                         VTY_NEWLINE);
676         else
677                 vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE);
678         vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE);
679         vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE);
680         vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE);
681         vty_out(vty, " test-sim%s", VTY_NEWLINE);
682         vty_out(vty, "  imsi %s%s", set->test_imsi, VTY_NEWLINE);
683         vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
684                 VTY_NEWLINE);
685         if (set->test_rplmn_valid)
686                 vty_out(vty, "  rplmn %s %s%s",
687                         gsm_print_mcc(set->test_rplmn_mcc),
688                         gsm_print_mnc(set->test_rplmn_mnc),
689                         VTY_NEWLINE);
690         else
691                 vty_out(vty, "  no rplmn%s", VTY_NEWLINE);
692         vty_out(vty, "  hplmn-search %s%s", (set->test_always) ? "everywhere"
693                         : "foreign-country", VTY_NEWLINE);
694         vty_out(vty, " exit%s", VTY_NEWLINE);
695         if (set->alter_tx_power)
696                 if (set->alter_tx_power_value)
697                         vty_out(vty, " tx-power %d%s",
698                                 set->alter_tx_power_value, VTY_NEWLINE);
699                 else
700                         vty_out(vty, " tx-power full%s", VTY_NEWLINE);
701         else
702                 vty_out(vty, " tx-power auto%s", VTY_NEWLINE);
703         if (set->alter_delay)
704                 vty_out(vty, " simulated-delay %d%s", set->alter_delay,
705                         VTY_NEWLINE);
706         else
707                 vty_out(vty, " no simulated-delay%s", VTY_NEWLINE);
708         if (set->stick)
709                 vty_out(vty, " stick %d%s", set->stick_arfcn,
710                         VTY_NEWLINE);
711         else
712                 vty_out(vty, " no stick%s", VTY_NEWLINE);
713         if (set->no_lupd)
714                 vty_out(vty, " no location-updating%s", VTY_NEWLINE);
715         else
716                 vty_out(vty, " location-updating%s", VTY_NEWLINE);
717         vty_out(vty, "exit%s", VTY_NEWLINE);
718         vty_out(vty, "!%s", VTY_NEWLINE);
719 }
720
721 static int config_write_ms(struct vty *vty)
722 {
723         struct osmocom_ms *ms;
724
725         vty_out(vty, "gps device %s%s", gps.device, VTY_NEWLINE);
726         if (gps.baud)
727                 vty_out(vty, "gps baudrate %d%s", gps.baud, VTY_NEWLINE);
728         else
729                 vty_out(vty, "gps baudrate default%s", VTY_NEWLINE);
730         vty_out(vty, "%sgps enable%s", (gps.enable) ? "" : "no ", VTY_NEWLINE);
731         vty_out(vty, "!%s", VTY_NEWLINE);
732
733         llist_for_each_entry(ms, &ms_list, entity)
734                 config_write_ms_single(vty, ms);
735
736         return CMD_SUCCESS;
737 }
738
739 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)",
740         "Set SIM card type when powering on\nNo SIM interted\n"
741         "Use SIM from reader\nTest SIM inserted")
742 {
743         struct osmocom_ms *ms = vty->index;
744
745         switch (argv[0][0]) {
746         case 'n':
747                 ms->settings.sim_type = GSM_SIM_TYPE_NONE;
748                 break;
749         case 'r':
750                 ms->settings.sim_type = GSM_SIM_TYPE_READER;
751                 break;
752         case 't':
753                 ms->settings.sim_type = GSM_SIM_TYPE_TEST;
754                 break;
755         default:
756                 vty_out(vty, "unknown SIM type%s", VTY_NEWLINE);
757                 return CMD_WARNING;
758         }
759
760         return CMD_SUCCESS;
761 }
762
763 DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
764         "Set network selection mode\nAutomatic network selection\n"
765         "Manual network selection")
766 {
767         struct osmocom_ms *ms = vty->index;
768         struct msgb *nmsg;
769
770         if (!ms->plmn.state) {
771                 if (argv[0][0] == 'a')
772                         ms->settings.plmn_mode = PLMN_MODE_AUTO;
773                 else
774                         ms->settings.plmn_mode = PLMN_MODE_MANUAL;
775
776                 return CMD_SUCCESS;
777         }
778         if (argv[0][0] == 'a')
779                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
780         else
781                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
782         if (!nmsg)
783                 return CMD_WARNING;
784         gsm322_plmn_sendmsg(ms, nmsg);
785
786         return CMD_SUCCESS;
787 }
788
789 DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
790         "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
791         "Software version digit")
792 {
793         struct osmocom_ms *ms = vty->index;
794         char *error, *sv = "0";
795
796         if (argc >= 2)
797                 sv = (char *)argv[1];
798
799         error = gsm_check_imei(argv[0], sv);
800         if (error) {
801                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
802                 return CMD_WARNING;
803         }
804
805         strcpy(ms->settings.imei, argv[0]);
806         strcpy(ms->settings.imeisv, argv[0]);
807         strcpy(ms->settings.imeisv + 15, sv);
808
809         return CMD_SUCCESS;
810 }
811
812 DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
813         "Use fixed IMEI on every power on")
814 {
815         struct osmocom_ms *ms = vty->index;
816
817         ms->settings.imei_random = 0;
818
819         return CMD_SUCCESS;
820 }
821
822 DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
823         "Use random IMEI on every power on\n"
824         "Number of trailing digits to randomize")
825 {
826         struct osmocom_ms *ms = vty->index;
827
828         ms->settings.imei_random = atoi(argv[0]);
829
830         return CMD_SUCCESS;
831 }
832
833 DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi IMSI",
834         "Use special IMSI for emergency calls\n15 digits IMSI")
835 {
836         struct osmocom_ms *ms = vty->index;
837         char *error;
838
839         error = gsm_check_imsi(argv[0]);
840         if (error) {
841                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
842                 return CMD_WARNING;
843         }
844         strcpy(ms->settings.emergency_imsi, argv[0]);
845
846         return CMD_SUCCESS;
847 }
848
849 DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
850         NO_STR "Use IMSI of SIM or IMEI for emergency calls")
851 {
852         struct osmocom_ms *ms = vty->index;
853
854         ms->settings.emergency_imsi[0] = '\0';
855
856         return CMD_SUCCESS;
857 }
858
859 DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
860         NO_STR "Disallow waiting calls")
861 {
862         struct osmocom_ms *ms = vty->index;
863
864         ms->settings.cw = 0;
865
866         return CMD_SUCCESS;
867 }
868
869 DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
870         "Allow waiting calls")
871 {
872         struct osmocom_ms *ms = vty->index;
873
874         ms->settings.cw = 1;
875
876         return CMD_SUCCESS;
877 }
878
879 DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
880         "Force caller ID presentation")
881 {
882         struct osmocom_ms *ms = vty->index;
883
884         ms->settings.clip = 1;
885         ms->settings.clir = 0;
886
887         return CMD_SUCCESS;
888 }
889
890 DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
891         "Force caller ID restriction")
892 {
893         struct osmocom_ms *ms = vty->index;
894
895         ms->settings.clip = 0;
896         ms->settings.clir = 1;
897
898         return CMD_SUCCESS;
899 }
900
901 DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
902         NO_STR "Disable forcing of caller ID presentation")
903 {
904         struct osmocom_ms *ms = vty->index;
905
906         ms->settings.clip = 0;
907
908         return CMD_SUCCESS;
909 }
910
911 DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
912         NO_STR "Disable forcing of caller ID restriction")
913 {
914         struct osmocom_ms *ms = vty->index;
915
916         ms->settings.clir = 0;
917
918         return CMD_SUCCESS;
919 }
920
921 DEFUN(cfg_ms_tx_power, cfg_ms_tx_power_cmd, "tx-power (auto|full)",
922         "Set the way to choose transmit power\nControlled by BTS\n"
923         "Always full power\nFixed GSM power value if supported")
924 {
925         struct osmocom_ms *ms = vty->index;
926
927         switch (argv[0][0]) {
928         case 'a':
929                 ms->settings.alter_tx_power = 0;
930                 break;
931         case 'f':
932                 ms->settings.alter_tx_power = 1;
933                 ms->settings.alter_tx_power_value = 0;
934                 break;
935         }
936
937         return CMD_SUCCESS;
938 }
939
940 DEFUN(cfg_ms_tx_power_val, cfg_ms_tx_power_val_cmd, "tx-power <0-31>",
941         "Set the way to choose transmit power\n"
942         "Fixed GSM power value if supported")
943 {
944         struct osmocom_ms *ms = vty->index;
945
946         ms->settings.alter_tx_power = 1;
947         ms->settings.alter_tx_power_value = atoi(argv[0]);
948
949         return CMD_SUCCESS;
950 }
951
952 DEFUN(cfg_ms_sim_delay, cfg_ms_sim_delay_cmd, "simulated-delay <-128-127>",
953         "Simulate a lower or higher distance from the BTS\n"
954         "Delay in half bits (distance in 553.85 meter steps)")
955 {
956         struct osmocom_ms *ms = vty->index;
957
958         ms->settings.alter_delay = atoi(argv[0]);
959
960         return CMD_SUCCESS;
961 }
962
963 DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
964         NO_STR "Do not simulate a lower or higher distance from the BTS")
965 {
966         struct osmocom_ms *ms = vty->index;
967
968         ms->settings.alter_delay = 0;
969
970         return CMD_SUCCESS;
971 }
972
973 DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023>",
974         "Stick to the given cell\nARFCN of the cell to stick to")
975 {
976         struct osmocom_ms *ms = vty->index;
977
978         ms->settings.stick = 1;
979         ms->settings.stick_arfcn = atoi(argv[0]);
980
981         return CMD_SUCCESS;
982 }
983
984 DEFUN(cfg_ms_no_stick, cfg_ms_no_stick_cmd, "no stick",
985         NO_STR "Do not stick to any cell")
986 {
987         struct osmocom_ms *ms = vty->index;
988
989         ms->settings.stick = 0;
990
991         return CMD_SUCCESS;
992 }
993
994 DEFUN(cfg_ms_lupd, cfg_ms_lupd_cmd, "location-updating",
995         "Allow location updating")
996 {
997         struct osmocom_ms *ms = vty->index;
998
999         ms->settings.no_lupd = 0;
1000
1001         return CMD_SUCCESS;
1002 }
1003
1004 DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating",
1005         NO_STR "Do not allow location updating")
1006 {
1007         struct osmocom_ms *ms = vty->index;
1008
1009         ms->settings.no_lupd = 1;
1010
1011         return CMD_SUCCESS;
1012 }
1013
1014 /* per testsim config */
1015 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
1016         "Configure test SIM emulation")
1017 {
1018         vty->node = TESTSIM_NODE;
1019
1020         return CMD_SUCCESS;
1021 }
1022
1023 static int config_write_dummy(struct vty *vty)
1024 {
1025         return CMD_SUCCESS;
1026 }
1027
1028 DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
1029         "Set IMSI on test card\n15 digits IMSI")
1030 {
1031         struct osmocom_ms *ms = vty->index;
1032         char *error = gsm_check_imsi(argv[0]);
1033
1034         if (error) {
1035                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1036                 return CMD_WARNING;
1037         }
1038
1039         strcpy(ms->settings.test_imsi, argv[0]);
1040
1041         return CMD_SUCCESS;
1042 }
1043
1044 DEFUN(cfg_test_barr, cfg_test_barr_cmd, "barred-access",
1045         "Allow access to barred cells")
1046 {
1047         struct osmocom_ms *ms = vty->index;
1048
1049         ms->settings.test_barr = 1;
1050
1051         return CMD_SUCCESS;
1052 }
1053
1054 DEFUN(cfg_test_no_barr, cfg_test_no_barr_cmd, "no barred-access",
1055         NO_STR "Deny access to barred cells")
1056 {
1057         struct osmocom_ms *ms = vty->index;
1058
1059         ms->settings.test_barr = 0;
1060
1061         return CMD_SUCCESS;
1062 }
1063
1064 DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
1065         NO_STR "Unset Registered PLMN")
1066 {
1067         struct osmocom_ms *ms = vty->index;
1068
1069         ms->settings.test_rplmn_valid = 0;
1070
1071         return CMD_SUCCESS;
1072 }
1073
1074 DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC",
1075         "Set Registered PLMN\nMobile Country Code\nMobile Network Code")
1076 {
1077         struct osmocom_ms *ms = vty->index;
1078         uint16_t mcc = gsm_input_mcc((char *)argv[0]),
1079                  mnc = gsm_input_mnc((char *)argv[1]);
1080
1081         if (!mcc) {
1082                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
1083                 return CMD_WARNING;
1084         }
1085         if (!mnc) {
1086                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
1087                 return CMD_WARNING;
1088         }
1089         ms->settings.test_rplmn_valid = 1;
1090         ms->settings.test_rplmn_mcc = mcc;
1091         ms->settings.test_rplmn_mnc = mnc;
1092
1093         return CMD_SUCCESS;
1094 }
1095
1096 DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-country)",
1097         "Set Home PLMN search mode\n"
1098         "Search for HPLMN when on any other network\n"
1099         "Search for HPLMN when in a different country")
1100 {
1101         struct osmocom_ms *ms = vty->index;
1102
1103         switch (argv[0][0]) {
1104         case 'e':
1105                 ms->settings.test_always = 1;
1106                 break;
1107         case 'f':
1108                 ms->settings.test_always = 0;
1109                 break;
1110         }
1111
1112         return CMD_SUCCESS;
1113 }
1114
1115 enum node_type ms_vty_go_parent(struct vty *vty)
1116 {
1117         switch (vty->node) {
1118         case MS_NODE:
1119                 vty->node = CONFIG_NODE;
1120                 vty->index = NULL;
1121                 break;
1122         case TESTSIM_NODE:
1123                 vty->node = MS_NODE;
1124                 break;
1125         default:
1126                 vty->node = CONFIG_NODE;
1127         }
1128
1129         return vty->node;
1130 }
1131
1132 /* Down vty node level. */
1133 gDEFUN(ournode_exit,
1134        ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
1135 {
1136         switch (vty->node) {
1137         case MS_NODE:
1138                 vty->node = CONFIG_NODE;
1139                 vty->index = NULL;
1140                 break;
1141         case TESTSIM_NODE:
1142                 vty->node = MS_NODE;
1143                 break;
1144         default:
1145                 break;
1146         }
1147         return CMD_SUCCESS;
1148 }
1149
1150 /* End of configuration. */
1151 gDEFUN(ournode_end,
1152        ournode_end_cmd, "end", "End current mode and change to enable mode.")
1153 {
1154         switch (vty->node) {
1155         case VIEW_NODE:
1156         case ENABLE_NODE:
1157                 /* Nothing to do. */
1158                 break;
1159         case CONFIG_NODE:
1160         case VTY_NODE:
1161         case MS_NODE:
1162         case TESTSIM_NODE:
1163                 vty_config_unlock(vty);
1164                 vty->node = ENABLE_NODE;
1165                 vty->index = NULL;
1166                 vty->index_sub = NULL;
1167                 break;
1168         default:
1169                 break;
1170         }
1171         return CMD_SUCCESS;
1172 }
1173
1174 int ms_vty_init(void)
1175 {
1176         install_element_ve(&show_ms_cmd);
1177         install_element_ve(&show_subscr_cmd);
1178         install_element_ve(&show_support_cmd);
1179         install_element_ve(&show_states_cmd);
1180         install_element_ve(&show_cell_cmd);
1181         install_element_ve(&show_cell_si_cmd);
1182         install_element_ve(&show_ba_cmd);
1183         install_element_ve(&show_forb_la_cmd);
1184         install_element_ve(&show_forb_plmn_cmd);
1185         install_element_ve(&monitor_network_cmd);
1186         install_element_ve(&no_monitor_network_cmd);
1187
1188         install_element(ENABLE_NODE, &sim_test_cmd);
1189         install_element(ENABLE_NODE, &sim_reader_cmd);
1190         install_element(ENABLE_NODE, &sim_remove_cmd);
1191         install_element(ENABLE_NODE, &sim_pin_cmd);
1192         install_element(ENABLE_NODE, &network_search_cmd);
1193         install_element(ENABLE_NODE, &network_show_cmd);
1194         install_element(ENABLE_NODE, &network_select_cmd);
1195         install_element(ENABLE_NODE, &call_cmd);
1196         install_element(ENABLE_NODE, &call_retr_cmd);
1197
1198         install_element(CONFIG_NODE, &cfg_gps_device_cmd);
1199         install_element(CONFIG_NODE, &cfg_gps_baud_cmd);
1200         install_element(CONFIG_NODE, &cfg_gps_enable_cmd);
1201         install_element(CONFIG_NODE, &cfg_no_gps_enable_cmd);
1202
1203         install_element(CONFIG_NODE, &cfg_ms_cmd);
1204         install_element(CONFIG_NODE, &ournode_end_cmd);
1205         install_node(&ms_node, config_write_ms);
1206         install_default(MS_NODE);
1207         install_element(MS_NODE, &ournode_exit_cmd);
1208         install_element(MS_NODE, &ournode_end_cmd);
1209         install_element(MS_NODE, &cfg_ms_sim_cmd);
1210         install_element(MS_NODE, &cfg_ms_mode_cmd);
1211         install_element(MS_NODE, &cfg_ms_imei_cmd);
1212         install_element(MS_NODE, &cfg_ms_imei_fixed_cmd);
1213         install_element(MS_NODE, &cfg_ms_imei_random_cmd);
1214         install_element(MS_NODE, &cfg_ms_no_emerg_imsi_cmd);
1215         install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
1216         install_element(MS_NODE, &cfg_ms_cw_cmd);
1217         install_element(MS_NODE, &cfg_ms_no_cw_cmd);
1218         install_element(MS_NODE, &cfg_ms_clip_cmd);
1219         install_element(MS_NODE, &cfg_ms_clir_cmd);
1220         install_element(MS_NODE, &cfg_ms_no_clip_cmd);
1221         install_element(MS_NODE, &cfg_ms_no_clir_cmd);
1222         install_element(MS_NODE, &cfg_ms_testsim_cmd);
1223         install_element(MS_NODE, &cfg_ms_tx_power_cmd);
1224         install_element(MS_NODE, &cfg_ms_tx_power_val_cmd);
1225         install_element(MS_NODE, &cfg_ms_sim_delay_cmd);
1226         install_element(MS_NODE, &cfg_ms_no_sim_delay_cmd);
1227         install_element(MS_NODE, &cfg_ms_stick_cmd);
1228         install_element(MS_NODE, &cfg_ms_no_stick_cmd);
1229         install_element(MS_NODE, &cfg_ms_lupd_cmd);
1230         install_element(MS_NODE, &cfg_ms_no_lupd_cmd);
1231
1232         install_node(&testsim_node, config_write_dummy);
1233         install_default(TESTSIM_NODE);
1234         install_element(TESTSIM_NODE, &ournode_exit_cmd);
1235         install_element(TESTSIM_NODE, &ournode_end_cmd);
1236         install_element(TESTSIM_NODE, &cfg_test_imsi_cmd);
1237         install_element(TESTSIM_NODE, &cfg_test_barr_cmd);
1238         install_element(TESTSIM_NODE, &cfg_test_no_barr_cmd);
1239         install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd);
1240         install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd);
1241         install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd);
1242
1243         return 0;
1244 }
1245
1246 void vty_notify(struct osmocom_ms *ms, const char *fmt, ...)
1247 {
1248         struct telnet_connection *connection;
1249         char buffer[1000];
1250         va_list args;
1251         struct vty *vty;
1252
1253         if (fmt) {
1254                 va_start(args, fmt);
1255                 vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
1256                 buffer[sizeof(buffer) - 1] = '\0';
1257                 va_end(args);
1258
1259                 if (!buffer[0])
1260                         return;
1261         }
1262
1263         llist_for_each_entry(connection, &active_connections, entry) {
1264                 vty = connection->vty;
1265                 if (!vty)
1266                         continue;
1267                 if (!fmt) {
1268                         vty_out(vty, "%s%% (MS %s)%s", VTY_NEWLINE, ms->name,
1269                                 VTY_NEWLINE);
1270                         continue;
1271                 }
1272                 if (buffer[strlen(buffer) - 1] == '\n') {
1273                         buffer[strlen(buffer) - 1] = '\0';
1274                         vty_out(vty, "%% %s%s", buffer, VTY_NEWLINE);
1275                         buffer[strlen(buffer)] = '\n';
1276                 } else
1277                         vty_out(vty, "%% %s", buffer);
1278         }
1279 }
1280