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