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