[layer23] Call control is disabled when mobile is set to SDCCH only
[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
31 #include <osmocom/bb/common/osmocom_data.h>
32 #include <osmocom/bb/common/networks.h>
33 #include <osmocom/bb/mobile/mncc.h>
34 #include <osmocom/bb/mobile/transaction.h>
35 #include <osmocom/bb/mobile/vty.h>
36 #include <osmocom/bb/mobile/gps.h>
37 #include <osmocom/vty/telnet_interface.h>
38
39 int mncc_call(struct osmocom_ms *ms, char *number);
40 int mncc_hangup(struct osmocom_ms *ms);
41 int mncc_answer(struct osmocom_ms *ms);
42 int mncc_hold(struct osmocom_ms *ms);
43 int mncc_retrieve(struct osmocom_ms *ms, int number);
44
45 extern struct llist_head ms_list;
46 extern struct llist_head active_connections;
47
48 struct cmd_node ms_node = {
49         MS_NODE,
50         "%s(ms)#",
51         1
52 };
53
54 struct cmd_node testsim_node = {
55         TESTSIM_NODE,
56         "%s(test-sim)#",
57         1
58 };
59
60 struct cmd_node support_node = {
61         SUPPORT_NODE,
62         "%s(support)#",
63         1
64 };
65
66 static void print_vty(void *priv, const char *fmt, ...)
67 {
68         char buffer[1000];
69         struct vty *vty = priv;
70         va_list args;
71
72         va_start(args, fmt);
73         vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
74         buffer[sizeof(buffer) - 1] = '\0';
75         va_end(args);
76
77         if (buffer[0]) {
78                 if (buffer[strlen(buffer) - 1] == '\n') {
79                         buffer[strlen(buffer) - 1] = '\0';
80                         vty_out(vty, "%s%s", buffer, VTY_NEWLINE);
81                 } else
82                         vty_out(vty, "%s", buffer);
83         }
84 }
85
86 int vty_reading = 0;
87
88 static void vty_restart(struct vty *vty)
89 {
90         if (vty_reading)
91                 return;
92         vty_out(vty, "You must restart for change to take effect!%s",
93                 VTY_NEWLINE);
94 }
95
96 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
97 {
98         struct osmocom_ms *ms;
99
100         llist_for_each_entry(ms, &ms_list, entity) {
101                 if (!strcmp(ms->name, name))
102                         return ms;
103         }
104         vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
105
106         return NULL;
107 }
108
109 DEFUN(show_ms, show_ms_cmd, "show ms",
110         SHOW_STR "Display available MS entities\n")
111 {
112         struct osmocom_ms *ms;
113
114         llist_for_each_entry(ms, &ms_list, entity) {
115                 struct gsm_settings *set = &ms->settings;
116
117                 vty_out(vty, "MS NAME: %s%s", ms->name, VTY_NEWLINE);
118                 vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE);
119                 vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE);
120                 if (set->imei_random)
121                         vty_out(vty, " IMEI generation: random (%d trailing "
122                                 "digits)%s", set->imei_random, VTY_NEWLINE);
123                 else
124                         vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE);
125                 vty_out(vty, " network selection mode: %s%s",
126                         (set->plmn_mode == PLMN_MODE_AUTO)
127                                 ? "automatic" : "manual", VTY_NEWLINE);
128         }
129
130         return CMD_SUCCESS;
131 }
132
133 DEFUN(show_support, show_support_cmd, "show support [ms_name]",
134         SHOW_STR "Display information about MS support\n"
135         "Name of MS (see \"show ms\")")
136 {
137         struct osmocom_ms *ms;
138
139         if (argc) {
140                 ms = get_ms(argv[0], vty);
141                 if (!ms)
142                         return CMD_WARNING;
143                 gsm_support_dump(ms, print_vty, vty);
144         } else {
145                 llist_for_each_entry(ms, &ms_list, entity) {
146                         gsm_support_dump(ms, print_vty, vty);
147                         vty_out(vty, "%s", VTY_NEWLINE);
148                 }
149         }
150
151         return CMD_SUCCESS;
152 }
153
154 static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty)
155 {
156         struct gsm_settings *set = &ms->settings;
157         struct gsm_trans *trans;
158
159         vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE);
160         if (set->plmn_mode == PLMN_MODE_AUTO)
161                 vty_out(vty, " automatic network selection: %s%s", 
162                         plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
163         else
164                 vty_out(vty, " manual network selection: %s%s", 
165                         plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
166         vty_out(vty, " cell selection: %s%s", 
167                 cs_state_names[ms->cellsel.state], VTY_NEWLINE);
168         vty_out(vty, " radio ressource layer: %s%s", 
169                 gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
170         vty_out(vty, " mobility management layer: %s", 
171                 gsm48_mm_state_names[ms->mmlayer.state]);
172         if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
173                 vty_out(vty, ", %s", 
174                         gsm48_mm_substate_names[ms->mmlayer.substate]);
175         vty_out(vty, "%s", VTY_NEWLINE);
176         llist_for_each_entry(trans, &ms->trans_list, entry) {
177                 vty_out(vty, " call control: %s%s", 
178                         gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
179         }
180 }
181
182 DEFUN(show_states, show_states_cmd, "show states [ms_name]",
183         SHOW_STR "Display current states of given MS\n"
184         "Name of MS (see \"show ms\")")
185 {
186         struct osmocom_ms *ms;
187
188         if (argc) {
189                 ms = get_ms(argv[0], vty);
190                 if (!ms)
191                         return CMD_WARNING;
192                 gsm_states_dump(ms, vty);
193         } else {
194                 llist_for_each_entry(ms, &ms_list, entity) {
195                         gsm_states_dump(ms, vty);
196                         vty_out(vty, "%s", VTY_NEWLINE);
197                 }
198         }
199
200         return CMD_SUCCESS;
201 }
202
203 DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]",
204         SHOW_STR "Display information about subscriber\n"
205         "Name of MS (see \"show ms\")")
206 {
207         struct osmocom_ms *ms;
208
209         if (argc) {
210                 ms = get_ms(argv[0], vty);
211                 if (!ms)
212                         return CMD_WARNING;
213                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
214         } else {
215                 llist_for_each_entry(ms, &ms_list, entity) {
216                         gsm_subscr_dump(&ms->subscr, print_vty, vty);
217                         vty_out(vty, "%s", VTY_NEWLINE);
218                 }
219         }
220
221         return CMD_SUCCESS;
222 }
223
224 DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
225         SHOW_STR "Display information about received cells\n"
226         "Name of MS (see \"show ms\")")
227 {
228         struct osmocom_ms *ms;
229
230         ms = get_ms(argv[0], vty);
231         if (!ms)
232                 return CMD_WARNING;
233
234         gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
235                 vty);
236
237         return CMD_SUCCESS;
238 }
239
240 DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>",
241         SHOW_STR "Display information about received cell\n"
242         "Name of MS (see \"show ms\")\nRadio frequency number")
243 {
244         struct osmocom_ms *ms;
245         int i;
246         struct gsm48_sysinfo *s;
247
248         ms = get_ms(argv[0], vty);
249         if (!ms)
250                 return CMD_WARNING;
251
252         i = atoi(argv[1]);
253         if (i < 0 || i > 1023) {
254                 vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s",
255                         argv[1], VTY_NEWLINE);
256                 return CMD_WARNING;
257         }
258         s = ms->cellsel.list[i].sysinfo;
259         if (!s) {
260                 vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s",
261                         argv[1], VTY_NEWLINE);
262                 return CMD_SUCCESS;
263         }
264
265         gsm48_sysinfo_dump(s, i, print_vty, vty);
266
267         return CMD_SUCCESS;
268 }
269
270 DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]",
271         SHOW_STR "Display information about band allocations\n"
272         "Name of MS (see \"show ms\")\nMobile Country Code\n"
273         "Mobile Network Code")
274 {
275         struct osmocom_ms *ms;
276         uint16_t mcc = 0, mnc = 0;
277
278         ms = get_ms(argv[0], vty);
279         if (!ms)
280                 return CMD_WARNING;
281
282         if (argc >= 3) {
283                 mcc = gsm_input_mcc((char *)argv[1]);
284                 mnc = gsm_input_mnc((char *)argv[2]);
285                 if (!mcc) {
286                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
287                         return CMD_WARNING;
288                 }
289                 if (!mnc) {
290                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
291                         return CMD_WARNING;
292                 }
293         }
294
295         gsm322_dump_ba_list(&ms->cellsel, mcc, mnc, print_vty, vty);
296
297         return CMD_SUCCESS;
298 }
299
300 DEFUN(show_forb_plmn, show_forb_plmn_cmd, "show forbidden plmn MS_NAME",
301         SHOW_STR "Display information about forbidden cells / networks\n"
302         "Display forbidden PLMNs\nName of MS (see \"show ms\")")
303 {
304         struct osmocom_ms *ms;
305
306         ms = get_ms(argv[0], vty);
307         if (!ms)
308                 return CMD_WARNING;
309
310         gsm_subscr_dump_forbidden_plmn(ms, print_vty, vty);
311
312         return CMD_SUCCESS;
313 }
314
315 DEFUN(show_forb_la, show_forb_la_cmd, "show forbidden location-area MS_NAME",
316         SHOW_STR "Display information about forbidden cells / networks\n"
317         "Display forbidden location areas\nName of MS (see \"show ms\")")
318 {
319         struct osmocom_ms *ms;
320
321         ms = get_ms(argv[0], vty);
322         if (!ms)
323                 return CMD_WARNING;
324
325         gsm322_dump_forbidden_la(ms, print_vty, vty);
326
327         return CMD_SUCCESS;
328 }
329
330 DEFUN(monitor_network, monitor_network_cmd, "monitor network MS_NAME",
331         "Monitor...\nMonitor network information\nName of MS (see \"show ms\")")
332 {
333         struct osmocom_ms *ms;
334
335         ms = get_ms(argv[0], vty);
336         if (!ms)
337                 return CMD_WARNING;
338
339         gsm48_rr_start_monitor(ms);
340
341         return CMD_SUCCESS;
342 }
343
344 DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME",
345         NO_STR "Monitor...\nDeactivate monitor of network information\n"
346         "Name of MS (see \"show ms\")")
347 {
348         struct osmocom_ms *ms;
349
350         ms = get_ms(argv[0], vty);
351         if (!ms)
352                 return CMD_WARNING;
353
354         gsm48_rr_stop_monitor(ms);
355
356         return CMD_SUCCESS;
357 }
358
359 DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]",
360         "SIM actions\nInsert test card\nName of MS (see \"show ms\")\n"
361         "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN")
362 {
363         struct osmocom_ms *ms;
364         uint16_t mcc = 0x001, mnc = 0x01f;
365
366         ms = get_ms(argv[0], vty);
367         if (!ms)
368                 return CMD_WARNING;
369
370         if (ms->subscr.sim_valid) {
371                 vty_out(vty, "SIM already presend, remove first!%s",
372                         VTY_NEWLINE);
373                 return CMD_WARNING;
374         }
375
376         if (argc >= 3) {
377                 mcc = gsm_input_mcc((char *)argv[1]);
378                 mnc = gsm_input_mnc((char *)argv[2]);
379                 if (!mcc) {
380                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
381                         return CMD_WARNING;
382                 }
383                 if (!mnc) {
384                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
385                         return CMD_WARNING;
386                 }
387         }
388
389         gsm_subscr_testcard(ms, mcc, mnc);
390
391         return CMD_SUCCESS;
392 }
393
394 DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
395         "SIM actions\nSelect SIM from reader\nName of MS (see \"show ms\")")
396 {
397         struct osmocom_ms *ms;
398
399         ms = get_ms(argv[0], vty);
400         if (!ms)
401                 return CMD_WARNING;
402
403         if (ms->subscr.sim_valid) {
404                 vty_out(vty, "SIM already presend, remove first!%s",
405                         VTY_NEWLINE);
406                 return CMD_WARNING;
407         }
408
409         gsm_subscr_simcard(ms);
410
411         return CMD_SUCCESS;
412 }
413
414 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
415         "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")")
416 {
417         struct osmocom_ms *ms;
418
419         ms = get_ms(argv[0], vty);
420         if (!ms)
421                 return CMD_WARNING;
422
423         if (!ms->subscr.sim_valid) {
424                 vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
425                 return CMD_WARNING;
426         }
427
428         gsm_subscr_remove(ms);
429
430         return CMD_SUCCESS;
431 }
432
433 DEFUN(sim_pin, sim_pin_cmd, "sim pin MS_NAME PIN",
434         "SIM actions\nEnter PIN for SIM card\nName of MS (see \"show ms\")\n"
435         "PIN number")
436 {
437         struct osmocom_ms *ms;
438
439         ms = get_ms(argv[0], vty);
440         if (!ms)
441                 return CMD_WARNING;
442
443         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
444                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
445                 return CMD_WARNING;
446         }
447
448         if (!ms->subscr.sim_pin_required) {
449                 vty_out(vty, "No PIN is required at this time!%s", VTY_NEWLINE);
450                 return CMD_WARNING;
451         }
452
453         gsm_subscr_sim_pin(ms, (char *)argv[1], "", 0);
454
455         return CMD_SUCCESS;
456 }
457
458 DEFUN(sim_disable_pin, sim_disable_pin_cmd, "sim disable-pin MS_NAME PIN",
459         "SIM actions\nDisable PIN of SIM card\nName of MS (see \"show ms\")\n"
460         "PIN number")
461 {
462         struct osmocom_ms *ms;
463
464         ms = get_ms(argv[0], vty);
465         if (!ms)
466                 return CMD_WARNING;
467
468         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
469                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
470                 return CMD_WARNING;
471         }
472
473         gsm_subscr_sim_pin(ms, (char *)argv[1], "", -1);
474
475         return CMD_SUCCESS;
476 }
477
478 DEFUN(sim_enable_pin, sim_enable_pin_cmd, "sim enable-pin MS_NAME PIN",
479         "SIM actions\nEnable PIN of SIM card\nName of MS (see \"show ms\")\n"
480         "PIN number")
481 {
482         struct osmocom_ms *ms;
483
484         ms = get_ms(argv[0], vty);
485         if (!ms)
486                 return CMD_WARNING;
487
488         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
489                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
490                 return CMD_WARNING;
491         }
492
493         gsm_subscr_sim_pin(ms, (char *)argv[1], "", 1);
494
495         return CMD_SUCCESS;
496 }
497
498 DEFUN(sim_change_pin, sim_change_pin_cmd, "sim change-pin MS_NAME OLD NEW",
499         "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
500         "Old PIN number\nNew PIN number")
501 {
502         struct osmocom_ms *ms;
503
504         ms = get_ms(argv[0], vty);
505         if (!ms)
506                 return CMD_WARNING;
507
508         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
509                 vty_out(vty, "Old PIN must be in range 4..8!%s", VTY_NEWLINE);
510                 return CMD_WARNING;
511         }
512         if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
513                 vty_out(vty, "New PIN must be in range 4..8!%s", VTY_NEWLINE);
514                 return CMD_WARNING;
515         }
516
517         gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 2);
518
519         return CMD_SUCCESS;
520 }
521
522 DEFUN(sim_unblock_pin, sim_unblock_pin_cmd, "sim unblock-pin MS_NAME PUC NEW",
523         "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
524         "Personal Unblock Key\nNew PIN number")
525 {
526         struct osmocom_ms *ms;
527
528         ms = get_ms(argv[0], vty);
529         if (!ms)
530                 return CMD_WARNING;
531
532         if (strlen(argv[1]) != 8) {
533                 vty_out(vty, "PUC must be 8 digits!%s", VTY_NEWLINE);
534                 return CMD_WARNING;
535         }
536         if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
537                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
538                 return CMD_WARNING;
539         }
540
541         gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 99);
542
543         return CMD_SUCCESS;
544 }
545
546 DEFUN(sim_lai, sim_lai_cmd, "sim lai MS_NAME MCC MNC LAC",
547         "SIM actions\nChange LAI of SIM card\nName of MS (see \"show ms\")\n"
548         "Mobile Country Code\nMobile Network Code\nLocation Area Code "
549         " (use 0000 to remove LAI)")
550 {
551         struct osmocom_ms *ms;
552         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
553                  mnc = gsm_input_mnc((char *)argv[2]),
554                  lac = strtoul(argv[3], NULL, 16);
555
556         ms = get_ms(argv[0], vty);
557         if (!ms)
558                 return CMD_WARNING;
559
560         if (!mcc) {
561                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
562                 return CMD_WARNING;
563         }
564         if (!mnc) {
565                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
566                 return CMD_WARNING;
567         }
568
569         ms->subscr.mcc = mcc;
570         ms->subscr.mnc = mnc;
571         ms->subscr.lac = lac;
572         ms->subscr.tmsi = 0xffffffff;
573
574         gsm_subscr_write_loci(ms);
575
576         return CMD_SUCCESS;
577 }
578
579 DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
580         "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
581         "Mobile Country Code\nMobile Network Code")
582 {
583         struct osmocom_ms *ms;
584         struct gsm322_plmn *plmn;
585         struct msgb *nmsg;
586         struct gsm322_msg *ngm;
587         struct gsm322_plmn_list *temp;
588         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
589                  mnc = gsm_input_mnc((char *)argv[2]);
590         int found = 0;
591
592         ms = get_ms(argv[0], vty);
593         if (!ms)
594                 return CMD_WARNING;
595         plmn = &ms->plmn;
596
597         if (!mcc) {
598                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
599                 return CMD_WARNING;
600         }
601         if (!mnc) {
602                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
603                 return CMD_WARNING;
604         }
605
606         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
607                 if (temp->mcc == mcc &&  temp->mnc == mnc)
608                         found = 1;
609         if (!found) {
610                 vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
611                 return CMD_WARNING;
612         }
613
614         nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
615         if (!nmsg)
616                 return CMD_WARNING;
617         ngm = (struct gsm322_msg *) nmsg->data;
618         ngm->mcc = mcc;
619         ngm->mnc = mnc;
620         gsm322_plmn_sendmsg(ms, nmsg);
621
622         return CMD_SUCCESS;
623 }
624
625 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
626         "Make a call\nName of MS (see \"show ms\")\nPhone number to call "
627         "(Use digits '0123456789*#abc', and '+' to dial international)\n"
628         "Make an emergency call\nAnswer an incomming call\nHangup a call\n"
629         "Hold current active call\n")
630 {
631         struct osmocom_ms *ms;
632         struct gsm_settings *set;
633         int i;
634
635         ms = get_ms(argv[0], vty);
636         if (!ms)
637                 return CMD_WARNING;
638         set = &ms->settings;
639
640         if (set->ch_cap == GSM_CAP_SDCCH) {
641                 vty_out(vty, "Basic call is not supported for SDCCH only "
642                         "mobile%s", VTY_NEWLINE);
643                 return CMD_WARNING;
644         }
645
646         if (!strcmp(argv[1], "emergency"))
647                 mncc_call(ms, (char *)argv[1]);
648         else switch (argv[1][0]) {
649         case 'a':
650                 mncc_answer(ms);
651                 break;
652         case 'h':
653                 if (argv[1][1] == 'a')
654                         mncc_hangup(ms);
655                 else
656                         mncc_hold(ms);
657                 break;
658         default:
659                 for (i = 0; i < strlen(argv[1]); i++) {
660                         /* allow international notation with + */
661                         if (i == 0 && argv[1][i] == '+')
662                                 continue;
663                         if (!(argv[1][i] >= '0' && argv[1][i] <= '9')
664                          && argv[1][i] != '*'
665                          && argv[1][i] != '#'
666                          && !(argv[1][i] >= 'a' && argv[1][i] <= 'c')) {
667                                 vty_out(vty, "Invalid digit '%c'%s", argv[1][i],
668                                         VTY_NEWLINE);
669                                 return CMD_WARNING;
670                         }
671                 }
672                 mncc_call(ms, (char *)argv[1]);
673         }
674
675         return CMD_SUCCESS;
676 }
677
678 DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]",
679         "Make a call\nName of MS (see \"show ms\")\n"
680         "Retrieve call on hold\nNumber of call to retrieve")
681 {
682         struct osmocom_ms *ms;
683
684         ms = get_ms(argv[0], vty);
685         if (!ms)
686                 return CMD_WARNING;
687
688         mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
689
690         return CMD_SUCCESS;
691 }
692
693 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
694         "Network ...\nShow results of network search (again)\n"
695         "Name of MS (see \"show ms\")")
696 {
697         struct osmocom_ms *ms;
698         struct gsm_settings *set;
699         struct gsm322_plmn *plmn;
700         struct gsm322_plmn_list *temp;
701
702         ms = get_ms(argv[0], vty);
703         if (!ms)
704                 return CMD_WARNING;
705         set = &ms->settings;
706         plmn = &ms->plmn;
707
708         if (set->plmn_mode != PLMN_MODE_AUTO
709          && plmn->state != GSM322_M3_NOT_ON_PLMN) {
710                 vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
711                 return CMD_WARNING;
712         }
713
714         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
715                 vty_out(vty, " Network %s, %s (%s, %s)%s",
716                         gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
717                         gsm_get_mcc(temp->mcc),
718                         gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
719
720         return CMD_SUCCESS;
721 }
722
723 DEFUN(network_search, network_search_cmd, "network search MS_NAME",
724         "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
725 {
726         struct osmocom_ms *ms;
727         struct msgb *nmsg;
728
729         ms = get_ms(argv[0], vty);
730         if (!ms)
731                 return CMD_WARNING;
732
733         nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
734         if (!nmsg)
735                 return CMD_WARNING;
736         gsm322_plmn_sendmsg(ms, nmsg);
737
738         return CMD_SUCCESS;
739 }
740
741 DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable",
742         "GPS receiver")
743 {
744         if (gps_open()) {
745                 gps.enable = 1;
746                 vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE);
747                 return CMD_WARNING;
748         }
749         gps.enable = 1;
750
751         return CMD_SUCCESS;
752 }
753
754 DEFUN(cfg_no_gps_enable, cfg_no_gps_enable_cmd, "no gps enable",
755         NO_STR "Disable GPS receiver")
756 {
757         if (gps.enable)
758                 gps_close();
759         gps.enable = 0;
760
761         return CMD_SUCCESS;
762 }
763
764 DEFUN(cfg_gps_device, cfg_gps_device_cmd, "gps device DEVICE",
765         "GPS receiver\nSelect serial device\n"
766         "Full path of serial device including /dev/")
767 {
768         strncpy(gps.device, argv[0], sizeof(gps.device));
769         gps.device[sizeof(gps.device) - 1] = '\0';
770         if (gps.enable) {
771                 gps_close();
772                 if (gps_open()) {
773                         vty_out(vty, "Failed to open GPS device!%s",
774                                 VTY_NEWLINE);
775                         return CMD_WARNING;
776                 }
777         }
778
779         return CMD_SUCCESS;
780 }
781
782 DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate "
783         "(default|4800|""9600|19200|38400|57600|115200)",
784         "GPS receiver\nSelect baud rate\nDefault, don't modify\n\n\n\n\n\n")
785 {
786         if (argv[0][0] == 'd')
787                 gps.baud = 0;
788         else
789                 gps.baud = atoi(argv[0]);
790         if (gps.enable) {
791                 gps_close();
792                 if (gps_open()) {
793                         gps.enable = 0;
794                         vty_out(vty, "Failed to open GPS device!%s",
795                                 VTY_NEWLINE);
796                         return CMD_WARNING;
797                 }
798         }
799
800         return CMD_SUCCESS;
801 }
802
803 /* per MS config */
804 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
805         "Select a mobile station to configure\nName of MS (see \"show ms\")")
806 {
807         struct osmocom_ms *ms;
808
809         ms = get_ms(argv[0], vty);
810         if (!ms)
811                 return CMD_WARNING;
812
813         vty->index = ms;
814         vty->node = MS_NODE;
815
816         return CMD_SUCCESS;
817 }
818
819 #define SUP_WRITE(item, cmd) \
820         if (sup->item) \
821                 vty_out(vty, "  %s%s%s", (set->item) ? "" : "no ", cmd, \
822                         VTY_NEWLINE);
823
824 static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
825 {
826         struct gsm_settings *set = &ms->settings;
827         struct gsm_support *sup = &ms->support;
828
829         vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
830         switch(set->sim_type) {
831                 case GSM_SIM_TYPE_NONE:
832                 vty_out(vty, " sim none%s", VTY_NEWLINE);
833                 break;
834                 case GSM_SIM_TYPE_READER:
835                 vty_out(vty, " sim reader%s", VTY_NEWLINE);
836                 break;
837                 case GSM_SIM_TYPE_TEST:
838                 vty_out(vty, " sim test%s", VTY_NEWLINE);
839                 break;
840         }
841         vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
842                         == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
843         vty_out(vty, " imei %s %s%s", set->imei,
844                 set->imeisv + strlen(set->imei), VTY_NEWLINE);
845         if (set->imei_random)
846                 vty_out(vty, " imei-random %d%s", set->imei_random,
847                         VTY_NEWLINE);
848         else
849                 vty_out(vty, " imei-fixed%s", VTY_NEWLINE);
850         if (set->emergency_imsi[0])
851                 vty_out(vty, " emergency-imsi %s%s", set->emergency_imsi,
852                         VTY_NEWLINE);
853         else
854                 vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE);
855         vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE);
856         vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE);
857         vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE);
858         if (set->alter_tx_power)
859                 if (set->alter_tx_power_value)
860                         vty_out(vty, " tx-power %d%s",
861                                 set->alter_tx_power_value, VTY_NEWLINE);
862                 else
863                         vty_out(vty, " tx-power full%s", VTY_NEWLINE);
864         else
865                 vty_out(vty, " tx-power auto%s", VTY_NEWLINE);
866         if (set->alter_delay)
867                 vty_out(vty, " simulated-delay %d%s", set->alter_delay,
868                         VTY_NEWLINE);
869         else
870                 vty_out(vty, " no simulated-delay%s", VTY_NEWLINE);
871         if (set->stick)
872                 vty_out(vty, " stick %d%s", set->stick_arfcn,
873                         VTY_NEWLINE);
874         else
875                 vty_out(vty, " no stick%s", VTY_NEWLINE);
876         if (set->no_lupd)
877                 vty_out(vty, " no location-updating%s", VTY_NEWLINE);
878         else
879                 vty_out(vty, " location-updating%s", VTY_NEWLINE);
880         if (set->full_v1 || set->full_v2 || set->full_v3) {
881                 /* mandatory anyway */
882                 vty_out(vty, " codec full-speed%s%s",
883                         (!set->half_prefer) ? " prefer" : "",
884                         VTY_NEWLINE);
885         }
886         if (set->half_v1 || set->half_v3) {
887                 if (set->half)
888                         vty_out(vty, " codec half-speed%s%s",
889                                 (set->half_prefer) ? " prefer" : "",
890                                 VTY_NEWLINE);
891                 else
892                         vty_out(vty, " no codec half-speed%s", VTY_NEWLINE);
893         }
894         vty_out(vty, " support%s", VTY_NEWLINE);
895         SUP_WRITE(sms_ptp, "sms");
896         SUP_WRITE(a5_1, "a5/1");
897         SUP_WRITE(a5_2, "a5/2");
898         SUP_WRITE(a5_3, "a5/3");
899         SUP_WRITE(a5_4, "a5/4");
900         SUP_WRITE(a5_5, "a5/5");
901         SUP_WRITE(a5_6, "a5/6");
902         SUP_WRITE(a5_7, "a5/7");
903         SUP_WRITE(p_gsm, "p-gsm");
904         SUP_WRITE(e_gsm, "e-gsm");
905         SUP_WRITE(r_gsm, "r-gsm");
906         SUP_WRITE(dcs, "dcs");
907         vty_out(vty, "  class-900 %d%s", set->class_900, VTY_NEWLINE);
908         vty_out(vty, "  class-dcs %d%s", set->class_dcs, VTY_NEWLINE);
909         switch (set->ch_cap) {
910         case GSM_CAP_SDCCH:
911                 vty_out(vty, "  channel-capability sdcch%s", VTY_NEWLINE);
912                 break;
913         case GSM_CAP_SDCCH_TCHF:
914                 vty_out(vty, "  channel-capability sdcch+tchf%s", VTY_NEWLINE);
915                 break;
916         case GSM_CAP_SDCCH_TCHF_TCHH:
917                 vty_out(vty, "  channel-capability sdcch+tchf+tchh%s",
918                         VTY_NEWLINE);
919                 break;
920         }
921         SUP_WRITE(full_v1, "full-speech-v1");
922         SUP_WRITE(full_v2, "full-speech-v2");
923         SUP_WRITE(full_v3, "full-speech-v3");
924         SUP_WRITE(half_v1, "half-speech-v1");
925         SUP_WRITE(half_v3, "half-speech-v3");
926         vty_out(vty, "  min-rxlev %d%s", set->min_rxlev_db, VTY_NEWLINE);
927         vty_out(vty, "  dsc-max %d%s", set->dsc_max, VTY_NEWLINE);
928         vty_out(vty, " exit%s", VTY_NEWLINE);
929         vty_out(vty, " test-sim%s", VTY_NEWLINE);
930         vty_out(vty, "  imsi %s%s", set->test_imsi, VTY_NEWLINE);
931         switch (set->test_ki_type) {
932         case GSM_SIM_KEY_XOR:
933                 vty_out(vty, "  ki xor %s%s", hexdump(set->test_ki, 12),
934                         VTY_NEWLINE);
935                 break;
936         case GSM_SIM_KEY_COMP128:
937                 vty_out(vty, "  ki comp128 %s%s", hexdump(set->test_ki, 16),
938                         VTY_NEWLINE);
939                 break;
940         }
941         vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
942                 VTY_NEWLINE);
943         if (set->test_rplmn_valid)
944                 vty_out(vty, "  rplmn %s %s%s",
945                         gsm_print_mcc(set->test_rplmn_mcc),
946                         gsm_print_mnc(set->test_rplmn_mnc),
947                         VTY_NEWLINE);
948         else
949                 vty_out(vty, "  no rplmn%s", VTY_NEWLINE);
950         vty_out(vty, "  hplmn-search %s%s", (set->test_always) ? "everywhere"
951                         : "foreign-country", VTY_NEWLINE);
952         vty_out(vty, " exit%s", VTY_NEWLINE);
953         vty_out(vty, "exit%s", VTY_NEWLINE);
954         vty_out(vty, "!%s", VTY_NEWLINE);
955 }
956
957 static int config_write_ms(struct vty *vty)
958 {
959         struct osmocom_ms *ms;
960
961         vty_out(vty, "gps device %s%s", gps.device, VTY_NEWLINE);
962         if (gps.baud)
963                 vty_out(vty, "gps baudrate %d%s", gps.baud, VTY_NEWLINE);
964         else
965                 vty_out(vty, "gps baudrate default%s", VTY_NEWLINE);
966         vty_out(vty, "%sgps enable%s", (gps.enable) ? "" : "no ", VTY_NEWLINE);
967         vty_out(vty, "!%s", VTY_NEWLINE);
968
969         llist_for_each_entry(ms, &ms_list, entity)
970                 config_write_ms_single(vty, ms);
971
972         return CMD_SUCCESS;
973 }
974
975 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)",
976         "Set SIM card type when powering on\nNo SIM interted\n"
977         "Use SIM from reader\nTest SIM inserted")
978 {
979         struct osmocom_ms *ms = vty->index;
980         struct gsm_settings *set = &ms->settings;
981
982         switch (argv[0][0]) {
983         case 'n':
984                 set->sim_type = GSM_SIM_TYPE_NONE;
985                 break;
986         case 'r':
987                 set->sim_type = GSM_SIM_TYPE_READER;
988                 break;
989         case 't':
990                 set->sim_type = GSM_SIM_TYPE_TEST;
991                 break;
992         default:
993                 vty_out(vty, "unknown SIM type%s", VTY_NEWLINE);
994                 return CMD_WARNING;
995         }
996
997         vty_restart(vty);
998         return CMD_SUCCESS;
999 }
1000
1001 DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
1002         "Set network selection mode\nAutomatic network selection\n"
1003         "Manual network selection")
1004 {
1005         struct osmocom_ms *ms = vty->index;
1006         struct gsm_settings *set = &ms->settings;
1007         struct msgb *nmsg;
1008
1009         if (!ms->plmn.state) {
1010                 if (argv[0][0] == 'a')
1011                         set->plmn_mode = PLMN_MODE_AUTO;
1012                 else
1013                         set->plmn_mode = PLMN_MODE_MANUAL;
1014
1015                 return CMD_SUCCESS;
1016         }
1017         if (argv[0][0] == 'a')
1018                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
1019         else
1020                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
1021         if (!nmsg)
1022                 return CMD_WARNING;
1023         gsm322_plmn_sendmsg(ms, nmsg);
1024
1025         return CMD_SUCCESS;
1026 }
1027
1028 DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
1029         "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
1030         "Software version digit")
1031 {
1032         struct osmocom_ms *ms = vty->index;
1033         struct gsm_settings *set = &ms->settings;
1034         char *error, *sv = "0";
1035
1036         if (argc >= 2)
1037                 sv = (char *)argv[1];
1038
1039         error = gsm_check_imei(argv[0], sv);
1040         if (error) {
1041                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1042                 return CMD_WARNING;
1043         }
1044
1045         strcpy(set->imei, argv[0]);
1046         strcpy(set->imeisv, argv[0]);
1047         strcpy(set->imeisv + 15, sv);
1048
1049         return CMD_SUCCESS;
1050 }
1051
1052 DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
1053         "Use fixed IMEI on every power on")
1054 {
1055         struct osmocom_ms *ms = vty->index;
1056         struct gsm_settings *set = &ms->settings;
1057
1058         set->imei_random = 0;
1059
1060         vty_restart(vty);
1061         return CMD_SUCCESS;
1062 }
1063
1064 DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
1065         "Use random IMEI on every power on\n"
1066         "Number of trailing digits to randomize")
1067 {
1068         struct osmocom_ms *ms = vty->index;
1069         struct gsm_settings *set = &ms->settings;
1070
1071         set->imei_random = atoi(argv[0]);
1072
1073         vty_restart(vty);
1074         return CMD_SUCCESS;
1075 }
1076
1077 DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi IMSI",
1078         "Use special IMSI for emergency calls\n15 digits IMSI")
1079 {
1080         struct osmocom_ms *ms = vty->index;
1081         struct gsm_settings *set = &ms->settings;
1082         char *error;
1083
1084         error = gsm_check_imsi(argv[0]);
1085         if (error) {
1086                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1087                 return CMD_WARNING;
1088         }
1089         strcpy(set->emergency_imsi, argv[0]);
1090
1091         return CMD_SUCCESS;
1092 }
1093
1094 DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
1095         NO_STR "Use IMSI of SIM or IMEI for emergency calls")
1096 {
1097         struct osmocom_ms *ms = vty->index;
1098         struct gsm_settings *set = &ms->settings;
1099
1100         set->emergency_imsi[0] = '\0';
1101
1102         return CMD_SUCCESS;
1103 }
1104
1105 DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
1106         NO_STR "Disallow waiting calls")
1107 {
1108         struct osmocom_ms *ms = vty->index;
1109         struct gsm_settings *set = &ms->settings;
1110
1111         set->cw = 0;
1112
1113         return CMD_SUCCESS;
1114 }
1115
1116 DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
1117         "Allow waiting calls")
1118 {
1119         struct osmocom_ms *ms = vty->index;
1120         struct gsm_settings *set = &ms->settings;
1121
1122         set->cw = 1;
1123
1124         return CMD_SUCCESS;
1125 }
1126
1127 DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
1128         "Force caller ID presentation")
1129 {
1130         struct osmocom_ms *ms = vty->index;
1131         struct gsm_settings *set = &ms->settings;
1132
1133         set->clip = 1;
1134         set->clir = 0;
1135
1136         return CMD_SUCCESS;
1137 }
1138
1139 DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
1140         "Force caller ID restriction")
1141 {
1142         struct osmocom_ms *ms = vty->index;
1143         struct gsm_settings *set = &ms->settings;
1144
1145         set->clip = 0;
1146         set->clir = 1;
1147
1148         return CMD_SUCCESS;
1149 }
1150
1151 DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
1152         NO_STR "Disable forcing of caller ID presentation")
1153 {
1154         struct osmocom_ms *ms = vty->index;
1155         struct gsm_settings *set = &ms->settings;
1156
1157         set->clip = 0;
1158
1159         return CMD_SUCCESS;
1160 }
1161
1162 DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
1163         NO_STR "Disable forcing of caller ID restriction")
1164 {
1165         struct osmocom_ms *ms = vty->index;
1166         struct gsm_settings *set = &ms->settings;
1167
1168         set->clir = 0;
1169
1170         return CMD_SUCCESS;
1171 }
1172
1173 DEFUN(cfg_ms_tx_power, cfg_ms_tx_power_cmd, "tx-power (auto|full)",
1174         "Set the way to choose transmit power\nControlled by BTS\n"
1175         "Always full power\nFixed GSM power value if supported")
1176 {
1177         struct osmocom_ms *ms = vty->index;
1178         struct gsm_settings *set = &ms->settings;
1179
1180         switch (argv[0][0]) {
1181         case 'a':
1182                 set->alter_tx_power = 0;
1183                 break;
1184         case 'f':
1185                 set->alter_tx_power = 1;
1186                 set->alter_tx_power_value = 0;
1187                 break;
1188         }
1189
1190         return CMD_SUCCESS;
1191 }
1192
1193 DEFUN(cfg_ms_tx_power_val, cfg_ms_tx_power_val_cmd, "tx-power <0-31>",
1194         "Set the way to choose transmit power\n"
1195         "Fixed GSM power value if supported")
1196 {
1197         struct osmocom_ms *ms = vty->index;
1198         struct gsm_settings *set = &ms->settings;
1199
1200         set->alter_tx_power = 1;
1201         set->alter_tx_power_value = atoi(argv[0]);
1202
1203         return CMD_SUCCESS;
1204 }
1205
1206 DEFUN(cfg_ms_sim_delay, cfg_ms_sim_delay_cmd, "simulated-delay <-128-127>",
1207         "Simulate a lower or higher distance from the BTS\n"
1208         "Delay in half bits (distance in 553.85 meter steps)")
1209 {
1210         struct osmocom_ms *ms = vty->index;
1211         struct gsm_settings *set = &ms->settings;
1212
1213         set->alter_delay = atoi(argv[0]);
1214         gsm48_rr_alter_delay(ms);
1215
1216         return CMD_SUCCESS;
1217 }
1218
1219 DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
1220         NO_STR "Do not simulate a lower or higher distance from the BTS")
1221 {
1222         struct osmocom_ms *ms = vty->index;
1223         struct gsm_settings *set = &ms->settings;
1224
1225         set->alter_delay = 0;
1226         gsm48_rr_alter_delay(ms);
1227
1228         return CMD_SUCCESS;
1229 }
1230
1231 DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023>",
1232         "Stick to the given cell\nARFCN of the cell to stick to")
1233 {
1234         struct osmocom_ms *ms = vty->index;
1235         struct gsm_settings *set = &ms->settings;
1236
1237         set->stick = 1;
1238         set->stick_arfcn = atoi(argv[0]);
1239
1240         return CMD_SUCCESS;
1241 }
1242
1243 DEFUN(cfg_ms_no_stick, cfg_ms_no_stick_cmd, "no stick",
1244         NO_STR "Do not stick to any cell")
1245 {
1246         struct osmocom_ms *ms = vty->index;
1247         struct gsm_settings *set = &ms->settings;
1248
1249         set->stick = 0;
1250
1251         return CMD_SUCCESS;
1252 }
1253
1254 DEFUN(cfg_ms_lupd, cfg_ms_lupd_cmd, "location-updating",
1255         "Allow location updating")
1256 {
1257         struct osmocom_ms *ms = vty->index;
1258         struct gsm_settings *set = &ms->settings;
1259
1260         set->no_lupd = 0;
1261
1262         return CMD_SUCCESS;
1263 }
1264
1265 DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating",
1266         NO_STR "Do not allow location updating")
1267 {
1268         struct osmocom_ms *ms = vty->index;
1269         struct gsm_settings *set = &ms->settings;
1270
1271         set->no_lupd = 1;
1272
1273         return CMD_SUCCESS;
1274 }
1275
1276 DEFUN(cfg_codec_full, cfg_ms_codec_full_cmd, "codec full-speed",
1277         "Enable codec\nFull speed speech codec")
1278 {
1279         struct osmocom_ms *ms = vty->index;
1280         struct gsm_settings *set = &ms->settings;
1281
1282         if (!set->full_v1 && !set->full_v2 && !set->full_v3) {
1283                 vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
1284                 return CMD_WARNING;
1285         }
1286
1287         return CMD_SUCCESS;
1288 }
1289
1290 DEFUN(cfg_codec_full_pref, cfg_ms_codec_full_pref_cmd, "codec full-speed "
1291         "prefer",
1292         "Enable codec\nFull speed speech codec\nPrefer this codec")
1293 {
1294         struct osmocom_ms *ms = vty->index;
1295         struct gsm_settings *set = &ms->settings;
1296
1297         if (!set->full_v1 && !set->full_v2 && !set->full_v3) {
1298                 vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
1299                 return CMD_WARNING;
1300         }
1301
1302         set->half_prefer = 0;
1303
1304         return CMD_SUCCESS;
1305 }
1306
1307 DEFUN(cfg_codec_half, cfg_ms_codec_half_cmd, "codec half-speed",
1308         "Enable codec\nHalf speed speech codec")
1309 {
1310         struct osmocom_ms *ms = vty->index;
1311         struct gsm_settings *set = &ms->settings;
1312
1313         if (!set->half_v1 && !set->half_v3) {
1314                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1315                 return CMD_WARNING;
1316         }
1317
1318         set->half = 1;
1319
1320         return CMD_SUCCESS;
1321 }
1322
1323 DEFUN(cfg_codec_half_pref, cfg_ms_codec_half_pref_cmd, "codec half-speed "
1324         "prefer",
1325         "Enable codec\nHalf speed speech codec\nPrefer this codec")
1326 {
1327         struct osmocom_ms *ms = vty->index;
1328         struct gsm_settings *set = &ms->settings;
1329
1330         if (!set->half_v1 && !set->half_v3) {
1331                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1332                 return CMD_WARNING;
1333         }
1334
1335         set->half = 1;
1336         set->half_prefer = 1;
1337
1338         return CMD_SUCCESS;
1339 }
1340
1341 DEFUN(cfg_no_codec_half, cfg_ms_no_codec_half_cmd, "no codec half-speed",
1342         NO_STR "Disable codec\nHalf speed speech codec")
1343 {
1344         struct osmocom_ms *ms = vty->index;
1345         struct gsm_settings *set = &ms->settings;
1346
1347         if (!set->half_v1 && !set->half_v3) {
1348                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1349                 return CMD_WARNING;
1350         }
1351
1352         set->half = 0;
1353         set->half_prefer = 0;
1354
1355         return CMD_SUCCESS;
1356 }
1357
1358 static int config_write_dummy(struct vty *vty)
1359 {
1360         return CMD_SUCCESS;
1361 }
1362
1363 /* per support config */
1364 DEFUN(cfg_ms_support, cfg_ms_support_cmd, "support",
1365         "Define supported features")
1366 {
1367         vty->node = SUPPORT_NODE;
1368
1369         return CMD_SUCCESS;
1370 }
1371
1372 #define SUP_EN(cfg, cfg_cmd, item, cmd, desc, restart) \
1373 DEFUN(cfg, cfg_cmd, cmd, "Enable " desc "support") \
1374 { \
1375         struct osmocom_ms *ms = vty->index; \
1376         struct gsm_settings *set = &ms->settings; \
1377         struct gsm_support *sup = &ms->support; \
1378         if (!sup->item) { \
1379                 vty_out(vty, desc " not supported%s", VTY_NEWLINE); \
1380                 if (vty_reading) \
1381                         return CMD_SUCCESS; \
1382                 return CMD_WARNING; \
1383         } \
1384         if (restart) \
1385                 vty_restart(vty); \
1386         set->item = 1; \
1387         return CMD_SUCCESS; \
1388 }
1389
1390 #define SUP_DI(cfg, cfg_cmd, item, cmd, desc, restart) \
1391 DEFUN(cfg, cfg_cmd, "no " cmd, NO_STR "Disable " desc " support") \
1392 { \
1393         struct osmocom_ms *ms = vty->index; \
1394         struct gsm_settings *set = &ms->settings; \
1395         struct gsm_support *sup = &ms->support; \
1396         if (!sup->item) { \
1397                 vty_out(vty, desc " not supported%s", VTY_NEWLINE); \
1398                 if (vty_reading) \
1399                         return CMD_SUCCESS; \
1400                 return CMD_WARNING; \
1401         } \
1402         if (restart) \
1403                 vty_restart(vty); \
1404         set->item = 0; \
1405         return CMD_SUCCESS; \
1406 }
1407
1408 SUP_EN(cfg_ms_sup_sms, cfg_ms_sup_sms_cmd, sms_ptp, "sms", "SMS", 0);
1409 SUP_DI(cfg_ms_sup_no_sms, cfg_ms_sup_no_sms_cmd, sms_ptp, "sms", "SMS", 0);
1410 SUP_EN(cfg_ms_sup_a5_1, cfg_ms_sup_a5_1_cmd, a5_1, "a5/1", "A5/1", 0);
1411 SUP_DI(cfg_ms_sup_no_a5_1, cfg_ms_sup_no_a5_1_cmd, a5_1, "a5/1", "A5/1", 0);
1412 SUP_EN(cfg_ms_sup_a5_2, cfg_ms_sup_a5_2_cmd, a5_2, "a5/2", "A5/2", 0);
1413 SUP_DI(cfg_ms_sup_no_a5_2, cfg_ms_sup_no_a5_2_cmd, a5_2, "a5/2", "A5/2", 0);
1414 SUP_EN(cfg_ms_sup_a5_3, cfg_ms_sup_a5_3_cmd, a5_3, "a5/3", "A5/3", 0);
1415 SUP_DI(cfg_ms_sup_no_a5_3, cfg_ms_sup_no_a5_3_cmd, a5_3, "a5/3", "A5/3", 0);
1416 SUP_EN(cfg_ms_sup_a5_4, cfg_ms_sup_a5_4_cmd, a5_4, "a5/4", "A5/4", 0);
1417 SUP_DI(cfg_ms_sup_no_a5_4, cfg_ms_sup_no_a5_4_cmd, a5_4, "a5/4", "A5/4", 0);
1418 SUP_EN(cfg_ms_sup_a5_5, cfg_ms_sup_a5_5_cmd, a5_5, "a5/5", "A5/5", 0);
1419 SUP_DI(cfg_ms_sup_no_a5_5, cfg_ms_sup_no_a5_5_cmd, a5_5, "a5/5", "A5/5", 0);
1420 SUP_EN(cfg_ms_sup_a5_6, cfg_ms_sup_a5_6_cmd, a5_6, "a5/6", "A5/6", 0);
1421 SUP_DI(cfg_ms_sup_no_a5_6, cfg_ms_sup_no_a5_6_cmd, a5_6, "a5/6", "A5/6", 0);
1422 SUP_EN(cfg_ms_sup_a5_7, cfg_ms_sup_a5_7_cmd, a5_7, "a5/7", "A5/7", 0);
1423 SUP_DI(cfg_ms_sup_no_a5_7, cfg_ms_sup_no_a5_7_cmd, a5_7, "a5/7", "A5/7", 1);
1424 SUP_EN(cfg_ms_sup_p_gsm, cfg_ms_sup_p_gsm_cmd, p_gsm, "p-gsm", "P-GSM (900)",
1425         1);
1426 SUP_DI(cfg_ms_sup_no_p_gsm, cfg_ms_sup_no_p_gsm_cmd, p_gsm, "p-gsm",
1427         "P-GSM (900)", 1);
1428 SUP_EN(cfg_ms_sup_e_gsm, cfg_ms_sup_e_gsm_cmd, e_gsm, "e-gsm", "E-GSM (850)",
1429         1);
1430 SUP_DI(cfg_ms_sup_no_e_gsm, cfg_ms_sup_no_e_gsm_cmd, e_gsm, "e-gsm",
1431         "E-GSM (850)", 1);
1432 SUP_EN(cfg_ms_sup_r_gsm, cfg_ms_sup_r_gsm_cmd, r_gsm, "r-gsm", "R-GSM (850)",
1433         1);
1434 SUP_DI(cfg_ms_sup_no_r_gsm, cfg_ms_sup_no_r_gsm_cmd, r_gsm, "r-gsm",
1435         "R-GSM (850)", 1);
1436 SUP_EN(cfg_ms_sup_dcs, cfg_ms_sup_dcs_cmd, dcs, "dcs", "DCS (1800)", 0);
1437 SUP_DI(cfg_ms_sup_no_dcs, cfg_ms_sup_no_dcs_cmd, dcs, "dcs", "DCS (1800)", 0);
1438
1439 DEFUN(cfg_ms_sup_class_900, cfg_ms_sup_class_900_cmd, "class-900 (1|2|3|4|5)",
1440         "Select power class for GSM 850/900\n"
1441         "20 Watts\n"
1442         "8 Watts\n"
1443         "5 Watts\n"
1444         "2 Watts\n"
1445         "0.8 Watts")
1446 {
1447         struct osmocom_ms *ms = vty->index;
1448         struct gsm_settings *set = &ms->settings;
1449         struct gsm_support *sup = &ms->support;
1450
1451         set->class_900 = atoi(argv[0]);
1452
1453         if (set->class_900 < sup->class_900 && !vty_reading)
1454                 vty_out(vty, "You selected an higher class than supported "
1455                         " by hardware!%s", VTY_NEWLINE);
1456
1457         return CMD_SUCCESS;
1458 }
1459
1460 DEFUN(cfg_ms_sup_class_dcs, cfg_ms_sup_class_dcs_cmd, "class-dcs (1|2|3)",
1461         "Select power class for DCS 1800\n"
1462         "1 Watt\n"
1463         "0.25 Watts\n"
1464         "4 Watts")
1465 {
1466         struct osmocom_ms *ms = vty->index;
1467         struct gsm_settings *set = &ms->settings;
1468         struct gsm_support *sup = &ms->support;
1469
1470         set->class_dcs = atoi(argv[0]);
1471
1472         if (((set->class_dcs + 1) & 3) < ((sup->class_dcs + 1) & 3)
1473          && !vty_reading)
1474                 vty_out(vty, "You selected an higher class than supported "
1475                         " by hardware!%s", VTY_NEWLINE);
1476
1477         return CMD_SUCCESS;
1478 }
1479
1480 DEFUN(cfg_ms_sup_ch_cap, cfg_ms_sup_ch_cap_cmd, "channel-capability "
1481         "(sdcch|sdcch+tchf|sdcch+tchf+tchh)",
1482         "Select channel capability\nSDCCH only\nSDCCH + TCH/F\nSDCCH + TCH/H")
1483 {
1484         struct osmocom_ms *ms = vty->index;
1485         struct gsm_settings *set = &ms->settings;
1486         struct gsm_support *sup = &ms->support;
1487         uint8_t ch_cap;
1488
1489         if (!strcmp(argv[0], "sdcch+tchf+tchh"))
1490                 ch_cap = GSM_CAP_SDCCH_TCHF_TCHH;
1491         else if (!strcmp(argv[0], "sdcch+tchf"))
1492                 ch_cap = GSM_CAP_SDCCH_TCHF;
1493         else
1494                 ch_cap = GSM_CAP_SDCCH;
1495
1496         if (ch_cap > sup->ch_cap && !vty_reading) {
1497                 vty_out(vty, "You selected an higher capability than supported "
1498                         " by hardware!%s", VTY_NEWLINE);
1499                 return CMD_WARNING;
1500         }
1501
1502         if (ch_cap != set->ch_cap
1503          && (ch_cap == GSM_CAP_SDCCH || set->ch_cap == GSM_CAP_SDCCH))
1504                 vty_restart(vty);
1505
1506         set->ch_cap = ch_cap;
1507
1508         return CMD_SUCCESS;
1509 }
1510
1511 SUP_EN(cfg_ms_sup_full_v1, cfg_ms_sup_full_v1_cmd, full_v1, "full-speech-v1",
1512         "Full rate speech V1", 0);
1513 SUP_DI(cfg_ms_sup_no_full_v1, cfg_ms_sup_no_full_v1_cmd, full_v1,
1514         "full-speech-v1", "Full rate speech V1", 0);
1515 SUP_EN(cfg_ms_sup_full_v2, cfg_ms_sup_full_v2_cmd, full_v2, "full-speech-v2",
1516         "Full rate speech V2 (EFR)", 0);
1517 SUP_DI(cfg_ms_sup_no_full_v2, cfg_ms_sup_no_full_v2_cmd, full_v2,
1518         "full-speech-v2", "Full rate speech V2 (EFR)", 0);
1519 SUP_EN(cfg_ms_sup_full_v3, cfg_ms_sup_full_v3_cmd, full_v3, "full-speech-v3",
1520         "Full rate speech V3 (AMR)", 0);
1521 SUP_DI(cfg_ms_sup_no_full_v3, cfg_ms_sup_no_full_v3_cmd, full_v3,
1522         "full-speech-v3", "Full rate speech V3 (AMR)", 0);
1523 SUP_EN(cfg_ms_sup_half_v1, cfg_ms_sup_half_v1_cmd, half_v1, "half-speech-v1",
1524         "Half rate speech V1 (AMR)", 0);
1525 SUP_DI(cfg_ms_sup_no_half_v1, cfg_ms_sup_no_half_v1_cmd, half_v1,
1526         "half-speech-v1", "Half rate speech V1", 0);
1527 SUP_EN(cfg_ms_sup_half_v3, cfg_ms_sup_half_v3_cmd, half_v3, "half-speech-v3",
1528         "Half rate speech V3 (AMR)", 0);
1529 SUP_DI(cfg_ms_sup_no_half_v3, cfg_ms_sup_no_half_v3_cmd, half_v3,
1530         "half-speech-v3", "Half rate speech V3", 0);
1531
1532 DEFUN(cfg_ms_sup_min_rxlev, cfg_ms_sup_min_rxlev_cmd, "min-rxlev <-110--47>",
1533         "Set the minimum receive level to select a cell\n"
1534         "Minimum receive level from -110 dBm to -47 dBm")
1535 {
1536         struct osmocom_ms *ms = vty->index;
1537         struct gsm_settings *set = &ms->settings;
1538
1539         set->min_rxlev_db = atoi(argv[0]);
1540
1541         return CMD_SUCCESS;
1542 }
1543
1544 DEFUN(cfg_ms_sup_dsc_max, cfg_ms_sup_dsc_max_cmd, "dsc-max <90-500>",
1545         "Set the maximum DSC value. Standard is 90. Increase to make mobile "
1546         "more reliable against bad RX signal. This increase the propability "
1547         "of missing a paging requests\n"
1548         "DSC initial and maximum value (standard is 90)")
1549 {
1550         struct osmocom_ms *ms = vty->index;
1551         struct gsm_settings *set = &ms->settings;
1552
1553         set->dsc_max = atoi(argv[0]);
1554
1555         return CMD_SUCCESS;
1556 }
1557
1558 /* per testsim config */
1559 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
1560         "Configure test SIM emulation")
1561 {
1562         vty->node = TESTSIM_NODE;
1563
1564         return CMD_SUCCESS;
1565 }
1566
1567 DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
1568         "Set IMSI on test card\n15 digits IMSI")
1569 {
1570         struct osmocom_ms *ms = vty->index;
1571         struct gsm_settings *set = &ms->settings;
1572         char *error = gsm_check_imsi(argv[0]);
1573
1574         if (error) {
1575                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1576                 return CMD_WARNING;
1577         }
1578
1579         strcpy(set->test_imsi, argv[0]);
1580
1581         vty_restart(vty);
1582         return CMD_SUCCESS;
1583 }
1584
1585 #define HEX_STR "\nByte as two digits hexadecimal"
1586 DEFUN(cfg_test_ki_xor, cfg_test_ki_xor_cmd, "ki xor HEX HEX HEX HEX HEX HEX "
1587         "HEX HEX HEX HEX HEX HEX",
1588         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1589         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR)
1590 {
1591         struct osmocom_ms *ms = vty->index;
1592         struct gsm_settings *set = &ms->settings;
1593         uint8_t ki[12];
1594         const char *p;
1595         int i;
1596
1597         for (i = 0; i < 12; i++) {
1598                 p = argv[i];
1599                 if (!strncmp(p, "0x", 2))
1600                         p += 2;
1601                 if (strlen(p) != 2) {
1602                         vty_out(vty, "Expecting two digits hex value (with or "
1603                                 "without 0x in front)%s", VTY_NEWLINE);
1604                         return CMD_WARNING;
1605                 }
1606                 ki[i] = strtoul(p, NULL, 16);
1607         }
1608
1609         set->test_ki_type = GSM_SIM_KEY_XOR;
1610         memcpy(set->test_ki, ki, 12);
1611         return CMD_SUCCESS;
1612 }
1613
1614 DEFUN(cfg_test_ki_comp128, cfg_test_ki_comp128_cmd, "ki comp128 HEX HEX HEX "
1615         "HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX",
1616         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1617         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR
1618         HEX_STR HEX_STR HEX_STR HEX_STR)
1619 {
1620         struct osmocom_ms *ms = vty->index;
1621         struct gsm_settings *set = &ms->settings;
1622         uint8_t ki[16];
1623         const char *p;
1624         int i;
1625
1626         for (i = 0; i < 16; i++) {
1627                 p = argv[i];
1628                 if (!strncmp(p, "0x", 2))
1629                         p += 2;
1630                 if (strlen(p) != 2) {
1631                         vty_out(vty, "Expecting two digits hex value (with or "
1632                                 "without 0x in front)%s", VTY_NEWLINE);
1633                         return CMD_WARNING;
1634                 }
1635                 ki[i] = strtoul(p, NULL, 16);
1636         }
1637
1638         set->test_ki_type = GSM_SIM_KEY_COMP128;
1639         memcpy(set->test_ki, ki, 16);
1640         return CMD_SUCCESS;
1641 }
1642
1643 DEFUN(cfg_test_barr, cfg_test_barr_cmd, "barred-access",
1644         "Allow access to barred cells")
1645 {
1646         struct osmocom_ms *ms = vty->index;
1647         struct gsm_settings *set = &ms->settings;
1648
1649         set->test_barr = 1;
1650
1651         return CMD_SUCCESS;
1652 }
1653
1654 DEFUN(cfg_test_no_barr, cfg_test_no_barr_cmd, "no barred-access",
1655         NO_STR "Deny access to barred cells")
1656 {
1657         struct osmocom_ms *ms = vty->index;
1658         struct gsm_settings *set = &ms->settings;
1659
1660         set->test_barr = 0;
1661
1662         return CMD_SUCCESS;
1663 }
1664
1665 DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
1666         NO_STR "Unset Registered PLMN")
1667 {
1668         struct osmocom_ms *ms = vty->index;
1669         struct gsm_settings *set = &ms->settings;
1670
1671         set->test_rplmn_valid = 0;
1672
1673         vty_restart(vty);
1674         return CMD_SUCCESS;
1675 }
1676
1677 DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC",
1678         "Set Registered PLMN\nMobile Country Code\nMobile Network Code")
1679 {
1680         struct osmocom_ms *ms = vty->index;
1681         struct gsm_settings *set = &ms->settings;
1682         uint16_t mcc = gsm_input_mcc((char *)argv[0]),
1683                  mnc = gsm_input_mnc((char *)argv[1]);
1684
1685         if (!mcc) {
1686                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
1687                 return CMD_WARNING;
1688         }
1689         if (!mnc) {
1690                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
1691                 return CMD_WARNING;
1692         }
1693         set->test_rplmn_valid = 1;
1694         set->test_rplmn_mcc = mcc;
1695         set->test_rplmn_mnc = mnc;
1696
1697         vty_restart(vty);
1698         return CMD_SUCCESS;
1699 }
1700
1701 DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-country)",
1702         "Set Home PLMN search mode\n"
1703         "Search for HPLMN when on any other network\n"
1704         "Search for HPLMN when in a different country")
1705 {
1706         struct osmocom_ms *ms = vty->index;
1707         struct gsm_settings *set = &ms->settings;
1708
1709         switch (argv[0][0]) {
1710         case 'e':
1711                 set->test_always = 1;
1712                 break;
1713         case 'f':
1714                 set->test_always = 0;
1715                 break;
1716         }
1717
1718         vty_restart(vty);
1719         return CMD_SUCCESS;
1720 }
1721
1722 enum node_type ms_vty_go_parent(struct vty *vty)
1723 {
1724         switch (vty->node) {
1725         case MS_NODE:
1726                 vty->node = CONFIG_NODE;
1727                 vty->index = NULL;
1728                 break;
1729         case TESTSIM_NODE:
1730         case SUPPORT_NODE:
1731                 vty->node = MS_NODE;
1732                 break;
1733         default:
1734                 vty->node = CONFIG_NODE;
1735         }
1736
1737         return vty->node;
1738 }
1739
1740 /* Down vty node level. */
1741 gDEFUN(ournode_exit,
1742        ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
1743 {
1744         switch (vty->node) {
1745         case MS_NODE:
1746                 vty->node = CONFIG_NODE;
1747                 vty->index = NULL;
1748                 break;
1749         case TESTSIM_NODE:
1750         case SUPPORT_NODE:
1751                 vty->node = MS_NODE;
1752                 break;
1753         default:
1754                 break;
1755         }
1756         return CMD_SUCCESS;
1757 }
1758
1759 /* End of configuration. */
1760 gDEFUN(ournode_end,
1761        ournode_end_cmd, "end", "End current mode and change to enable mode.")
1762 {
1763         switch (vty->node) {
1764         case VIEW_NODE:
1765         case ENABLE_NODE:
1766                 /* Nothing to do. */
1767                 break;
1768         case CONFIG_NODE:
1769         case VTY_NODE:
1770         case MS_NODE:
1771         case TESTSIM_NODE:
1772         case SUPPORT_NODE:
1773                 vty_config_unlock(vty);
1774                 vty->node = ENABLE_NODE;
1775                 vty->index = NULL;
1776                 vty->index_sub = NULL;
1777                 break;
1778         default:
1779                 break;
1780         }
1781         return CMD_SUCCESS;
1782 }
1783
1784 #define SUP_NODE(item) \
1785         install_element(SUPPORT_NODE, &cfg_ms_sup_item_cmd);
1786
1787 int ms_vty_init(void)
1788 {
1789         install_element_ve(&show_ms_cmd);
1790         install_element_ve(&show_subscr_cmd);
1791         install_element_ve(&show_support_cmd);
1792         install_element_ve(&show_states_cmd);
1793         install_element_ve(&show_cell_cmd);
1794         install_element_ve(&show_cell_si_cmd);
1795         install_element_ve(&show_ba_cmd);
1796         install_element_ve(&show_forb_la_cmd);
1797         install_element_ve(&show_forb_plmn_cmd);
1798         install_element_ve(&monitor_network_cmd);
1799         install_element_ve(&no_monitor_network_cmd);
1800
1801         install_element(ENABLE_NODE, &sim_test_cmd);
1802         install_element(ENABLE_NODE, &sim_reader_cmd);
1803         install_element(ENABLE_NODE, &sim_remove_cmd);
1804         install_element(ENABLE_NODE, &sim_pin_cmd);
1805         install_element(ENABLE_NODE, &sim_disable_pin_cmd);
1806         install_element(ENABLE_NODE, &sim_enable_pin_cmd);
1807         install_element(ENABLE_NODE, &sim_change_pin_cmd);
1808         install_element(ENABLE_NODE, &sim_unblock_pin_cmd);
1809         install_element(ENABLE_NODE, &sim_lai_cmd);
1810         install_element(ENABLE_NODE, &network_search_cmd);
1811         install_element(ENABLE_NODE, &network_show_cmd);
1812         install_element(ENABLE_NODE, &network_select_cmd);
1813         install_element(ENABLE_NODE, &call_cmd);
1814         install_element(ENABLE_NODE, &call_retr_cmd);
1815
1816         install_element(CONFIG_NODE, &cfg_gps_device_cmd);
1817         install_element(CONFIG_NODE, &cfg_gps_baud_cmd);
1818         install_element(CONFIG_NODE, &cfg_gps_enable_cmd);
1819         install_element(CONFIG_NODE, &cfg_no_gps_enable_cmd);
1820
1821         install_element(CONFIG_NODE, &cfg_ms_cmd);
1822         install_element(CONFIG_NODE, &ournode_end_cmd);
1823         install_node(&ms_node, config_write_ms);
1824         install_default(MS_NODE);
1825         install_element(MS_NODE, &ournode_exit_cmd);
1826         install_element(MS_NODE, &ournode_end_cmd);
1827         install_element(MS_NODE, &cfg_ms_sim_cmd);
1828         install_element(MS_NODE, &cfg_ms_mode_cmd);
1829         install_element(MS_NODE, &cfg_ms_imei_cmd);
1830         install_element(MS_NODE, &cfg_ms_imei_fixed_cmd);
1831         install_element(MS_NODE, &cfg_ms_imei_random_cmd);
1832         install_element(MS_NODE, &cfg_ms_no_emerg_imsi_cmd);
1833         install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
1834         install_element(MS_NODE, &cfg_ms_cw_cmd);
1835         install_element(MS_NODE, &cfg_ms_no_cw_cmd);
1836         install_element(MS_NODE, &cfg_ms_clip_cmd);
1837         install_element(MS_NODE, &cfg_ms_clir_cmd);
1838         install_element(MS_NODE, &cfg_ms_no_clip_cmd);
1839         install_element(MS_NODE, &cfg_ms_no_clir_cmd);
1840         install_element(MS_NODE, &cfg_ms_tx_power_cmd);
1841         install_element(MS_NODE, &cfg_ms_tx_power_val_cmd);
1842         install_element(MS_NODE, &cfg_ms_sim_delay_cmd);
1843         install_element(MS_NODE, &cfg_ms_no_sim_delay_cmd);
1844         install_element(MS_NODE, &cfg_ms_stick_cmd);
1845         install_element(MS_NODE, &cfg_ms_no_stick_cmd);
1846         install_element(MS_NODE, &cfg_ms_lupd_cmd);
1847         install_element(MS_NODE, &cfg_ms_no_lupd_cmd);
1848         install_element(MS_NODE, &cfg_ms_codec_full_cmd);
1849         install_element(MS_NODE, &cfg_ms_codec_full_pref_cmd);
1850         install_element(MS_NODE, &cfg_ms_codec_half_cmd);
1851         install_element(MS_NODE, &cfg_ms_codec_half_pref_cmd);
1852         install_element(MS_NODE, &cfg_ms_no_codec_half_cmd);
1853         install_element(MS_NODE, &cfg_ms_testsim_cmd);
1854         install_element(MS_NODE, &cfg_ms_support_cmd);
1855         install_node(&support_node, config_write_dummy);
1856         install_default(SUPPORT_NODE);
1857         install_element(SUPPORT_NODE, &ournode_exit_cmd);
1858         install_element(SUPPORT_NODE, &ournode_end_cmd);
1859         install_element(SUPPORT_NODE, &cfg_ms_sup_sms_cmd);
1860         install_element(SUPPORT_NODE, &cfg_ms_sup_no_sms_cmd);
1861         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_1_cmd);
1862         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_1_cmd);
1863         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_2_cmd);
1864         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_2_cmd);
1865         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_3_cmd);
1866         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_3_cmd);
1867         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_4_cmd);
1868         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_4_cmd);
1869         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_5_cmd);
1870         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_5_cmd);
1871         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_6_cmd);
1872         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_6_cmd);
1873         install_element(SUPPORT_NODE, &cfg_ms_sup_a5_7_cmd);
1874         install_element(SUPPORT_NODE, &cfg_ms_sup_no_a5_7_cmd);
1875         install_element(SUPPORT_NODE, &cfg_ms_sup_p_gsm_cmd);
1876         install_element(SUPPORT_NODE, &cfg_ms_sup_no_p_gsm_cmd);
1877         install_element(SUPPORT_NODE, &cfg_ms_sup_e_gsm_cmd);
1878         install_element(SUPPORT_NODE, &cfg_ms_sup_no_e_gsm_cmd);
1879         install_element(SUPPORT_NODE, &cfg_ms_sup_r_gsm_cmd);
1880         install_element(SUPPORT_NODE, &cfg_ms_sup_no_r_gsm_cmd);
1881         install_element(SUPPORT_NODE, &cfg_ms_sup_dcs_cmd);
1882         install_element(SUPPORT_NODE, &cfg_ms_sup_no_dcs_cmd);
1883         install_element(SUPPORT_NODE, &cfg_ms_sup_class_900_cmd);
1884         install_element(SUPPORT_NODE, &cfg_ms_sup_class_dcs_cmd);
1885         install_element(SUPPORT_NODE, &cfg_ms_sup_ch_cap_cmd);
1886         install_element(SUPPORT_NODE, &cfg_ms_sup_full_v1_cmd);
1887         install_element(SUPPORT_NODE, &cfg_ms_sup_no_full_v1_cmd);
1888         install_element(SUPPORT_NODE, &cfg_ms_sup_full_v2_cmd);
1889         install_element(SUPPORT_NODE, &cfg_ms_sup_no_full_v2_cmd);
1890         install_element(SUPPORT_NODE, &cfg_ms_sup_full_v3_cmd);
1891         install_element(SUPPORT_NODE, &cfg_ms_sup_no_full_v3_cmd);
1892         install_element(SUPPORT_NODE, &cfg_ms_sup_half_v1_cmd);
1893         install_element(SUPPORT_NODE, &cfg_ms_sup_no_half_v1_cmd);
1894         install_element(SUPPORT_NODE, &cfg_ms_sup_half_v3_cmd);
1895         install_element(SUPPORT_NODE, &cfg_ms_sup_no_half_v3_cmd);
1896         install_element(SUPPORT_NODE, &cfg_ms_sup_min_rxlev_cmd);
1897         install_element(SUPPORT_NODE, &cfg_ms_sup_dsc_max_cmd);
1898         install_node(&testsim_node, config_write_dummy);
1899         install_default(TESTSIM_NODE);
1900         install_element(TESTSIM_NODE, &ournode_exit_cmd);
1901         install_element(TESTSIM_NODE, &ournode_end_cmd);
1902         install_element(TESTSIM_NODE, &cfg_test_imsi_cmd);
1903         install_element(TESTSIM_NODE, &cfg_test_ki_xor_cmd);
1904         install_element(TESTSIM_NODE, &cfg_test_ki_comp128_cmd);
1905         install_element(TESTSIM_NODE, &cfg_test_barr_cmd);
1906         install_element(TESTSIM_NODE, &cfg_test_no_barr_cmd);
1907         install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd);
1908         install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd);
1909         install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd);
1910
1911         return 0;
1912 }
1913
1914 void vty_notify(struct osmocom_ms *ms, const char *fmt, ...)
1915 {
1916         struct telnet_connection *connection;
1917         char buffer[1000];
1918         va_list args;
1919         struct vty *vty;
1920
1921         if (fmt) {
1922                 va_start(args, fmt);
1923                 vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
1924                 buffer[sizeof(buffer) - 1] = '\0';
1925                 va_end(args);
1926
1927                 if (!buffer[0])
1928                         return;
1929         }
1930
1931         llist_for_each_entry(connection, &active_connections, entry) {
1932                 vty = connection->vty;
1933                 if (!vty)
1934                         continue;
1935                 if (!fmt) {
1936                         vty_out(vty, "%s%% (MS %s)%s", VTY_NEWLINE, ms->name,
1937                                 VTY_NEWLINE);
1938                         continue;
1939                 }
1940                 if (buffer[strlen(buffer) - 1] == '\n') {
1941                         buffer[strlen(buffer) - 1] = '\0';
1942                         vty_out(vty, "%% %s%s", buffer, VTY_NEWLINE);
1943                         buffer[strlen(buffer)] = '\n';
1944                 } else
1945                         vty_out(vty, "%% %s", buffer);
1946         }
1947 }
1948