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