Added gpsd support.
[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/utils.h>
29 #include <osmocore/gsm48.h>
30 #include <osmocore/talloc.h>
31 #include <osmocore/signal.h>
32
33 #include <osmocom/bb/common/osmocom_data.h>
34 #include <osmocom/bb/common/networks.h>
35 #include <osmocom/bb/common/gps.h>
36 #include <osmocom/bb/mobile/mncc.h>
37 #include <osmocom/bb/mobile/transaction.h>
38 #include <osmocom/bb/mobile/vty.h>
39 #include <osmocom/bb/mobile/app_mobile.h>
40 #include <osmocom/vty/telnet_interface.h>
41
42 void *l23_ctx;
43
44 int mncc_call(struct osmocom_ms *ms, char *number);
45 int mncc_hangup(struct osmocom_ms *ms);
46 int mncc_answer(struct osmocom_ms *ms);
47 int mncc_hold(struct osmocom_ms *ms);
48 int mncc_retrieve(struct osmocom_ms *ms, int number);
49 int mncc_dtmf(struct osmocom_ms *ms, char *dtmf);
50
51 extern struct llist_head ms_list;
52 extern struct llist_head active_connections;
53
54 struct cmd_node ms_node = {
55         MS_NODE,
56         "%s(ms)#",
57         1
58 };
59
60 struct cmd_node testsim_node = {
61         TESTSIM_NODE,
62         "%s(test-sim)#",
63         1
64 };
65
66 struct cmd_node support_node = {
67         SUPPORT_NODE,
68         "%s(support)#",
69         1
70 };
71
72 static void print_vty(void *priv, const char *fmt, ...)
73 {
74         char buffer[1000];
75         struct vty *vty = priv;
76         va_list args;
77
78         va_start(args, fmt);
79         vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
80         buffer[sizeof(buffer) - 1] = '\0';
81         va_end(args);
82
83         if (buffer[0]) {
84                 if (buffer[strlen(buffer) - 1] == '\n') {
85                         buffer[strlen(buffer) - 1] = '\0';
86                         vty_out(vty, "%s%s", buffer, VTY_NEWLINE);
87                 } else
88                         vty_out(vty, "%s", buffer);
89         }
90 }
91
92 int vty_check_number(struct vty *vty, const char *number)
93 {
94         int i;
95
96         for (i = 0; i < strlen(number); i++) {
97                 /* allow international notation with + */
98                 if (i == 0 && number[i] == '+')
99                         continue;
100                 if (!(number[i] >= '0' && number[i] <= '9')
101                  && number[i] != '*'
102                  && number[i] != '#'
103                  && !(number[i] >= 'a' && number[i] <= 'c')) {
104                         vty_out(vty, "Invalid digit '%c' of number!%s",
105                                 number[i], VTY_NEWLINE);
106                         return -EINVAL;
107                 }
108         }
109         if (number[0] == '\0' || (number[0] == '+' && number[1] == '\0')) {
110                 vty_out(vty, "Given number has no digits!%s", VTY_NEWLINE);
111                 return -EINVAL;
112         }
113
114         return 0;
115 }
116
117 int vty_reading = 0;
118
119 static void vty_restart(struct vty *vty, struct osmocom_ms *ms)
120 {
121         if (vty_reading)
122                 return;
123         if (ms->shutdown != 0)
124                 return;
125         vty_out(vty, "You must restart MS '%s' ('shutdown / no shutdown') for "
126                 "change to take effect!%s", ms->name, VTY_NEWLINE);
127 }
128
129 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
130 {
131         struct osmocom_ms *ms;
132
133         llist_for_each_entry(ms, &ms_list, entity) {
134                 if (!strcmp(ms->name, name)) {
135                         if (ms->shutdown) {
136                                 vty_out(vty, "MS '%s' is admin down.%s", name,
137                                         VTY_NEWLINE);
138                                 return NULL;
139                         }
140                         return ms;
141                 }
142         }
143         vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
144
145         return NULL;
146 }
147
148 static void gsm_ms_dump(struct osmocom_ms *ms, struct vty *vty)
149 {
150         struct gsm_settings *set = &ms->settings;
151         struct gsm_trans *trans;
152         char *service = "";
153
154         if (!ms->started)
155                 service = ", radio is not started";
156         else if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE) {
157                 /* current MM idle state */
158                 switch (ms->mmlayer.substate) {
159                 case GSM48_MM_SST_NORMAL_SERVICE:
160                 case GSM48_MM_SST_PLMN_SEARCH_NORMAL:
161                         service = ", service is normal";
162                         break;
163                 case GSM48_MM_SST_LOC_UPD_NEEDED:
164                 case GSM48_MM_SST_ATTEMPT_UPDATE:
165                         service = ", service is limited (pending)";
166                         break;
167                 case GSM48_MM_SST_NO_CELL_AVAIL:
168                         service = ", service is unavailable";
169                         break;
170                 default:
171                         if (ms->subscr.sim_valid)
172                                 service = ", service is limited";
173                         else
174                                 service = ", service is limited "
175                                         "(IMSI detached)";
176                         break;
177                 }
178         } else
179                 service = ", MM connection active";
180
181         vty_out(vty, "MS '%s' is %s%s%s%s", ms->name,
182                 (ms->shutdown) ? "administratively " : "",
183                 (ms->shutdown || !ms->started) ? "down" : "up",
184                 (!ms->shutdown) ? service : "",
185                 VTY_NEWLINE);
186         vty_out(vty, "  IMEI: %s%s", set->imei, VTY_NEWLINE);
187         vty_out(vty, "     IMEISV: %s%s", set->imeisv, VTY_NEWLINE);
188         if (set->imei_random)
189                 vty_out(vty, "     IMEI generation: random (%d trailing "
190                         "digits)%s", set->imei_random, VTY_NEWLINE);
191         else
192                 vty_out(vty, "     IMEI generation: fixed%s", VTY_NEWLINE);
193
194         if (ms->shutdown)
195                 return;
196
197         if (set->plmn_mode == PLMN_MODE_AUTO)
198                 vty_out(vty, "  automatic network selection state: %s%s", 
199                         plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
200         else
201                 vty_out(vty, "  manual network selection state: %s%s", 
202                         plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
203         vty_out(vty, "  cell selection state: %s",
204                 cs_state_names[ms->cellsel.state]);
205         if (ms->rrlayer.state == GSM48_RR_ST_IDLE && ms->cellsel.selected)
206                 vty_out(vty, " (ARFCN %d)", ms->cellsel.sel_arfcn);
207         vty_out(vty, "%s", VTY_NEWLINE);
208         vty_out(vty, "  radio ressource layer state: %s%s", 
209                 gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
210         vty_out(vty, "  mobility management layer state: %s", 
211                 gsm48_mm_state_names[ms->mmlayer.state]);
212         if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
213                 vty_out(vty, ", %s", 
214                         gsm48_mm_substate_names[ms->mmlayer.substate]);
215         vty_out(vty, "%s", VTY_NEWLINE);
216         llist_for_each_entry(trans, &ms->trans_list, entry) {
217                 vty_out(vty, "  call control state: %s%s", 
218                         gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
219         }
220 }
221
222
223 DEFUN(show_ms, show_ms_cmd, "show ms [MS_NAME]",
224         SHOW_STR "Display available MS entities\n")
225 {
226         struct osmocom_ms *ms;
227
228         if (argc) {
229                 llist_for_each_entry(ms, &ms_list, entity) {
230                         if (!strcmp(ms->name, argv[0])) {
231                                 gsm_ms_dump(ms, vty);
232                                 return CMD_SUCCESS;
233                         }
234                 }
235                 vty_out(vty, "MS name '%s' does not exits.%s", argv[0],
236                 VTY_NEWLINE);
237                 return CMD_WARNING;
238         } else {
239                 llist_for_each_entry(ms, &ms_list, entity) {
240                         gsm_ms_dump(ms, vty);
241                         vty_out(vty, "%s", VTY_NEWLINE);
242                 }
243         }
244
245         return CMD_SUCCESS;
246 }
247
248 DEFUN(show_support, show_support_cmd, "show support [MS_NAME]",
249         SHOW_STR "Display information about MS support\n"
250         "Name of MS (see \"show ms\")")
251 {
252         struct osmocom_ms *ms;
253
254         if (argc) {
255                 ms = get_ms(argv[0], vty);
256                 if (!ms)
257                         return CMD_WARNING;
258                 gsm_support_dump(ms, print_vty, vty);
259         } else {
260                 llist_for_each_entry(ms, &ms_list, entity) {
261                         gsm_support_dump(ms, print_vty, vty);
262                         vty_out(vty, "%s", VTY_NEWLINE);
263                 }
264         }
265
266         return CMD_SUCCESS;
267 }
268
269 DEFUN(show_subscr, show_subscr_cmd, "show subscriber [MS_NAME]",
270         SHOW_STR "Display information about subscriber\n"
271         "Name of MS (see \"show ms\")")
272 {
273         struct osmocom_ms *ms;
274
275         if (argc) {
276                 ms = get_ms(argv[0], vty);
277                 if (!ms)
278                         return CMD_WARNING;
279                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
280         } else {
281                 llist_for_each_entry(ms, &ms_list, entity) {
282                         if (!ms->shutdown) {
283                                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
284                                 vty_out(vty, "%s", VTY_NEWLINE);
285                         }
286                 }
287         }
288
289         return CMD_SUCCESS;
290 }
291
292 DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
293         SHOW_STR "Display information about received cells\n"
294         "Name of MS (see \"show ms\")")
295 {
296         struct osmocom_ms *ms;
297
298         ms = get_ms(argv[0], vty);
299         if (!ms)
300                 return CMD_WARNING;
301
302         gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
303                 vty);
304
305         return CMD_SUCCESS;
306 }
307
308 DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>",
309         SHOW_STR "Display information about received cell\n"
310         "Name of MS (see \"show ms\")\nRadio frequency number")
311 {
312         struct osmocom_ms *ms;
313         int i;
314         struct gsm48_sysinfo *s;
315
316         ms = get_ms(argv[0], vty);
317         if (!ms)
318                 return CMD_WARNING;
319
320         i = atoi(argv[1]);
321         if (i < 0 || i > 1023) {
322                 vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s",
323                         argv[1], VTY_NEWLINE);
324                 return CMD_WARNING;
325         }
326         s = ms->cellsel.list[i].sysinfo;
327         if (!s) {
328                 vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s",
329                         argv[1], VTY_NEWLINE);
330                 return CMD_SUCCESS;
331         }
332
333         gsm48_sysinfo_dump(s, i, print_vty, vty);
334
335         return CMD_SUCCESS;
336 }
337
338 DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [MCC] [MNC]",
339         SHOW_STR "Display information about band allocations\n"
340         "Name of MS (see \"show ms\")\nMobile Country Code\n"
341         "Mobile Network Code")
342 {
343         struct osmocom_ms *ms;
344         uint16_t mcc = 0, mnc = 0;
345
346         ms = get_ms(argv[0], vty);
347         if (!ms)
348                 return CMD_WARNING;
349
350         if (argc >= 3) {
351                 mcc = gsm_input_mcc((char *)argv[1]);
352                 mnc = gsm_input_mnc((char *)argv[2]);
353                 if (!mcc) {
354                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
355                         return CMD_WARNING;
356                 }
357                 if (!mnc) {
358                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
359                         return CMD_WARNING;
360                 }
361         }
362
363         gsm322_dump_ba_list(&ms->cellsel, mcc, mnc, print_vty, vty);
364
365         return CMD_SUCCESS;
366 }
367
368 DEFUN(show_forb_plmn, show_forb_plmn_cmd, "show forbidden plmn MS_NAME",
369         SHOW_STR "Display information about forbidden cells / networks\n"
370         "Display forbidden PLMNs\nName of MS (see \"show ms\")")
371 {
372         struct osmocom_ms *ms;
373
374         ms = get_ms(argv[0], vty);
375         if (!ms)
376                 return CMD_WARNING;
377
378         gsm_subscr_dump_forbidden_plmn(ms, print_vty, vty);
379
380         return CMD_SUCCESS;
381 }
382
383 DEFUN(show_forb_la, show_forb_la_cmd, "show forbidden location-area MS_NAME",
384         SHOW_STR "Display information about forbidden cells / networks\n"
385         "Display forbidden location areas\nName of MS (see \"show ms\")")
386 {
387         struct osmocom_ms *ms;
388
389         ms = get_ms(argv[0], vty);
390         if (!ms)
391                 return CMD_WARNING;
392
393         gsm322_dump_forbidden_la(ms, print_vty, vty);
394
395         return CMD_SUCCESS;
396 }
397
398 DEFUN(monitor_network, monitor_network_cmd, "monitor network MS_NAME",
399         "Monitor...\nMonitor network information\nName of MS (see \"show ms\")")
400 {
401         struct osmocom_ms *ms;
402
403         ms = get_ms(argv[0], vty);
404         if (!ms)
405                 return CMD_WARNING;
406
407         gsm48_rr_start_monitor(ms);
408
409         return CMD_SUCCESS;
410 }
411
412 DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME",
413         NO_STR "Monitor...\nDeactivate monitor of network information\n"
414         "Name of MS (see \"show ms\")")
415 {
416         struct osmocom_ms *ms;
417
418         ms = get_ms(argv[0], vty);
419         if (!ms)
420                 return CMD_WARNING;
421
422         gsm48_rr_stop_monitor(ms);
423
424         return CMD_SUCCESS;
425 }
426
427 DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [MCC] [MNC] [LAC] [TMSI]",
428         "SIM actions\nInsert test card\nName of MS (see \"show ms\")\n"
429         "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN\n"
430         "Optionally locatio area code\nOptionally current assigned TMSI")
431 {
432         struct osmocom_ms *ms;
433         uint16_t mcc = 0x001, mnc = 0x01f, lac = 0x0000;
434         uint32_t tmsi = 0xffffffff;
435
436         ms = get_ms(argv[0], vty);
437         if (!ms)
438                 return CMD_WARNING;
439
440         if (ms->subscr.sim_valid) {
441                 vty_out(vty, "SIM already presend, remove first!%s",
442                         VTY_NEWLINE);
443                 return CMD_WARNING;
444         }
445
446         if (argc >= 3) {
447                 mcc = gsm_input_mcc((char *)argv[1]);
448                 mnc = gsm_input_mnc((char *)argv[2]);
449                 if (!mcc) {
450                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
451                         return CMD_WARNING;
452                 }
453                 if (!mnc) {
454                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
455                         return CMD_WARNING;
456                 }
457         }
458
459         if (argc >= 4)
460                 lac = strtoul(argv[3], NULL, 16);
461
462         if (argc >= 5)
463                 tmsi = strtoul(argv[4], NULL, 16);
464
465         gsm_subscr_testcard(ms, mcc, mnc, lac, tmsi);
466
467         return CMD_SUCCESS;
468 }
469
470 DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
471         "SIM actions\nSelect SIM from reader\nName of MS (see \"show ms\")")
472 {
473         struct osmocom_ms *ms;
474
475         ms = get_ms(argv[0], vty);
476         if (!ms)
477                 return CMD_WARNING;
478
479         if (ms->subscr.sim_valid) {
480                 vty_out(vty, "SIM already presend, remove first!%s",
481                         VTY_NEWLINE);
482                 return CMD_WARNING;
483         }
484
485         gsm_subscr_simcard(ms);
486
487         return CMD_SUCCESS;
488 }
489
490 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
491         "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")")
492 {
493         struct osmocom_ms *ms;
494
495         ms = get_ms(argv[0], vty);
496         if (!ms)
497                 return CMD_WARNING;
498
499         if (!ms->subscr.sim_valid) {
500                 vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
501                 return CMD_WARNING;
502         }
503
504         gsm_subscr_remove(ms);
505
506         return CMD_SUCCESS;
507 }
508
509 DEFUN(sim_pin, sim_pin_cmd, "sim pin MS_NAME PIN",
510         "SIM actions\nEnter PIN for SIM card\nName of MS (see \"show ms\")\n"
511         "PIN number")
512 {
513         struct osmocom_ms *ms;
514
515         ms = get_ms(argv[0], vty);
516         if (!ms)
517                 return CMD_WARNING;
518
519         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
520                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
521                 return CMD_WARNING;
522         }
523
524         if (!ms->subscr.sim_pin_required) {
525                 vty_out(vty, "No PIN is required at this time!%s", VTY_NEWLINE);
526                 return CMD_WARNING;
527         }
528
529         gsm_subscr_sim_pin(ms, (char *)argv[1], "", 0);
530
531         return CMD_SUCCESS;
532 }
533
534 DEFUN(sim_disable_pin, sim_disable_pin_cmd, "sim disable-pin MS_NAME PIN",
535         "SIM actions\nDisable PIN of SIM card\nName of MS (see \"show ms\")\n"
536         "PIN number")
537 {
538         struct osmocom_ms *ms;
539
540         ms = get_ms(argv[0], vty);
541         if (!ms)
542                 return CMD_WARNING;
543
544         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
545                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
546                 return CMD_WARNING;
547         }
548
549         gsm_subscr_sim_pin(ms, (char *)argv[1], "", -1);
550
551         return CMD_SUCCESS;
552 }
553
554 DEFUN(sim_enable_pin, sim_enable_pin_cmd, "sim enable-pin MS_NAME PIN",
555         "SIM actions\nEnable PIN of SIM card\nName of MS (see \"show ms\")\n"
556         "PIN number")
557 {
558         struct osmocom_ms *ms;
559
560         ms = get_ms(argv[0], vty);
561         if (!ms)
562                 return CMD_WARNING;
563
564         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
565                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
566                 return CMD_WARNING;
567         }
568
569         gsm_subscr_sim_pin(ms, (char *)argv[1], "", 1);
570
571         return CMD_SUCCESS;
572 }
573
574 DEFUN(sim_change_pin, sim_change_pin_cmd, "sim change-pin MS_NAME OLD NEW",
575         "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
576         "Old PIN number\nNew PIN number")
577 {
578         struct osmocom_ms *ms;
579
580         ms = get_ms(argv[0], vty);
581         if (!ms)
582                 return CMD_WARNING;
583
584         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
585                 vty_out(vty, "Old PIN must be in range 4..8!%s", VTY_NEWLINE);
586                 return CMD_WARNING;
587         }
588         if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
589                 vty_out(vty, "New PIN must be in range 4..8!%s", VTY_NEWLINE);
590                 return CMD_WARNING;
591         }
592
593         gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 2);
594
595         return CMD_SUCCESS;
596 }
597
598 DEFUN(sim_unblock_pin, sim_unblock_pin_cmd, "sim unblock-pin MS_NAME PUC NEW",
599         "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
600         "Personal Unblock Key\nNew PIN number")
601 {
602         struct osmocom_ms *ms;
603
604         ms = get_ms(argv[0], vty);
605         if (!ms)
606                 return CMD_WARNING;
607
608         if (strlen(argv[1]) != 8) {
609                 vty_out(vty, "PUC must be 8 digits!%s", VTY_NEWLINE);
610                 return CMD_WARNING;
611         }
612         if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
613                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
614                 return CMD_WARNING;
615         }
616
617         gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 99);
618
619         return CMD_SUCCESS;
620 }
621
622 DEFUN(sim_lai, sim_lai_cmd, "sim lai MS_NAME MCC MNC LAC",
623         "SIM actions\nChange LAI of SIM card\nName of MS (see \"show ms\")\n"
624         "Mobile Country Code\nMobile Network Code\nLocation Area Code "
625         " (use 0000 to remove LAI)")
626 {
627         struct osmocom_ms *ms;
628         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
629                  mnc = gsm_input_mnc((char *)argv[2]),
630                  lac = strtoul(argv[3], NULL, 16);
631
632         ms = get_ms(argv[0], vty);
633         if (!ms)
634                 return CMD_WARNING;
635
636         if (!mcc) {
637                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
638                 return CMD_WARNING;
639         }
640         if (!mnc) {
641                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
642                 return CMD_WARNING;
643         }
644
645         ms->subscr.mcc = mcc;
646         ms->subscr.mnc = mnc;
647         ms->subscr.lac = lac;
648         ms->subscr.tmsi = 0xffffffff;
649
650         gsm_subscr_write_loci(ms);
651
652         return CMD_SUCCESS;
653 }
654
655 DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
656         "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
657         "Mobile Country Code\nMobile Network Code")
658 {
659         struct osmocom_ms *ms;
660         struct gsm322_plmn *plmn;
661         struct msgb *nmsg;
662         struct gsm322_msg *ngm;
663         struct gsm322_plmn_list *temp;
664         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
665                  mnc = gsm_input_mnc((char *)argv[2]);
666         int found = 0;
667
668         ms = get_ms(argv[0], vty);
669         if (!ms)
670                 return CMD_WARNING;
671         plmn = &ms->plmn;
672
673         if (!mcc) {
674                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
675                 return CMD_WARNING;
676         }
677         if (!mnc) {
678                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
679                 return CMD_WARNING;
680         }
681
682         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
683                 if (temp->mcc == mcc &&  temp->mnc == mnc)
684                         found = 1;
685         if (!found) {
686                 vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
687                 return CMD_WARNING;
688         }
689
690         nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
691         if (!nmsg)
692                 return CMD_WARNING;
693         ngm = (struct gsm322_msg *) nmsg->data;
694         ngm->mcc = mcc;
695         ngm->mnc = mnc;
696         gsm322_plmn_sendmsg(ms, nmsg);
697
698         return CMD_SUCCESS;
699 }
700
701 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
702         "Make a call\nName of MS (see \"show ms\")\nPhone number to call "
703         "(Use digits '0123456789*#abc', and '+' to dial international)\n"
704         "Make an emergency call\nAnswer an incomming call\nHangup a call\n"
705         "Hold current active call\n")
706 {
707         struct osmocom_ms *ms;
708         struct gsm_settings *set;
709         struct gsm_settings_abbrev *abbrev;
710         char *number;
711
712         ms = get_ms(argv[0], vty);
713         if (!ms)
714                 return CMD_WARNING;
715         set = &ms->settings;
716
717         if (set->ch_cap == GSM_CAP_SDCCH) {
718                 vty_out(vty, "Basic call is not supported for SDCCH only "
719                         "mobile%s", VTY_NEWLINE);
720                 return CMD_WARNING;
721         }
722
723         number = (char *)argv[1];
724         if (!strcmp(number, "emergency"))
725                 mncc_call(ms, number);
726         else if (!strcmp(number, "answer"))
727                 mncc_answer(ms);
728         else if (!strcmp(number, "hangup"))
729                 mncc_hangup(ms);
730         else if (!strcmp(number, "hold"))
731                 mncc_hold(ms);
732         else {
733                 llist_for_each_entry(abbrev, &set->abbrev, list) {
734                         if (!strcmp(number, abbrev->abbrev)) {
735                                 number = abbrev->number;
736                                 vty_out(vty, "Dialing number '%s'%s", number,
737                                         VTY_NEWLINE);
738                                 break;
739                         }
740                 }
741                 if (vty_check_number(vty, number))
742                         return CMD_WARNING;
743                 mncc_call(ms, number);
744         }
745
746         return CMD_SUCCESS;
747 }
748
749 DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [NUMBER]",
750         "Make a call\nName of MS (see \"show ms\")\n"
751         "Retrieve call on hold\nNumber of call to retrieve")
752 {
753         struct osmocom_ms *ms;
754
755         ms = get_ms(argv[0], vty);
756         if (!ms)
757                 return CMD_WARNING;
758
759         mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
760
761         return CMD_SUCCESS;
762 }
763
764 DEFUN(call_dtmf, call_dtmf_cmd, "call MS_NAME dtmf DIGITS",
765         "Make a call\nName of MS (see \"show ms\")\n"
766         "One or more DTMF digits to transmit")
767 {
768         struct osmocom_ms *ms;
769         struct gsm_settings *set;
770
771         ms = get_ms(argv[0], vty);
772         if (!ms)
773                 return CMD_WARNING;
774         set = &ms->settings;
775
776         if (!set->cc_dtmf) {
777                 vty_out(vty, "DTMF not supported, please enable!%s",
778                         VTY_NEWLINE);
779                 return CMD_WARNING;
780         }
781
782         mncc_dtmf(ms, (char *)argv[1]);
783
784         return CMD_SUCCESS;
785 }
786
787 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
788         "Network ...\nShow results of network search (again)\n"
789         "Name of MS (see \"show ms\")")
790 {
791         struct osmocom_ms *ms;
792         struct gsm_settings *set;
793         struct gsm322_plmn *plmn;
794         struct gsm322_plmn_list *temp;
795
796         ms = get_ms(argv[0], vty);
797         if (!ms)
798                 return CMD_WARNING;
799         set = &ms->settings;
800         plmn = &ms->plmn;
801
802         if (set->plmn_mode != PLMN_MODE_AUTO
803          && plmn->state != GSM322_M3_NOT_ON_PLMN) {
804                 vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
805                 return CMD_WARNING;
806         }
807
808         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
809                 vty_out(vty, " Network %s, %s (%s, %s)%s",
810                         gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
811                         gsm_get_mcc(temp->mcc),
812                         gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
813
814         return CMD_SUCCESS;
815 }
816
817 DEFUN(network_search, network_search_cmd, "network search MS_NAME",
818         "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
819 {
820         struct osmocom_ms *ms;
821         struct msgb *nmsg;
822
823         ms = get_ms(argv[0], vty);
824         if (!ms)
825                 return CMD_WARNING;
826
827         nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
828         if (!nmsg)
829                 return CMD_WARNING;
830         gsm322_plmn_sendmsg(ms, nmsg);
831
832         return CMD_SUCCESS;
833 }
834
835 DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable",
836         "GPS receiver")
837 {
838         if (osmo_gps_open()) {
839                 gps.enable = 1;
840                 vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE);
841                 return CMD_WARNING;
842         }
843         gps.enable = 1;
844
845         return CMD_SUCCESS;
846 }
847
848 DEFUN(cfg_no_gps_enable, cfg_no_gps_enable_cmd, "no gps enable",
849         NO_STR "Disable GPS receiver")
850 {
851         if (gps.enable)
852                 osmo_gps_close();
853         gps.enable = 0;
854
855         return CMD_SUCCESS;
856 }
857
858 #ifdef _USE_GPSD
859 DEFUN(cfg_gps_host, cfg_gps_host_cmd, "gps host HOST:PORT",
860         "GPS receiver\nSelect gpsd host and port\n"
861         "IP and port (optional) of the host running gpsd")
862 {
863         char* colon = strstr(argv[0], ":");
864         if (colon != NULL) {
865                 memcpy(gps.gpsd_host, argv[0], colon - argv[0] - 1);
866                 gps.gpsd_host[colon - argv[0]] = '\0';
867                 memcpy(gps.gpsd_port, colon, strlen(colon));
868                 gps.gpsd_port[strlen(colon)] = '\0';
869         } else {
870                 snprintf(gps.gpsd_host, ARRAY_SIZE(gps.gpsd_host), "%s", argv[0]);
871                 gps.gpsd_host[ARRAY_SIZE(gps.gpsd_host) - 1] = '\0';
872                 snprintf(gps.gpsd_port, ARRAY_SIZE(gps.gpsd_port), "2947");
873                 gps.gpsd_port[ARRAY_SIZE(gps.gpsd_port) - 1] = '\0';
874         }
875         if (gps.enable) {
876                 osmo_gps_close();
877                 if (osmo_gps_open()) {
878                         vty_out(vty, "Failed to connect to gpsd host!%s",
879                                 VTY_NEWLINE);
880                         return CMD_WARNING;
881                 }
882         }
883
884         return CMD_SUCCESS;
885 }
886 #else
887 DEFUN(cfg_gps_device, cfg_gps_device_cmd, "gps device DEVICE",
888         "GPS receiver\nSelect serial device\n"
889         "Full path of serial device including /dev/")
890 {
891         strncpy(gps.device, argv[0], sizeof(gps.device));
892         gps.device[sizeof(gps.device) - 1] = '\0';
893         if (gps.enable) {
894                 osmo_gps_close();
895                 if (osmo_gps_open()) {
896                         vty_out(vty, "Failed to open GPS device!%s",
897                                 VTY_NEWLINE);
898                         return CMD_WARNING;
899                 }
900         }
901
902         return CMD_SUCCESS;
903 }
904 #endif
905
906 #ifndef _USE_GPSD
907 DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate "
908         "(default|4800|""9600|19200|38400|57600|115200)",
909         "GPS receiver\nSelect baud rate\nDefault, don't modify\n\n\n\n\n\n")
910 {
911         if (argv[0][0] == 'd')
912                 gps.baud = 0;
913         else
914                 gps.baud = atoi(argv[0]);
915         if (gps.enable) {
916                 osmo_gps_close();
917                 if (osmo_gps_open()) {
918                         gps.enable = 0;
919                         vty_out(vty, "Failed to open GPS device!%s",
920                                 VTY_NEWLINE);
921                         return CMD_WARNING;
922                 }
923         }
924
925         return CMD_SUCCESS;
926 }
927 #endif
928
929 /* per MS config */
930 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
931         "Select a mobile station to configure\nName of MS (see \"show ms\")")
932 {
933         struct osmocom_ms *ms;
934         int found = 0;
935
936         llist_for_each_entry(ms, &ms_list, entity) {
937                 if (!strcmp(ms->name, argv[0])) {
938                         found = 1;
939                         break;
940                 }
941         }
942
943         if (!found) {
944                 if (!vty_reading) {
945                         vty_out(vty, "MS name '%s' does not exits, try "
946                                 "'ms %s create'%s", argv[0], argv[0],
947                                 VTY_NEWLINE);
948                         return CMD_WARNING;
949                 }
950                 ms = mobile_new((char *)argv[0]);
951                 if (!ms) {
952                         vty_out(vty, "Failed to add MS name '%s'%s", argv[0],
953                                 VTY_NEWLINE);
954                         return CMD_WARNING;
955                 }
956         }
957
958         vty->index = ms;
959         vty->node = MS_NODE;
960
961         return CMD_SUCCESS;
962 }
963
964 DEFUN(cfg_ms_create, cfg_ms_create_cmd, "ms MS_NAME create",
965         "Select a mobile station to configure\nName of MS (see \"show ms\")\n"
966         "Create if MS does not exists")
967 {
968         struct osmocom_ms *ms;
969         int found = 0;
970
971         llist_for_each_entry(ms, &ms_list, entity) {
972                 if (!strcmp(ms->name, argv[0])) {
973                         found = 1;
974                         break;
975                 }
976         }
977
978         if (!found) {
979                 ms = mobile_new((char *)argv[0]);
980                 if (!ms) {
981                         vty_out(vty, "Failed to add MS name '%s'%s", argv[0],
982                                 VTY_NEWLINE);
983                         return CMD_WARNING;
984                 }
985         }
986
987         vty->index = ms;
988         vty->node = MS_NODE;
989
990         vty_out(vty, "MS '%s' created, after configuration, do 'no shutdown'%s",
991                 argv[0], VTY_NEWLINE);
992         return CMD_SUCCESS;
993 }
994
995 DEFUN(cfg_ms_rename, cfg_ms_rename_cmd, "ms MS_NAME rename MS_NAME",
996         "Select a mobile station to configure\nName of MS (see \"show ms\")\n"
997         "Rename MS\nNew name of MS")
998 {
999         struct osmocom_ms *ms;
1000         int found = 0;
1001
1002         llist_for_each_entry(ms, &ms_list, entity) {
1003                 if (!strcmp(ms->name, argv[0])) {
1004                         found = 1;
1005                         break;
1006                 }
1007         }
1008
1009         if (!found) {
1010                 vty_out(vty, "MS name '%s' does not exist%s", argv[0],
1011                         VTY_NEWLINE);
1012                 return CMD_WARNING;
1013         }
1014
1015         strncpy(ms->name, argv[1], sizeof(ms->name) - 1);
1016
1017         return CMD_SUCCESS;
1018 }
1019
1020 DEFUN(cfg_no_ms, cfg_no_ms_cmd, "no ms MS_NAME",
1021         NO_STR "Select a mobile station to remove\n"
1022         "Name of MS (see \"show ms\")")
1023 {
1024         struct osmocom_ms *ms;
1025         int found = 0;
1026
1027         llist_for_each_entry(ms, &ms_list, entity) {
1028                 if (!strcmp(ms->name, argv[0])) {
1029                         found = 1;
1030                         break;
1031                 }
1032         }
1033
1034         if (!found) {
1035                 vty_out(vty, "MS name '%s' does not exist%s", argv[0],
1036                         VTY_NEWLINE);
1037                 return CMD_WARNING;
1038         }
1039
1040         mobile_delete(ms, 1);
1041
1042         return CMD_SUCCESS;
1043 }
1044
1045 #define SUP_WRITE(item, cmd) \
1046         if (sup->item) \
1047                 vty_out(vty, "  %s%s%s", (set->item) ? "" : "no ", cmd, \
1048                         VTY_NEWLINE);
1049
1050 static void config_write_ms(struct vty *vty, struct osmocom_ms *ms)
1051 {
1052         struct gsm_settings *set = &ms->settings;
1053         struct gsm_support *sup = &ms->support;
1054         struct gsm_settings_abbrev *abbrev;
1055
1056         vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
1057         vty_out(vty, " layer2-socket %s%s", set->layer2_socket_path,
1058                 VTY_NEWLINE);
1059         vty_out(vty, " sap-socket %s%s", set->sap_socket_path, VTY_NEWLINE);
1060         switch(set->sim_type) {
1061                 case GSM_SIM_TYPE_NONE:
1062                 vty_out(vty, " sim none%s", VTY_NEWLINE);
1063                 break;
1064                 case GSM_SIM_TYPE_READER:
1065                 vty_out(vty, " sim reader%s", VTY_NEWLINE);
1066                 break;
1067                 case GSM_SIM_TYPE_TEST:
1068                 vty_out(vty, " sim test%s", VTY_NEWLINE);
1069                 break;
1070         }
1071         vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
1072                         == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
1073         vty_out(vty, " imei %s %s%s", set->imei,
1074                 set->imeisv + strlen(set->imei), VTY_NEWLINE);
1075         if (set->imei_random)
1076                 vty_out(vty, " imei-random %d%s", set->imei_random,
1077                         VTY_NEWLINE);
1078         else
1079                 vty_out(vty, " imei-fixed%s", VTY_NEWLINE);
1080         if (set->emergency_imsi[0])
1081                 vty_out(vty, " emergency-imsi %s%s", set->emergency_imsi,
1082                         VTY_NEWLINE);
1083         else
1084                 vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE);
1085         vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE);
1086         vty_out(vty, " %sauto-answer%s", (set->auto_answer) ? "" : "no ",
1087                 VTY_NEWLINE);
1088         vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE);
1089         vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE);
1090         if (set->alter_tx_power)
1091                 if (set->alter_tx_power_value)
1092                         vty_out(vty, " tx-power %d%s",
1093                                 set->alter_tx_power_value, VTY_NEWLINE);
1094                 else
1095                         vty_out(vty, " tx-power full%s", VTY_NEWLINE);
1096         else
1097                 vty_out(vty, " tx-power auto%s", VTY_NEWLINE);
1098         if (set->alter_delay)
1099                 vty_out(vty, " simulated-delay %d%s", set->alter_delay,
1100                         VTY_NEWLINE);
1101         else
1102                 vty_out(vty, " no simulated-delay%s", VTY_NEWLINE);
1103         if (set->stick)
1104                 vty_out(vty, " stick %d%s", set->stick_arfcn,
1105                         VTY_NEWLINE);
1106         else
1107                 vty_out(vty, " no stick%s", VTY_NEWLINE);
1108         if (set->no_lupd)
1109                 vty_out(vty, " no location-updating%s", VTY_NEWLINE);
1110         else
1111                 vty_out(vty, " location-updating%s", VTY_NEWLINE);
1112         if (set->full_v1 || set->full_v2 || set->full_v3) {
1113                 /* mandatory anyway */
1114                 vty_out(vty, " codec full-speed%s%s",
1115                         (!set->half_prefer) ? " prefer" : "",
1116                         VTY_NEWLINE);
1117         }
1118         if (set->half_v1 || set->half_v3) {
1119                 if (set->half)
1120                         vty_out(vty, " codec half-speed%s%s",
1121                                 (set->half_prefer) ? " prefer" : "",
1122                                 VTY_NEWLINE);
1123                 else
1124                         vty_out(vty, " no codec half-speed%s", VTY_NEWLINE);
1125         }
1126         if (llist_empty(&set->abbrev))
1127                 vty_out(vty, " no abbrev%s", VTY_NEWLINE);
1128         else {
1129                 llist_for_each_entry(abbrev, &set->abbrev, list)
1130                         vty_out(vty, " abbrev %s %s%s%s%s", abbrev->abbrev,
1131                                 abbrev->number, (abbrev->name[0]) ? " " : "",
1132                                 abbrev->name, VTY_NEWLINE);
1133         }
1134         vty_out(vty, " support%s", VTY_NEWLINE);
1135         SUP_WRITE(sms_ptp, "sms");
1136         SUP_WRITE(a5_1, "a5/1");
1137         SUP_WRITE(a5_2, "a5/2");
1138         SUP_WRITE(a5_3, "a5/3");
1139         SUP_WRITE(a5_4, "a5/4");
1140         SUP_WRITE(a5_5, "a5/5");
1141         SUP_WRITE(a5_6, "a5/6");
1142         SUP_WRITE(a5_7, "a5/7");
1143         SUP_WRITE(p_gsm, "p-gsm");
1144         SUP_WRITE(e_gsm, "e-gsm");
1145         SUP_WRITE(r_gsm, "r-gsm");
1146         SUP_WRITE(dcs, "dcs");
1147         vty_out(vty, "  class-900 %d%s", set->class_900, VTY_NEWLINE);
1148         vty_out(vty, "  class-dcs %d%s", set->class_dcs, VTY_NEWLINE);
1149         switch (set->ch_cap) {
1150         case GSM_CAP_SDCCH:
1151                 vty_out(vty, "  channel-capability sdcch%s", VTY_NEWLINE);
1152                 break;
1153         case GSM_CAP_SDCCH_TCHF:
1154                 vty_out(vty, "  channel-capability sdcch+tchf%s", VTY_NEWLINE);
1155                 break;
1156         case GSM_CAP_SDCCH_TCHF_TCHH:
1157                 vty_out(vty, "  channel-capability sdcch+tchf+tchh%s",
1158                         VTY_NEWLINE);
1159                 break;
1160         }
1161         SUP_WRITE(full_v1, "full-speech-v1");
1162         SUP_WRITE(full_v2, "full-speech-v2");
1163         SUP_WRITE(full_v3, "full-speech-v3");
1164         SUP_WRITE(half_v1, "half-speech-v1");
1165         SUP_WRITE(half_v3, "half-speech-v3");
1166         vty_out(vty, "  min-rxlev %d%s", set->min_rxlev_db, VTY_NEWLINE);
1167         vty_out(vty, "  dsc-max %d%s", set->dsc_max, VTY_NEWLINE);
1168         vty_out(vty, " exit%s", VTY_NEWLINE);
1169         vty_out(vty, " test-sim%s", VTY_NEWLINE);
1170         vty_out(vty, "  imsi %s%s", set->test_imsi, VTY_NEWLINE);
1171         switch (set->test_ki_type) {
1172         case GSM_SIM_KEY_XOR:
1173                 vty_out(vty, "  ki xor %s%s", hexdump(set->test_ki, 12),
1174                         VTY_NEWLINE);
1175                 break;
1176         case GSM_SIM_KEY_COMP128:
1177                 vty_out(vty, "  ki comp128 %s%s", hexdump(set->test_ki, 16),
1178                         VTY_NEWLINE);
1179                 break;
1180         }
1181         vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
1182                 VTY_NEWLINE);
1183         if (set->test_rplmn_valid) {
1184                 vty_out(vty, "  rplmn %s %s",
1185                         gsm_print_mcc(set->test_rplmn_mcc),
1186                         gsm_print_mnc(set->test_rplmn_mnc));
1187                 if (set->test_lac > 0x0000 && set->test_lac < 0xfffe)
1188                         vty_out(vty, " 0x%04x", set->test_lac);
1189                 if (set->test_tmsi != 0xffffffff)
1190                         vty_out(vty, " 0x%08x", set->test_tmsi);
1191                 vty_out(vty, "%s", VTY_NEWLINE);
1192         } else
1193                 vty_out(vty, "  no rplmn%s", VTY_NEWLINE);
1194         vty_out(vty, "  hplmn-search %s%s", (set->test_always) ? "everywhere"
1195                         : "foreign-country", VTY_NEWLINE);
1196         vty_out(vty, " exit%s", VTY_NEWLINE);
1197         vty_out(vty, " %sshutdown%s", (ms->shutdown) ? "" : "no ",
1198                 VTY_NEWLINE);
1199         vty_out(vty, "exit%s", VTY_NEWLINE);
1200         vty_out(vty, "!%s", VTY_NEWLINE);
1201 }
1202
1203 static int config_write(struct vty *vty)
1204 {
1205         struct osmocom_ms *ms;
1206
1207 #ifdef _USE_GPSD
1208         vty_out(vty, "gpsd host %s%s", gps.gpsd_host, VTY_NEWLINE);
1209         vty_out(vty, "gpsd port %s%s", gps.gpsd_port, VTY_NEWLINE);
1210 #else
1211         vty_out(vty, "gps device %s%s", gps.device, VTY_NEWLINE);
1212         if (gps.baud)
1213                 vty_out(vty, "gps baudrate %d%s", gps.baud, VTY_NEWLINE);
1214         else
1215                 vty_out(vty, "gps baudrate default%s", VTY_NEWLINE);
1216 #endif
1217         vty_out(vty, "%sgps enable%s", (gps.enable) ? "" : "no ", VTY_NEWLINE);
1218         vty_out(vty, "!%s", VTY_NEWLINE);
1219
1220         llist_for_each_entry(ms, &ms_list, entity)
1221                 config_write_ms(vty, ms);
1222
1223         return CMD_SUCCESS;
1224 }
1225
1226 DEFUN(cfg_ms_show_this, cfg_ms_show_this_cmd, "show this",
1227         SHOW_STR "Show config of this MS")
1228 {
1229         struct osmocom_ms *ms = vty->index;
1230
1231         config_write_ms(vty, ms);
1232
1233         return CMD_SUCCESS;
1234 }
1235
1236 DEFUN(cfg_ms_layer2, cfg_ms_layer2_cmd, "layer2-socket PATH",
1237         "Define socket path to connect between layer 2 and layer 1\n"
1238         "Unix socket, default '/tmp/osmocom_l2'")
1239 {
1240         struct osmocom_ms *ms = vty->index;
1241         struct gsm_settings *set = &ms->settings;
1242
1243         strncpy(set->layer2_socket_path, argv[0],
1244                 sizeof(set->layer2_socket_path) - 1);
1245
1246         vty_restart(vty, ms);
1247         return CMD_SUCCESS;
1248 }
1249
1250 DEFUN(cfg_ms_sap, cfg_ms_sap_cmd, "sap-socket PATH",
1251         "Define socket path to connect to SIM reader\n"
1252         "Unix socket, default '/tmp/osmocom_sap'")
1253 {
1254         struct osmocom_ms *ms = vty->index;
1255         struct gsm_settings *set = &ms->settings;
1256
1257         strncpy(set->sap_socket_path, argv[0],
1258                 sizeof(set->sap_socket_path) - 1);
1259
1260         vty_restart(vty, ms);
1261         return CMD_SUCCESS;
1262 }
1263
1264 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)",
1265         "Set SIM card type when powering on\nNo SIM interted\n"
1266         "Use SIM from reader\nTest SIM inserted")
1267 {
1268         struct osmocom_ms *ms = vty->index;
1269         struct gsm_settings *set = &ms->settings;
1270
1271         switch (argv[0][0]) {
1272         case 'n':
1273                 set->sim_type = GSM_SIM_TYPE_NONE;
1274                 break;
1275         case 'r':
1276                 set->sim_type = GSM_SIM_TYPE_READER;
1277                 break;
1278         case 't':
1279                 set->sim_type = GSM_SIM_TYPE_TEST;
1280                 break;
1281         default:
1282                 vty_out(vty, "unknown SIM type%s", VTY_NEWLINE);
1283                 return CMD_WARNING;
1284         }
1285
1286         vty_restart(vty, ms);
1287         return CMD_SUCCESS;
1288 }
1289
1290 DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
1291         "Set network selection mode\nAutomatic network selection\n"
1292         "Manual network selection")
1293 {
1294         struct osmocom_ms *ms = vty->index;
1295         struct gsm_settings *set = &ms->settings;
1296         struct msgb *nmsg;
1297
1298         if (!ms->plmn.state) {
1299                 if (argv[0][0] == 'a')
1300                         set->plmn_mode = PLMN_MODE_AUTO;
1301                 else
1302                         set->plmn_mode = PLMN_MODE_MANUAL;
1303
1304                 return CMD_SUCCESS;
1305         }
1306         if (argv[0][0] == 'a')
1307                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
1308         else
1309                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
1310         if (!nmsg)
1311                 return CMD_WARNING;
1312         gsm322_plmn_sendmsg(ms, nmsg);
1313
1314         return CMD_SUCCESS;
1315 }
1316
1317 DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
1318         "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
1319         "Software version digit")
1320 {
1321         struct osmocom_ms *ms = vty->index;
1322         struct gsm_settings *set = &ms->settings;
1323         char *error, *sv = "0";
1324
1325         if (argc >= 2)
1326                 sv = (char *)argv[1];
1327
1328         error = gsm_check_imei(argv[0], sv);
1329         if (error) {
1330                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1331                 return CMD_WARNING;
1332         }
1333
1334         strcpy(set->imei, argv[0]);
1335         strcpy(set->imeisv, argv[0]);
1336         strcpy(set->imeisv + 15, sv);
1337
1338         return CMD_SUCCESS;
1339 }
1340
1341 DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
1342         "Use fixed IMEI on every power on")
1343 {
1344         struct osmocom_ms *ms = vty->index;
1345         struct gsm_settings *set = &ms->settings;
1346
1347         set->imei_random = 0;
1348
1349         vty_restart(vty, ms);
1350         return CMD_SUCCESS;
1351 }
1352
1353 DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
1354         "Use random IMEI on every power on\n"
1355         "Number of trailing digits to randomize")
1356 {
1357         struct osmocom_ms *ms = vty->index;
1358         struct gsm_settings *set = &ms->settings;
1359
1360         set->imei_random = atoi(argv[0]);
1361
1362         vty_restart(vty, ms);
1363         return CMD_SUCCESS;
1364 }
1365
1366 DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi IMSI",
1367         "Use special IMSI for emergency calls\n15 digits IMSI")
1368 {
1369         struct osmocom_ms *ms = vty->index;
1370         struct gsm_settings *set = &ms->settings;
1371         char *error;
1372
1373         error = gsm_check_imsi(argv[0]);
1374         if (error) {
1375                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1376                 return CMD_WARNING;
1377         }
1378         strcpy(set->emergency_imsi, argv[0]);
1379
1380         return CMD_SUCCESS;
1381 }
1382
1383 DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
1384         NO_STR "Use IMSI of SIM or IMEI for emergency calls")
1385 {
1386         struct osmocom_ms *ms = vty->index;
1387         struct gsm_settings *set = &ms->settings;
1388
1389         set->emergency_imsi[0] = '\0';
1390
1391         return CMD_SUCCESS;
1392 }
1393
1394 DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
1395         NO_STR "Disallow waiting calls")
1396 {
1397         struct osmocom_ms *ms = vty->index;
1398         struct gsm_settings *set = &ms->settings;
1399
1400         set->cw = 0;
1401
1402         return CMD_SUCCESS;
1403 }
1404
1405 DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
1406         "Allow waiting calls")
1407 {
1408         struct osmocom_ms *ms = vty->index;
1409         struct gsm_settings *set = &ms->settings;
1410
1411         set->cw = 1;
1412
1413         return CMD_SUCCESS;
1414 }
1415
1416 DEFUN(cfg_no_auto_answer, cfg_ms_no_auto_answer_cmd, "no auto-answer",
1417         NO_STR "Disable auto-answering calls")
1418 {
1419         struct osmocom_ms *ms = vty->index;
1420         struct gsm_settings *set = &ms->settings;
1421
1422         set->auto_answer = 0;
1423
1424         return CMD_SUCCESS;
1425 }
1426
1427 DEFUN(cfg_auto_answer, cfg_ms_auto_answer_cmd, "auto-answer",
1428         "Enable auto-answering calls")
1429 {
1430         struct osmocom_ms *ms = vty->index;
1431         struct gsm_settings *set = &ms->settings;
1432
1433         set->auto_answer = 1;
1434
1435         return CMD_SUCCESS;
1436 }
1437
1438 DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
1439         "Force caller ID presentation")
1440 {
1441         struct osmocom_ms *ms = vty->index;
1442         struct gsm_settings *set = &ms->settings;
1443
1444         set->clip = 1;
1445         set->clir = 0;
1446
1447         return CMD_SUCCESS;
1448 }
1449
1450 DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
1451         "Force caller ID restriction")
1452 {
1453         struct osmocom_ms *ms = vty->index;
1454         struct gsm_settings *set = &ms->settings;
1455
1456         set->clip = 0;
1457         set->clir = 1;
1458
1459         return CMD_SUCCESS;
1460 }
1461
1462 DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
1463         NO_STR "Disable forcing of caller ID presentation")
1464 {
1465         struct osmocom_ms *ms = vty->index;
1466         struct gsm_settings *set = &ms->settings;
1467
1468         set->clip = 0;
1469
1470         return CMD_SUCCESS;
1471 }
1472
1473 DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
1474         NO_STR "Disable forcing of caller ID restriction")
1475 {
1476         struct osmocom_ms *ms = vty->index;
1477         struct gsm_settings *set = &ms->settings;
1478
1479         set->clir = 0;
1480
1481         return CMD_SUCCESS;
1482 }
1483
1484 DEFUN(cfg_ms_tx_power, cfg_ms_tx_power_cmd, "tx-power (auto|full)",
1485         "Set the way to choose transmit power\nControlled by BTS\n"
1486         "Always full power\nFixed GSM power value if supported")
1487 {
1488         struct osmocom_ms *ms = vty->index;
1489         struct gsm_settings *set = &ms->settings;
1490
1491         switch (argv[0][0]) {
1492         case 'a':
1493                 set->alter_tx_power = 0;
1494                 break;
1495         case 'f':
1496                 set->alter_tx_power = 1;
1497                 set->alter_tx_power_value = 0;
1498                 break;
1499         }
1500
1501         return CMD_SUCCESS;
1502 }
1503
1504 DEFUN(cfg_ms_tx_power_val, cfg_ms_tx_power_val_cmd, "tx-power <0-31>",
1505         "Set the way to choose transmit power\n"
1506         "Fixed GSM power value if supported")
1507 {
1508         struct osmocom_ms *ms = vty->index;
1509         struct gsm_settings *set = &ms->settings;
1510
1511         set->alter_tx_power = 1;
1512         set->alter_tx_power_value = atoi(argv[0]);
1513
1514         return CMD_SUCCESS;
1515 }
1516
1517 DEFUN(cfg_ms_sim_delay, cfg_ms_sim_delay_cmd, "simulated-delay <-128-127>",
1518         "Simulate a lower or higher distance from the BTS\n"
1519         "Delay in half bits (distance in 553.85 meter steps)")
1520 {
1521         struct osmocom_ms *ms = vty->index;
1522         struct gsm_settings *set = &ms->settings;
1523
1524         set->alter_delay = atoi(argv[0]);
1525         gsm48_rr_alter_delay(ms);
1526
1527         return CMD_SUCCESS;
1528 }
1529
1530 DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
1531         NO_STR "Do not simulate a lower or higher distance from the BTS")
1532 {
1533         struct osmocom_ms *ms = vty->index;
1534         struct gsm_settings *set = &ms->settings;
1535
1536         set->alter_delay = 0;
1537         gsm48_rr_alter_delay(ms);
1538
1539         return CMD_SUCCESS;
1540 }
1541
1542 DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023>",
1543         "Stick to the given cell\nARFCN of the cell to stick to")
1544 {
1545         struct osmocom_ms *ms = vty->index;
1546         struct gsm_settings *set = &ms->settings;
1547
1548         set->stick = 1;
1549         set->stick_arfcn = atoi(argv[0]);
1550
1551         return CMD_SUCCESS;
1552 }
1553
1554 DEFUN(cfg_ms_no_stick, cfg_ms_no_stick_cmd, "no stick",
1555         NO_STR "Do not stick to any cell")
1556 {
1557         struct osmocom_ms *ms = vty->index;
1558         struct gsm_settings *set = &ms->settings;
1559
1560         set->stick = 0;
1561
1562         return CMD_SUCCESS;
1563 }
1564
1565 DEFUN(cfg_ms_lupd, cfg_ms_lupd_cmd, "location-updating",
1566         "Allow location updating")
1567 {
1568         struct osmocom_ms *ms = vty->index;
1569         struct gsm_settings *set = &ms->settings;
1570
1571         set->no_lupd = 0;
1572
1573         return CMD_SUCCESS;
1574 }
1575
1576 DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating",
1577         NO_STR "Do not allow location updating")
1578 {
1579         struct osmocom_ms *ms = vty->index;
1580         struct gsm_settings *set = &ms->settings;
1581
1582         set->no_lupd = 1;
1583
1584         return CMD_SUCCESS;
1585 }
1586
1587 DEFUN(cfg_codec_full, cfg_ms_codec_full_cmd, "codec full-speed",
1588         "Enable codec\nFull speed speech codec")
1589 {
1590         struct osmocom_ms *ms = vty->index;
1591         struct gsm_settings *set = &ms->settings;
1592
1593         if (!set->full_v1 && !set->full_v2 && !set->full_v3) {
1594                 vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
1595                 return CMD_WARNING;
1596         }
1597
1598         return CMD_SUCCESS;
1599 }
1600
1601 DEFUN(cfg_codec_full_pref, cfg_ms_codec_full_pref_cmd, "codec full-speed "
1602         "prefer",
1603         "Enable codec\nFull speed speech codec\nPrefer this codec")
1604 {
1605         struct osmocom_ms *ms = vty->index;
1606         struct gsm_settings *set = &ms->settings;
1607
1608         if (!set->full_v1 && !set->full_v2 && !set->full_v3) {
1609                 vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
1610                 return CMD_WARNING;
1611         }
1612
1613         set->half_prefer = 0;
1614
1615         return CMD_SUCCESS;
1616 }
1617
1618 DEFUN(cfg_codec_half, cfg_ms_codec_half_cmd, "codec half-speed",
1619         "Enable codec\nHalf speed speech codec")
1620 {
1621         struct osmocom_ms *ms = vty->index;
1622         struct gsm_settings *set = &ms->settings;
1623
1624         if (!set->half_v1 && !set->half_v3) {
1625                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1626                 return CMD_WARNING;
1627         }
1628
1629         set->half = 1;
1630
1631         return CMD_SUCCESS;
1632 }
1633
1634 DEFUN(cfg_codec_half_pref, cfg_ms_codec_half_pref_cmd, "codec half-speed "
1635         "prefer",
1636         "Enable codec\nHalf speed speech codec\nPrefer this codec")
1637 {
1638         struct osmocom_ms *ms = vty->index;
1639         struct gsm_settings *set = &ms->settings;
1640
1641         if (!set->half_v1 && !set->half_v3) {
1642                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1643                 return CMD_WARNING;
1644         }
1645
1646         set->half = 1;
1647         set->half_prefer = 1;
1648
1649         return CMD_SUCCESS;
1650 }
1651
1652 DEFUN(cfg_no_codec_half, cfg_ms_no_codec_half_cmd, "no codec half-speed",
1653         NO_STR "Disable codec\nHalf speed speech codec")
1654 {
1655         struct osmocom_ms *ms = vty->index;
1656         struct gsm_settings *set = &ms->settings;
1657
1658         if (!set->half_v1 && !set->half_v3) {
1659                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1660                 return CMD_WARNING;
1661         }
1662
1663         set->half = 0;
1664         set->half_prefer = 0;
1665
1666         return CMD_SUCCESS;
1667 }
1668
1669 DEFUN(cfg_abbrev, cfg_ms_abbrev_cmd, "abbrev ABBREVIATION NUMBER [NAME]",
1670         "Store given abbreviation number\n1-3 digits abbreviation\n"
1671         "Number to store for the abbreviation "
1672         "(Use digits '0123456789*#abc', and '+' to dial international)\n"
1673         "Name of the abbreviation")
1674 {
1675         struct osmocom_ms *ms = vty->index;
1676         struct gsm_settings *set = &ms->settings;
1677         struct gsm_settings_abbrev *abbrev;
1678         int i;
1679
1680         llist_for_each_entry(abbrev, &set->abbrev, list) {
1681                 if (!strcmp(argv[0], abbrev->abbrev)) {
1682                         vty_out(vty, "Given abbreviation '%s' already stored, "
1683                                 "delete first!%s", argv[0], VTY_NEWLINE);
1684                         return CMD_WARNING;
1685                 }
1686         }
1687
1688         if (strlen(argv[0]) >= sizeof(abbrev->abbrev)) {
1689                 vty_out(vty, "Given abbreviation too long%s", VTY_NEWLINE);
1690                 return CMD_WARNING;
1691         }
1692
1693         for (i = 0; i < strlen(argv[0]); i++) {
1694                 if (argv[0][i] < '0' || argv[0][i] > '9') {
1695                         vty_out(vty, "Given abbreviation must have digits "
1696                                 "0..9 only!%s", VTY_NEWLINE);
1697                         return CMD_WARNING;
1698                 }
1699         }
1700
1701         if (vty_check_number(vty, argv[1]))
1702                 return CMD_WARNING;
1703
1704         abbrev = talloc_zero(l23_ctx, struct gsm_settings_abbrev);
1705         if (!abbrev) {
1706                 vty_out(vty, "No Memory!%s", VTY_NEWLINE);
1707                 return CMD_WARNING;
1708         }
1709         llist_add_tail(&abbrev->list, &set->abbrev);
1710         strncpy(abbrev->abbrev, argv[0], sizeof(abbrev->abbrev) - 1);
1711         strncpy(abbrev->number, argv[1], sizeof(abbrev->number) - 1);
1712         if (argc >= 3)
1713                 strncpy(abbrev->name, argv[2], sizeof(abbrev->name) - 1);
1714
1715         return CMD_SUCCESS;
1716 }
1717
1718 DEFUN(cfg_no_abbrev, cfg_ms_no_abbrev_cmd, "no abbrev [ABBREVIATION]",
1719         NO_STR "Remove given abbreviation number or all numbers\n"
1720         "Abbreviation number to remove")
1721 {
1722         struct osmocom_ms *ms = vty->index;
1723         struct gsm_settings *set = &ms->settings;
1724         struct gsm_settings_abbrev *abbrev, *abbrev2;
1725         uint8_t deleted = 0;
1726
1727         llist_for_each_entry_safe(abbrev, abbrev2, &set->abbrev, list) {
1728                 if (argc < 1 || !strcmp(argv[0], abbrev->abbrev)) {
1729                         llist_del(&abbrev->list);
1730                         deleted = 1;
1731                 }
1732         }
1733
1734         if (argc >= 1 && !deleted) {
1735                 vty_out(vty, "Given abbreviation '%s' not found!%s",
1736                         argv[0], VTY_NEWLINE);
1737                 return CMD_WARNING;
1738         }
1739
1740         return CMD_SUCCESS;
1741 }
1742
1743 static int config_write_dummy(struct vty *vty)
1744 {
1745         return CMD_SUCCESS;
1746 }
1747
1748 /* per support config */
1749 DEFUN(cfg_ms_support, cfg_ms_support_cmd, "support",
1750         "Define supported features")
1751 {
1752         vty->node = SUPPORT_NODE;
1753
1754         return CMD_SUCCESS;
1755 }
1756
1757 #define SUP_EN(cfg, cfg_cmd, item, cmd, desc, restart) \
1758 DEFUN(cfg, cfg_cmd, cmd, "Enable " desc "support") \
1759 { \
1760         struct osmocom_ms *ms = vty->index; \
1761         struct gsm_settings *set = &ms->settings; \
1762         struct gsm_support *sup = &ms->support; \
1763         if (!sup->item) { \
1764                 vty_out(vty, desc " not supported%s", VTY_NEWLINE); \
1765                 if (vty_reading) \
1766                         return CMD_SUCCESS; \
1767                 return CMD_WARNING; \
1768         } \
1769         if (restart) \
1770                 vty_restart(vty, ms); \
1771         set->item = 1; \
1772         return CMD_SUCCESS; \
1773 }
1774
1775 #define SUP_DI(cfg, cfg_cmd, item, cmd, desc, restart) \
1776 DEFUN(cfg, cfg_cmd, "no " cmd, NO_STR "Disable " desc " support") \
1777 { \
1778         struct osmocom_ms *ms = vty->index; \
1779         struct gsm_settings *set = &ms->settings; \
1780         struct gsm_support *sup = &ms->support; \
1781         if (!sup->item) { \
1782                 vty_out(vty, desc " not supported%s", VTY_NEWLINE); \
1783                 if (vty_reading) \
1784                         return CMD_SUCCESS; \
1785                 return CMD_WARNING; \
1786         } \
1787         if (restart) \
1788                 vty_restart(vty, ms); \
1789         set->item = 0; \
1790         return CMD_SUCCESS; \
1791 }
1792
1793 #define SET_EN(cfg, cfg_cmd, item, cmd, desc, restart) \
1794 DEFUN(cfg, cfg_cmd, cmd, "Enable " desc "support") \
1795 { \
1796         struct osmocom_ms *ms = vty->index; \
1797         struct gsm_settings *set = &ms->settings; \
1798         if (restart) \
1799                 vty_restart(vty, ms); \
1800         set->item = 1; \
1801         return CMD_SUCCESS; \
1802 }
1803
1804 #define SET_DI(cfg, cfg_cmd, item, cmd, desc, restart) \
1805 DEFUN(cfg, cfg_cmd, "no " cmd, NO_STR "Disable " desc " support") \
1806 { \
1807         struct osmocom_ms *ms = vty->index; \
1808         struct gsm_settings *set = &ms->settings; \
1809         if (restart) \
1810                 vty_restart(vty, ms); \
1811         set->item = 0; \
1812         return CMD_SUCCESS; \
1813 }
1814
1815 SET_EN(cfg_ms_sup_dtmf, cfg_ms_sup_dtmf_cmd, cc_dtmf, "dtmf", "DTMF", 0);
1816 SET_DI(cfg_ms_sup_no_dtmf, cfg_ms_sup_no_dtmf_cmd, cc_dtmf, "dtmf", "DTMF", 0);
1817 SUP_EN(cfg_ms_sup_sms, cfg_ms_sup_sms_cmd, sms_ptp, "sms", "SMS", 0);
1818 SUP_DI(cfg_ms_sup_no_sms, cfg_ms_sup_no_sms_cmd, sms_ptp, "sms", "SMS", 0);
1819 SUP_EN(cfg_ms_sup_a5_1, cfg_ms_sup_a5_1_cmd, a5_1, "a5/1", "A5/1", 0);
1820 SUP_DI(cfg_ms_sup_no_a5_1, cfg_ms_sup_no_a5_1_cmd, a5_1, "a5/1", "A5/1", 0);
1821 SUP_EN(cfg_ms_sup_a5_2, cfg_ms_sup_a5_2_cmd, a5_2, "a5/2", "A5/2", 0);
1822 SUP_DI(cfg_ms_sup_no_a5_2, cfg_ms_sup_no_a5_2_cmd, a5_2, "a5/2", "A5/2", 0);
1823 SUP_EN(cfg_ms_sup_a5_3, cfg_ms_sup_a5_3_cmd, a5_3, "a5/3", "A5/3", 0);
1824 SUP_DI(cfg_ms_sup_no_a5_3, cfg_ms_sup_no_a5_3_cmd, a5_3, "a5/3", "A5/3", 0);
1825 SUP_EN(cfg_ms_sup_a5_4, cfg_ms_sup_a5_4_cmd, a5_4, "a5/4", "A5/4", 0);
1826 SUP_DI(cfg_ms_sup_no_a5_4, cfg_ms_sup_no_a5_4_cmd, a5_4, "a5/4", "A5/4", 0);
1827 SUP_EN(cfg_ms_sup_a5_5, cfg_ms_sup_a5_5_cmd, a5_5, "a5/5", "A5/5", 0);
1828 SUP_DI(cfg_ms_sup_no_a5_5, cfg_ms_sup_no_a5_5_cmd, a5_5, "a5/5", "A5/5", 0);
1829 SUP_EN(cfg_ms_sup_a5_6, cfg_ms_sup_a5_6_cmd, a5_6, "a5/6", "A5/6", 0);
1830 SUP_DI(cfg_ms_sup_no_a5_6, cfg_ms_sup_no_a5_6_cmd, a5_6, "a5/6", "A5/6", 0);
1831 SUP_EN(cfg_ms_sup_a5_7, cfg_ms_sup_a5_7_cmd, a5_7, "a5/7", "A5/7", 0);
1832 SUP_DI(cfg_ms_sup_no_a5_7, cfg_ms_sup_no_a5_7_cmd, a5_7, "a5/7", "A5/7", 1);
1833 SUP_EN(cfg_ms_sup_p_gsm, cfg_ms_sup_p_gsm_cmd, p_gsm, "p-gsm", "P-GSM (900)",
1834         1);
1835 SUP_DI(cfg_ms_sup_no_p_gsm, cfg_ms_sup_no_p_gsm_cmd, p_gsm, "p-gsm",
1836         "P-GSM (900)", 1);
1837 SUP_EN(cfg_ms_sup_e_gsm, cfg_ms_sup_e_gsm_cmd, e_gsm, "e-gsm", "E-GSM (850)",
1838         1);
1839 SUP_DI(cfg_ms_sup_no_e_gsm, cfg_ms_sup_no_e_gsm_cmd, e_gsm, "e-gsm",
1840         "E-GSM (850)", 1);
1841 SUP_EN(cfg_ms_sup_r_gsm, cfg_ms_sup_r_gsm_cmd, r_gsm, "r-gsm", "R-GSM (850)",
1842         1);
1843 SUP_DI(cfg_ms_sup_no_r_gsm, cfg_ms_sup_no_r_gsm_cmd, r_gsm, "r-gsm",
1844         "R-GSM (850)", 1);
1845 SUP_EN(cfg_ms_sup_dcs, cfg_ms_sup_dcs_cmd, dcs, "dcs", "DCS (1800)", 0);
1846 SUP_DI(cfg_ms_sup_no_dcs, cfg_ms_sup_no_dcs_cmd, dcs, "dcs", "DCS (1800)", 0);
1847
1848 DEFUN(cfg_ms_sup_class_900, cfg_ms_sup_class_900_cmd, "class-900 (1|2|3|4|5)",
1849         "Select power class for GSM 850/900\n"
1850         "20 Watts\n"
1851         "8 Watts\n"
1852         "5 Watts\n"
1853         "2 Watts\n"
1854         "0.8 Watts")
1855 {
1856         struct osmocom_ms *ms = vty->index;
1857         struct gsm_settings *set = &ms->settings;
1858         struct gsm_support *sup = &ms->support;
1859
1860         set->class_900 = atoi(argv[0]);
1861
1862         if (set->class_900 < sup->class_900 && !vty_reading)
1863                 vty_out(vty, "You selected an higher class than supported "
1864                         " by hardware!%s", VTY_NEWLINE);
1865
1866         return CMD_SUCCESS;
1867 }
1868
1869 DEFUN(cfg_ms_sup_class_dcs, cfg_ms_sup_class_dcs_cmd, "class-dcs (1|2|3)",
1870         "Select power class for DCS 1800\n"
1871         "1 Watt\n"
1872         "0.25 Watts\n"
1873         "4 Watts")
1874 {
1875         struct osmocom_ms *ms = vty->index;
1876         struct gsm_settings *set = &ms->settings;
1877         struct gsm_support *sup = &ms->support;
1878
1879         set->class_dcs = atoi(argv[0]);
1880
1881         if (((set->class_dcs + 1) & 3) < ((sup->class_dcs + 1) & 3)
1882          && !vty_reading)
1883                 vty_out(vty, "You selected an higher class than supported "
1884                         " by hardware!%s", VTY_NEWLINE);
1885
1886         return CMD_SUCCESS;
1887 }
1888
1889 DEFUN(cfg_ms_sup_ch_cap, cfg_ms_sup_ch_cap_cmd, "channel-capability "
1890         "(sdcch|sdcch+tchf|sdcch+tchf+tchh)",
1891         "Select channel capability\nSDCCH only\nSDCCH + TCH/F\nSDCCH + TCH/H")
1892 {
1893         struct osmocom_ms *ms = vty->index;
1894         struct gsm_settings *set = &ms->settings;
1895         struct gsm_support *sup = &ms->support;
1896         uint8_t ch_cap;
1897
1898         if (!strcmp(argv[0], "sdcch+tchf+tchh"))
1899                 ch_cap = GSM_CAP_SDCCH_TCHF_TCHH;
1900         else if (!strcmp(argv[0], "sdcch+tchf"))
1901                 ch_cap = GSM_CAP_SDCCH_TCHF;
1902         else
1903                 ch_cap = GSM_CAP_SDCCH;
1904
1905         if (ch_cap > sup->ch_cap && !vty_reading) {
1906                 vty_out(vty, "You selected an higher capability than supported "
1907                         " by hardware!%s", VTY_NEWLINE);
1908                 return CMD_WARNING;
1909         }
1910
1911         if (ch_cap != set->ch_cap
1912          && (ch_cap == GSM_CAP_SDCCH || set->ch_cap == GSM_CAP_SDCCH))
1913                 vty_restart(vty, ms);
1914
1915         set->ch_cap = ch_cap;
1916
1917         return CMD_SUCCESS;
1918 }
1919
1920 SUP_EN(cfg_ms_sup_full_v1, cfg_ms_sup_full_v1_cmd, full_v1, "full-speech-v1",
1921         "Full rate speech V1", 0);
1922 SUP_DI(cfg_ms_sup_no_full_v1, cfg_ms_sup_no_full_v1_cmd, full_v1,
1923         "full-speech-v1", "Full rate speech V1", 0);
1924 SUP_EN(cfg_ms_sup_full_v2, cfg_ms_sup_full_v2_cmd, full_v2, "full-speech-v2",
1925         "Full rate speech V2 (EFR)", 0);
1926 SUP_DI(cfg_ms_sup_no_full_v2, cfg_ms_sup_no_full_v2_cmd, full_v2,
1927         "full-speech-v2", "Full rate speech V2 (EFR)", 0);
1928 SUP_EN(cfg_ms_sup_full_v3, cfg_ms_sup_full_v3_cmd, full_v3, "full-speech-v3",
1929         "Full rate speech V3 (AMR)", 0);
1930 SUP_DI(cfg_ms_sup_no_full_v3, cfg_ms_sup_no_full_v3_cmd, full_v3,
1931         "full-speech-v3", "Full rate speech V3 (AMR)", 0);
1932 SUP_EN(cfg_ms_sup_half_v1, cfg_ms_sup_half_v1_cmd, half_v1, "half-speech-v1",
1933         "Half rate speech V1", 0);
1934 SUP_DI(cfg_ms_sup_no_half_v1, cfg_ms_sup_no_half_v1_cmd, half_v1,
1935         "half-speech-v1", "Half rate speech V1", 0);
1936 SUP_EN(cfg_ms_sup_half_v3, cfg_ms_sup_half_v3_cmd, half_v3, "half-speech-v3",
1937         "Half rate speech V3 (AMR)", 0);
1938 SUP_DI(cfg_ms_sup_no_half_v3, cfg_ms_sup_no_half_v3_cmd, half_v3,
1939         "half-speech-v3", "Half rate speech V3 (AMR)", 0);
1940
1941 DEFUN(cfg_ms_sup_min_rxlev, cfg_ms_sup_min_rxlev_cmd, "min-rxlev <-110--47>",
1942         "Set the minimum receive level to select a cell\n"
1943         "Minimum receive level from -110 dBm to -47 dBm")
1944 {
1945         struct osmocom_ms *ms = vty->index;
1946         struct gsm_settings *set = &ms->settings;
1947
1948         set->min_rxlev_db = atoi(argv[0]);
1949
1950         return CMD_SUCCESS;
1951 }
1952
1953 DEFUN(cfg_ms_sup_dsc_max, cfg_ms_sup_dsc_max_cmd, "dsc-max <90-500>",
1954         "Set the maximum DSC value. Standard is 90. Increase to make mobile "
1955         "more reliable against bad RX signal. This increase the propability "
1956         "of missing a paging requests\n"
1957         "DSC initial and maximum value (standard is 90)")
1958 {
1959         struct osmocom_ms *ms = vty->index;
1960         struct gsm_settings *set = &ms->settings;
1961
1962         set->dsc_max = atoi(argv[0]);
1963
1964         return CMD_SUCCESS;
1965 }
1966
1967 /* per testsim config */
1968 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
1969         "Configure test SIM emulation")
1970 {
1971         vty->node = TESTSIM_NODE;
1972
1973         return CMD_SUCCESS;
1974 }
1975
1976 DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
1977         "Set IMSI on test card\n15 digits IMSI")
1978 {
1979         struct osmocom_ms *ms = vty->index;
1980         struct gsm_settings *set = &ms->settings;
1981         char *error = gsm_check_imsi(argv[0]);
1982
1983         if (error) {
1984                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1985                 return CMD_WARNING;
1986         }
1987
1988         strcpy(set->test_imsi, argv[0]);
1989
1990         vty_restart(vty, ms);
1991         return CMD_SUCCESS;
1992 }
1993
1994 #define HEX_STR "\nByte as two digits hexadecimal"
1995 DEFUN(cfg_test_ki_xor, cfg_test_ki_xor_cmd, "ki xor HEX HEX HEX HEX HEX HEX "
1996         "HEX HEX HEX HEX HEX HEX",
1997         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1998         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR)
1999 {
2000         struct osmocom_ms *ms = vty->index;
2001         struct gsm_settings *set = &ms->settings;
2002         uint8_t ki[12];
2003         const char *p;
2004         int i;
2005
2006         for (i = 0; i < 12; i++) {
2007                 p = argv[i];
2008                 if (!strncmp(p, "0x", 2))
2009                         p += 2;
2010                 if (strlen(p) != 2) {
2011                         vty_out(vty, "Expecting two digits hex value (with or "
2012                                 "without 0x in front)%s", VTY_NEWLINE);
2013                         return CMD_WARNING;
2014                 }
2015                 ki[i] = strtoul(p, NULL, 16);
2016         }
2017
2018         set->test_ki_type = GSM_SIM_KEY_XOR;
2019         memcpy(set->test_ki, ki, 12);
2020         return CMD_SUCCESS;
2021 }
2022
2023 DEFUN(cfg_test_ki_comp128, cfg_test_ki_comp128_cmd, "ki comp128 HEX HEX HEX "
2024         "HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX",
2025         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
2026         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR
2027         HEX_STR HEX_STR HEX_STR HEX_STR)
2028 {
2029         struct osmocom_ms *ms = vty->index;
2030         struct gsm_settings *set = &ms->settings;
2031         uint8_t ki[16];
2032         const char *p;
2033         int i;
2034
2035         for (i = 0; i < 16; i++) {
2036                 p = argv[i];
2037                 if (!strncmp(p, "0x", 2))
2038                         p += 2;
2039                 if (strlen(p) != 2) {
2040                         vty_out(vty, "Expecting two digits hex value (with or "
2041                                 "without 0x in front)%s", VTY_NEWLINE);
2042                         return CMD_WARNING;
2043                 }
2044                 ki[i] = strtoul(p, NULL, 16);
2045         }
2046
2047         set->test_ki_type = GSM_SIM_KEY_COMP128;
2048         memcpy(set->test_ki, ki, 16);
2049         return CMD_SUCCESS;
2050 }
2051
2052 DEFUN(cfg_test_barr, cfg_test_barr_cmd, "barred-access",
2053         "Allow access to barred cells")
2054 {
2055         struct osmocom_ms *ms = vty->index;
2056         struct gsm_settings *set = &ms->settings;
2057
2058         set->test_barr = 1;
2059
2060         return CMD_SUCCESS;
2061 }
2062
2063 DEFUN(cfg_test_no_barr, cfg_test_no_barr_cmd, "no barred-access",
2064         NO_STR "Deny access to barred cells")
2065 {
2066         struct osmocom_ms *ms = vty->index;
2067         struct gsm_settings *set = &ms->settings;
2068
2069         set->test_barr = 0;
2070
2071         return CMD_SUCCESS;
2072 }
2073
2074 DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
2075         NO_STR "Unset Registered PLMN")
2076 {
2077         struct osmocom_ms *ms = vty->index;
2078         struct gsm_settings *set = &ms->settings;
2079
2080         set->test_rplmn_valid = 0;
2081
2082         vty_restart(vty, ms);
2083         return CMD_SUCCESS;
2084 }
2085
2086 DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC [LAC] [TMSI]",
2087         "Set Registered PLMN\nMobile Country Code\nMobile Network Code\n"
2088         "Optionally set locatio area code\n"
2089         "Optionally set current assigned TMSI")
2090 {
2091         struct osmocom_ms *ms = vty->index;
2092         struct gsm_settings *set = &ms->settings;
2093         uint16_t mcc = gsm_input_mcc((char *)argv[0]),
2094                  mnc = gsm_input_mnc((char *)argv[1]);
2095
2096         if (!mcc) {
2097                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
2098                 return CMD_WARNING;
2099         }
2100         if (!mnc) {
2101                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
2102                 return CMD_WARNING;
2103         }
2104         set->test_rplmn_valid = 1;
2105         set->test_rplmn_mcc = mcc;
2106         set->test_rplmn_mnc = mnc;
2107
2108         if (argc >= 3)
2109                 set->test_lac = strtoul(argv[2], NULL, 16);
2110         else
2111                 set->test_lac = 0xfffe;
2112
2113         if (argc >= 4)
2114                 set->test_tmsi = strtoul(argv[3], NULL, 16);
2115         else
2116                 set->test_tmsi = 0xffffffff;
2117
2118         vty_restart(vty, ms);
2119         return CMD_SUCCESS;
2120 }
2121
2122 DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-country)",
2123         "Set Home PLMN search mode\n"
2124         "Search for HPLMN when on any other network\n"
2125         "Search for HPLMN when in a different country")
2126 {
2127         struct osmocom_ms *ms = vty->index;
2128         struct gsm_settings *set = &ms->settings;
2129
2130         switch (argv[0][0]) {
2131         case 'e':
2132                 set->test_always = 1;
2133                 break;
2134         case 'f':
2135                 set->test_always = 0;
2136                 break;
2137         }
2138
2139         vty_restart(vty, ms);
2140         return CMD_SUCCESS;
2141 }
2142
2143 DEFUN(cfg_no_shutdown, cfg_ms_no_shutdown_cmd, "no shutdown",
2144         NO_STR "Activate and run MS")
2145 {
2146         struct osmocom_ms *ms = vty->index, *tmp;
2147         int rc;
2148
2149         if (ms->shutdown != 2)
2150                 return CMD_SUCCESS;
2151
2152         llist_for_each_entry(tmp, &ms_list, entity) {
2153                 if (tmp->shutdown == 2)
2154                         continue;
2155                 if (!strcmp(ms->settings.layer2_socket_path,
2156                                 tmp->settings.layer2_socket_path)) {
2157                         vty_out(vty, "Cannot start MS '%s', because MS '%s' "
2158                                 "use the same layer2-socket.%sPlease shutdown "
2159                                 "MS '%s' first.%s", ms->name, tmp->name,
2160                                 VTY_NEWLINE, tmp->name, VTY_NEWLINE);
2161                         return CMD_WARNING;
2162                 }
2163                 if (!strcmp(ms->settings.sap_socket_path,
2164                                 tmp->settings.sap_socket_path)) {
2165                         vty_out(vty, "Cannot start MS '%s', because MS '%s' "
2166                                 "use the same sap-socket.%sPlease shutdown "
2167                                 "MS '%s' first.%s", ms->name, tmp->name,
2168                                 VTY_NEWLINE, tmp->name, VTY_NEWLINE);
2169                         return CMD_WARNING;
2170                 }
2171         }
2172
2173         rc = mobile_init(ms);
2174         if (rc < 0) {
2175                 vty_out(vty, "Connection to layer 1 failed!%s",
2176                         VTY_NEWLINE);
2177                 return CMD_WARNING;
2178         }
2179
2180         return CMD_SUCCESS;
2181 }
2182
2183 DEFUN(cfg_shutdown, cfg_ms_shutdown_cmd, "shutdown",
2184         "Shut down and deactivate MS")
2185 {
2186         struct osmocom_ms *ms = vty->index;
2187
2188         if (ms->shutdown == 0)
2189                 mobile_exit(ms, 0);
2190
2191         return CMD_SUCCESS;
2192 }
2193
2194 DEFUN(cfg_shutdown_force, cfg_ms_shutdown_force_cmd, "shutdown force",
2195         "Shut down and deactivate MS\nDo not perform IMSI detach")
2196 {
2197         struct osmocom_ms *ms = vty->index;
2198
2199         if (ms->shutdown <= 1)
2200                 mobile_exit(ms, 1);
2201
2202         return CMD_SUCCESS;
2203 }
2204
2205 enum node_type ms_vty_go_parent(struct vty *vty)
2206 {
2207         switch (vty->node) {
2208         case MS_NODE:
2209                 vty->node = CONFIG_NODE;
2210                 vty->index = NULL;
2211                 break;
2212         case TESTSIM_NODE:
2213         case SUPPORT_NODE:
2214                 vty->node = MS_NODE;
2215                 break;
2216         default:
2217                 vty->node = CONFIG_NODE;
2218         }
2219
2220         return vty->node;
2221 }
2222
2223 /* Down vty node level. */
2224 gDEFUN(ournode_exit,
2225        ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
2226 {
2227         switch (vty->node) {
2228         case MS_NODE:
2229                 vty->node = CONFIG_NODE;
2230                 vty->index = NULL;
2231                 break;
2232         case TESTSIM_NODE:
2233         case SUPPORT_NODE:
2234                 vty->node = MS_NODE;
2235                 break;
2236         default:
2237                 break;
2238         }
2239         return CMD_SUCCESS;
2240 }
2241
2242 /* End of configuration. */
2243 gDEFUN(ournode_end,
2244        ournode_end_cmd, "end", "End current mode and change to enable mode.")
2245 {
2246         switch (vty->node) {
2247         case VIEW_NODE:
2248         case ENABLE_NODE:
2249                 /* Nothing to do. */
2250                 break;
2251         case CONFIG_NODE:
2252         case VTY_NODE:
2253         case MS_NODE:
2254         case TESTSIM_NODE:
2255         case SUPPORT_NODE:
2256                 vty_config_unlock(vty);
2257                 vty->node = ENABLE_NODE;
2258                 vty->index = NULL;
2259                 vty->index_sub = NULL;
2260                 break;
2261         default:
2262                 break;
2263         }
2264         return CMD_SUCCESS;
2265 }
2266
2267 DEFUN(off, off_cmd, "off",
2268         "Turn mobiles off (shutdown) and exit")
2269 {
2270         dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
2271
2272         return CMD_SUCCESS;
2273 }
2274
2275 #define SUP_NODE(item) \
2276         install_element(SUPPORT_NODE, &cfg_ms_sup_item_cmd);
2277
2278 int ms_vty_init(void)
2279 {
2280         install_element_ve(&show_ms_cmd);
2281         install_element_ve(&show_subscr_cmd);
2282         install_element_ve(&show_support_cmd);
2283         install_element_ve(&show_cell_cmd);
2284         install_element_ve(&show_cell_si_cmd);
2285         install_element_ve(&show_ba_cmd);
2286         install_element_ve(&show_forb_la_cmd);
2287         install_element_ve(&show_forb_plmn_cmd);
2288         install_element_ve(&monitor_network_cmd);
2289         install_element_ve(&no_monitor_network_cmd);
2290         install_element(ENABLE_NODE, &off_cmd);
2291
2292         install_element(ENABLE_NODE, &sim_test_cmd);
2293         install_element(ENABLE_NODE, &sim_reader_cmd);
2294         install_element(ENABLE_NODE, &sim_remove_cmd);
2295         install_element(ENABLE_NODE, &sim_pin_cmd);
2296         install_element(ENABLE_NODE, &sim_disable_pin_cmd);
2297         install_element(ENABLE_NODE, &sim_enable_pin_cmd);
2298         install_element(ENABLE_NODE, &sim_change_pin_cmd);
2299         install_element(ENABLE_NODE, &sim_unblock_pin_cmd);
2300         install_element(ENABLE_NODE, &sim_lai_cmd);
2301         install_element(ENABLE_NODE, &network_search_cmd);
2302         install_element(ENABLE_NODE, &network_show_cmd);
2303         install_element(ENABLE_NODE, &network_select_cmd);
2304         install_element(ENABLE_NODE, &call_cmd);
2305         install_element(ENABLE_NODE, &call_retr_cmd);
2306         install_element(ENABLE_NODE, &call_dtmf_cmd);
2307
2308 #ifdef _USE_GPSD
2309         install_element(CONFIG_NODE, &cfg_gps_host_cmd);
2310 #else
2311         install_element(CONFIG_NODE, &cfg_gps_device_cmd);
2312         install_element(CONFIG_NODE, &cfg_gps_baud_cmd);
2313 #endif
2314         install_element(CONFIG_NODE, &cfg_gps_enable_cmd);
2315         install_element(CONFIG_NODE, &cfg_no_gps_enable_cmd);
2316
2317         install_element(CONFIG_NODE, &cfg_ms_cmd);
2318         install_element(CONFIG_NODE, &cfg_ms_create_cmd);
2319         install_element(CONFIG_NODE, &cfg_ms_rename_cmd);
2320         install_element(CONFIG_NODE, &cfg_no_ms_cmd);
2321         install_element(CONFIG_NODE, &ournode_end_cmd);
2322         install_node(&ms_node, config_write);
2323         install_default(MS_NODE);
2324         install_element(MS_NODE, &ournode_exit_cmd);
2325         install_element(MS_NODE, &ournode_end_cmd);
2326         install_element(MS_NODE, &cfg_ms_show_this_cmd);
2327         install_element(MS_NODE, &cfg_ms_layer2_cmd);
2328         install_element(MS_NODE, &cfg_ms_sap_cmd);
2329         install_element(MS_NODE, &cfg_ms_sim_cmd);
2330         install_element(MS_NODE, &cfg_ms_mode_cmd);
2331         install_element(MS_NODE, &cfg_ms_imei_cmd);
2332         install_element(MS_NODE, &cfg_ms_imei_fixed_cmd);
2333         install_element(MS_NODE, &cfg_ms_imei_random_cmd);
2334         install_element(MS_NODE, &cfg_ms_no_emerg_imsi_cmd);
2335         install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
2336         install_element(MS_NODE, &cfg_ms_cw_cmd);
2337         install_element(MS_NODE, &cfg_ms_no_cw_cmd);
2338         install_element(MS_NODE, &cfg_ms_auto_answer_cmd);
2339         install_element(MS_NODE, &cfg_ms_no_auto_answer_cmd);
2340         install_element(MS_NODE, &cfg_ms_clip_cmd);
2341         install_element(MS_NODE, &cfg_ms_clir_cmd);
2342         install_element(MS_NODE, &cfg_ms_no_clip_cmd);
2343         install_element(MS_NODE, &cfg_ms_no_clir_cmd);
2344         install_element(MS_NODE, &cfg_ms_tx_power_cmd);
2345         install_element(MS_NODE, &cfg_ms_tx_power_val_cmd);
2346         install_element(MS_NODE, &cfg_ms_sim_delay_cmd);
2347         install_element(MS_NODE, &cfg_ms_no_sim_delay_cmd);
2348         install_element(MS_NODE, &cfg_ms_stick_cmd);
2349         install_element(MS_NODE, &cfg_ms_no_stick_cmd);
2350         install_element(MS_NODE, &cfg_ms_lupd_cmd);
2351         install_element(MS_NODE, &cfg_ms_no_lupd_cmd);
2352         install_element(MS_NODE, &cfg_ms_codec_full_cmd);
2353         install_element(MS_NODE, &cfg_ms_codec_full_pref_cmd);
2354         install_element(MS_NODE, &cfg_ms_codec_half_cmd);
2355         install_element(MS_NODE, &cfg_ms_codec_half_pref_cmd);
2356         install_element(MS_NODE, &cfg_ms_no_codec_half_cmd);
2357         install_element(MS_NODE, &cfg_ms_abbrev_cmd);
2358         install_element(MS_NODE, &cfg_ms_no_abbrev_cmd);
2359         install_element(MS_NODE, &cfg_ms_testsim_cmd);
2360         install_element(MS_NODE, &cfg_ms_support_cmd);
2361         install_node(&support_node, config_write_dummy);
2362         install_default(SUPPORT_NODE);
2363         install_element(SUPPORT_NODE, &ournode_exit_cmd);
2364         install_element(SUPPORT_NODE, &ournode_end_cmd);
2365         install_element(SUPPORT_NODE, &cfg_ms_sup_dtmf_cmd);
2366         install_element(SUPPORT_NODE, &cfg_ms_sup_no_dtmf_cmd);
2367         install_element(SUPPORT_NODE, &cfg_ms_sup_sms_cmd);
2368         install_element(SUPPORT_NODE, &cfg_ms_sup_no_sms_cmd);
2369         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_1_cmd);
2370         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_1_cmd);
2371         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_2_cmd);
2372         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_2_cmd);
2373         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_3_cmd);
2374         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_3_cmd);
2375         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_4_cmd);
2376         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_4_cmd);
2377         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_5_cmd);
2378         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_5_cmd);
2379         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_6_cmd);
2380         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_6_cmd);
2381         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_7_cmd);
2382         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_7_cmd);
2383         install_element(SUPPORT_NODE, &cfg_ms_sup_p_gsm_cmd);
2384         install_element(SUPPORT_NODE, &cfg_ms_sup_no_p_gsm_cmd);
2385         install_element(SUPPORT_NODE, &cfg_ms_sup_e_gsm_cmd);
2386         install_element(SUPPORT_NODE, &cfg_ms_sup_no_e_gsm_cmd);
2387         install_element(SUPPORT_NODE, &cfg_ms_sup_r_gsm_cmd);
2388         install_element(SUPPORT_NODE, &cfg_ms_sup_no_r_gsm_cmd);
2389         install_element(SUPPORT_NODE, &cfg_ms_sup_dcs_cmd);
2390         install_element(SUPPORT_NODE, &cfg_ms_sup_no_dcs_cmd);
2391         install_element(SUPPORT_NODE, &cfg_ms_sup_class_900_cmd);
2392         install_element(SUPPORT_NODE, &cfg_ms_sup_class_dcs_cmd);
2393         install_element(SUPPORT_NODE, &cfg_ms_sup_ch_cap_cmd);
2394         install_element(SUPPORT_NODE, &cfg_ms_sup_full_v1_cmd);
2395         install_element(SUPPORT_NODE, &cfg_ms_sup_no_full_v1_cmd);
2396         install_element(SUPPORT_NODE, &cfg_ms_sup_full_v2_cmd);
2397         install_element(SUPPORT_NODE, &cfg_ms_sup_no_full_v2_cmd);
2398         install_element(SUPPORT_NODE, &cfg_ms_sup_full_v3_cmd);
2399         install_element(SUPPORT_NODE, &cfg_ms_sup_no_full_v3_cmd);
2400         install_element(SUPPORT_NODE, &cfg_ms_sup_half_v1_cmd);
2401         install_element(SUPPORT_NODE, &cfg_ms_sup_no_half_v1_cmd);
2402         install_element(SUPPORT_NODE, &cfg_ms_sup_half_v3_cmd);
2403         install_element(SUPPORT_NODE, &cfg_ms_sup_no_half_v3_cmd);
2404         install_element(SUPPORT_NODE, &cfg_ms_sup_min_rxlev_cmd);
2405         install_element(SUPPORT_NODE, &cfg_ms_sup_dsc_max_cmd);
2406         install_node(&testsim_node, config_write_dummy);
2407         install_default(TESTSIM_NODE);
2408         install_element(TESTSIM_NODE, &ournode_exit_cmd);
2409         install_element(TESTSIM_NODE, &ournode_end_cmd);
2410         install_element(TESTSIM_NODE, &cfg_test_imsi_cmd);
2411         install_element(TESTSIM_NODE, &cfg_test_ki_xor_cmd);
2412         install_element(TESTSIM_NODE, &cfg_test_ki_comp128_cmd);
2413         install_element(TESTSIM_NODE, &cfg_test_barr_cmd);
2414         install_element(TESTSIM_NODE, &cfg_test_no_barr_cmd);
2415         install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd);
2416         install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd);
2417         install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd);
2418         install_element(MS_NODE, &cfg_ms_shutdown_cmd);
2419         install_element(MS_NODE, &cfg_ms_shutdown_force_cmd);
2420         install_element(MS_NODE, &cfg_ms_no_shutdown_cmd);
2421
2422         return 0;
2423 }
2424
2425 void vty_notify(struct osmocom_ms *ms, const char *fmt, ...)
2426 {
2427         struct telnet_connection *connection;
2428         char buffer[1000];
2429         va_list args;
2430         struct vty *vty;
2431
2432         if (fmt) {
2433                 va_start(args, fmt);
2434                 vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
2435                 buffer[sizeof(buffer) - 1] = '\0';
2436                 va_end(args);
2437
2438                 if (!buffer[0])
2439                         return;
2440         }
2441
2442         llist_for_each_entry(connection, &active_connections, entry) {
2443                 vty = connection->vty;
2444                 if (!vty)
2445                         continue;
2446                 if (!fmt) {
2447                         vty_out(vty, "%s%% (MS %s)%s", VTY_NEWLINE, ms->name,
2448                                 VTY_NEWLINE);
2449                         continue;
2450                 }
2451                 if (buffer[strlen(buffer) - 1] == '\n') {
2452                         buffer[strlen(buffer) - 1] = '\0';
2453                         vty_out(vty, "%% %s%s", buffer, VTY_NEWLINE);
2454                         buffer[strlen(buffer)] = '\n';
2455                 } else
2456                         vty_out(vty, "%% %s", buffer);
2457         }
2458 }
2459