[layer23] Added XOR and COMP128 encryption to test SIM
[osmocom-bb.git] / src / host / layer23 / src / mobile / vty_interface.c
1 /*
2  * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
3  *
4  * All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  */
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27
28 #include <osmocore/utils.h>
29 #include <osmocore/gsm48.h>
30
31 #include <osmocom/bb/common/osmocom_data.h>
32 #include <osmocom/bb/common/networks.h>
33 #include <osmocom/bb/mobile/mncc.h>
34 #include <osmocom/bb/mobile/transaction.h>
35 #include <osmocom/bb/mobile/vty.h>
36 #include <osmocom/bb/mobile/gps.h>
37 #include <osmocom/vty/telnet_interface.h>
38
39 int mncc_call(struct osmocom_ms *ms, char *number);
40 int mncc_hangup(struct osmocom_ms *ms);
41 int mncc_answer(struct osmocom_ms *ms);
42 int mncc_hold(struct osmocom_ms *ms);
43 int mncc_retrieve(struct osmocom_ms *ms, int number);
44
45 extern struct llist_head ms_list;
46 extern struct llist_head active_connections;
47
48 struct cmd_node ms_node = {
49         MS_NODE,
50         "%s(ms)#",
51         1
52 };
53
54 struct cmd_node testsim_node = {
55         TESTSIM_NODE,
56         "%s(test-sim)#",
57         1
58 };
59
60 static void print_vty(void *priv, const char *fmt, ...)
61 {
62         char buffer[1000];
63         struct vty *vty = priv;
64         va_list args;
65
66         va_start(args, fmt);
67         vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
68         buffer[sizeof(buffer) - 1] = '\0';
69         va_end(args);
70
71         if (buffer[0]) {
72                 if (buffer[strlen(buffer) - 1] == '\n') {
73                         buffer[strlen(buffer) - 1] = '\0';
74                         vty_out(vty, "%s%s", buffer, VTY_NEWLINE);
75                 } else
76                         vty_out(vty, "%s", buffer);
77         }
78 }
79
80 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
81 {
82         struct osmocom_ms *ms;
83
84         llist_for_each_entry(ms, &ms_list, entity) {
85                 if (!strcmp(ms->name, name))
86                         return ms;
87         }
88         vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
89
90         return NULL;
91 }
92
93 DEFUN(show_ms, show_ms_cmd, "show ms",
94         SHOW_STR "Display available MS entities\n")
95 {
96         struct osmocom_ms *ms;
97
98         llist_for_each_entry(ms, &ms_list, entity) {
99                 struct gsm_settings *set = &ms->settings;
100
101                 vty_out(vty, "MS NAME: %s%s", ms->name, VTY_NEWLINE);
102                 vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE);
103                 vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE);
104                 if (set->imei_random)
105                         vty_out(vty, " IMEI generation: random (%d trailing "
106                                 "digits)%s", set->imei_random, VTY_NEWLINE);
107                 else
108                         vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE);
109                 vty_out(vty, " network selection mode: %s%s",
110                         (set->plmn_mode == PLMN_MODE_AUTO)
111                                 ? "automatic" : "manual", VTY_NEWLINE);
112         }
113
114         return CMD_SUCCESS;
115 }
116
117 DEFUN(show_support, show_support_cmd, "show support [ms_name]",
118         SHOW_STR "Display information about MS support\n"
119         "Name of MS (see \"show ms\")")
120 {
121         struct osmocom_ms *ms;
122
123         if (argc) {
124                 ms = get_ms(argv[0], vty);
125                 if (!ms)
126                         return CMD_WARNING;
127                 gsm_support_dump(&ms->support, print_vty, vty);
128         } else {
129                 llist_for_each_entry(ms, &ms_list, entity) {
130                         gsm_support_dump(&ms->support, print_vty, vty);
131                         vty_out(vty, "%s", VTY_NEWLINE);
132                 }
133         }
134
135         return CMD_SUCCESS;
136 }
137
138 static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty)
139 {
140         struct gsm_trans *trans;
141
142         vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE);
143         if (ms->settings.plmn_mode == PLMN_MODE_AUTO)
144                 vty_out(vty, " automatic network selection: %s%s", 
145                         plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
146         else
147                 vty_out(vty, " manual network selection: %s%s", 
148                         plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
149         vty_out(vty, " cell selection: %s%s", 
150                 cs_state_names[ms->cellsel.state], VTY_NEWLINE);
151         vty_out(vty, " radio ressource layer: %s%s", 
152                 gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
153         vty_out(vty, " mobility management layer: %s", 
154                 gsm48_mm_state_names[ms->mmlayer.state]);
155         if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
156                 vty_out(vty, ", %s", 
157                         gsm48_mm_substate_names[ms->mmlayer.substate]);
158         vty_out(vty, "%s", VTY_NEWLINE);
159         llist_for_each_entry(trans, &ms->trans_list, entry) {
160                 vty_out(vty, " call control: %s%s", 
161                         gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
162         }
163 }
164
165 DEFUN(show_states, show_states_cmd, "show states [ms_name]",
166         SHOW_STR "Display current states of given MS\n"
167         "Name of MS (see \"show ms\")")
168 {
169         struct osmocom_ms *ms;
170
171         if (argc) {
172                 ms = get_ms(argv[0], vty);
173                 if (!ms)
174                         return CMD_WARNING;
175                 gsm_states_dump(ms, vty);
176         } else {
177                 llist_for_each_entry(ms, &ms_list, entity) {
178                         gsm_states_dump(ms, vty);
179                         vty_out(vty, "%s", VTY_NEWLINE);
180                 }
181         }
182
183         return CMD_SUCCESS;
184 }
185
186 DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]",
187         SHOW_STR "Display information about subscriber\n"
188         "Name of MS (see \"show ms\")")
189 {
190         struct osmocom_ms *ms;
191
192         if (argc) {
193                 ms = get_ms(argv[0], vty);
194                 if (!ms)
195                         return CMD_WARNING;
196                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
197         } else {
198                 llist_for_each_entry(ms, &ms_list, entity) {
199                         gsm_subscr_dump(&ms->subscr, print_vty, vty);
200                         vty_out(vty, "%s", VTY_NEWLINE);
201                 }
202         }
203
204         return CMD_SUCCESS;
205 }
206
207 DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
208         SHOW_STR "Display information about received cells\n"
209         "Name of MS (see \"show ms\")")
210 {
211         struct osmocom_ms *ms;
212
213         ms = get_ms(argv[0], vty);
214         if (!ms)
215                 return CMD_WARNING;
216
217         gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
218                 vty);
219
220         return CMD_SUCCESS;
221 }
222
223 DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>",
224         SHOW_STR "Display information about received cell\n"
225         "Name of MS (see \"show ms\")\nRadio frequency number")
226 {
227         struct osmocom_ms *ms;
228         int i;
229         struct gsm48_sysinfo *s;
230
231         ms = get_ms(argv[0], vty);
232         if (!ms)
233                 return CMD_WARNING;
234
235         i = atoi(argv[1]);
236         if (i < 0 || i > 1023) {
237                 vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s",
238                         argv[1], VTY_NEWLINE);
239                 return CMD_WARNING;
240         }
241         s = ms->cellsel.list[i].sysinfo;
242         if (!s) {
243                 vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s",
244                         argv[1], VTY_NEWLINE);
245                 return CMD_SUCCESS;
246         }
247
248         gsm48_sysinfo_dump(s, i, print_vty, vty);
249
250         return CMD_SUCCESS;
251 }
252
253 DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]",
254         SHOW_STR "Display information about band allocations\n"
255         "Name of MS (see \"show ms\")\nMobile Country Code\n"
256         "Mobile Network Code")
257 {
258         struct osmocom_ms *ms;
259         uint16_t mcc = 0, mnc = 0;
260
261         ms = get_ms(argv[0], vty);
262         if (!ms)
263                 return CMD_WARNING;
264
265         if (argc >= 3) {
266                 mcc = gsm_input_mcc((char *)argv[1]);
267                 mnc = gsm_input_mnc((char *)argv[2]);
268                 if (!mcc) {
269                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
270                         return CMD_WARNING;
271                 }
272                 if (!mnc) {
273                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
274                         return CMD_WARNING;
275                 }
276         }
277
278         gsm322_dump_ba_list(&ms->cellsel, mcc, mnc, print_vty, vty);
279
280         return CMD_SUCCESS;
281 }
282
283 DEFUN(show_forb_plmn, show_forb_plmn_cmd, "show forbidden plmn MS_NAME",
284         SHOW_STR "Display information about forbidden cells / networks\n"
285         "Display forbidden PLMNs\nName of MS (see \"show ms\")")
286 {
287         struct osmocom_ms *ms;
288
289         ms = get_ms(argv[0], vty);
290         if (!ms)
291                 return CMD_WARNING;
292
293         gsm_subscr_dump_forbidden_plmn(ms, print_vty, vty);
294
295         return CMD_SUCCESS;
296 }
297
298 DEFUN(show_forb_la, show_forb_la_cmd, "show forbidden location-area MS_NAME",
299         SHOW_STR "Display information about forbidden cells / networks\n"
300         "Display forbidden location areas\nName of MS (see \"show ms\")")
301 {
302         struct osmocom_ms *ms;
303
304         ms = get_ms(argv[0], vty);
305         if (!ms)
306                 return CMD_WARNING;
307
308         gsm322_dump_forbidden_la(ms, print_vty, vty);
309
310         return CMD_SUCCESS;
311 }
312
313 DEFUN(monitor_network, monitor_network_cmd, "monitor network MS_NAME",
314         "Monitor...\nMonitor network information\nName of MS (see \"show ms\")")
315 {
316         struct osmocom_ms *ms;
317
318         ms = get_ms(argv[0], vty);
319         if (!ms)
320                 return CMD_WARNING;
321
322         gsm48_rr_start_monitor(ms);
323
324         return CMD_SUCCESS;
325 }
326
327 DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME",
328         NO_STR "Monitor...\nDeactivate monitor of network information\n"
329         "Name of MS (see \"show ms\")")
330 {
331         struct osmocom_ms *ms;
332
333         ms = get_ms(argv[0], vty);
334         if (!ms)
335                 return CMD_WARNING;
336
337         gsm48_rr_stop_monitor(ms);
338
339         return CMD_SUCCESS;
340 }
341
342 DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]",
343         "SIM actions\nInsert test card\nName of MS (see \"show ms\")\n"
344         "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN")
345 {
346         struct osmocom_ms *ms;
347         uint16_t mcc = 0x001, mnc = 0x01f;
348
349         ms = get_ms(argv[0], vty);
350         if (!ms)
351                 return CMD_WARNING;
352
353         if (ms->subscr.sim_valid) {
354                 vty_out(vty, "SIM already presend, remove first!%s",
355                         VTY_NEWLINE);
356                 return CMD_WARNING;
357         }
358
359         if (argc >= 3) {
360                 mcc = gsm_input_mcc((char *)argv[1]);
361                 mnc = gsm_input_mnc((char *)argv[2]);
362                 if (!mcc) {
363                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
364                         return CMD_WARNING;
365                 }
366                 if (!mnc) {
367                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
368                         return CMD_WARNING;
369                 }
370         }
371
372         gsm_subscr_testcard(ms, mcc, mnc);
373
374         return CMD_SUCCESS;
375 }
376
377 DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
378         "SIM actions\nSelect SIM from reader\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         if (ms->subscr.sim_valid) {
387                 vty_out(vty, "SIM already presend, remove first!%s",
388                         VTY_NEWLINE);
389                 return CMD_WARNING;
390         }
391
392         gsm_subscr_simcard(ms);
393
394         return CMD_SUCCESS;
395 }
396
397 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
398         "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")")
399 {
400         struct osmocom_ms *ms;
401
402         ms = get_ms(argv[0], vty);
403         if (!ms)
404                 return CMD_WARNING;
405
406         if (!ms->subscr.sim_valid) {
407                 vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
408                 return CMD_WARNING;
409         }
410
411         gsm_subscr_remove(ms);
412
413         return CMD_SUCCESS;
414 }
415
416 DEFUN(sim_pin, sim_pin_cmd, "sim pin MS_NAME PIN",
417         "SIM actions\nEnter PIN for SIM card\nName of MS (see \"show ms\")\n"
418         "PIN number")
419 {
420         struct osmocom_ms *ms;
421
422         ms = get_ms(argv[0], vty);
423         if (!ms)
424                 return CMD_WARNING;
425
426         if (!ms->subscr.sim_pin_required) {
427                 vty_out(vty, "No PIN is required at this time!%s", VTY_NEWLINE);
428                 return CMD_WARNING;
429         }
430
431         gsm_subscr_sim_pin(ms, (char *)argv[1]);
432
433         return CMD_SUCCESS;
434 }
435
436 DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
437         "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
438         "Mobile Country Code\nMobile Network Code")
439 {
440         struct osmocom_ms *ms;
441         struct gsm322_plmn *plmn;
442         struct msgb *nmsg;
443         struct gsm322_msg *ngm;
444         struct gsm322_plmn_list *temp;
445         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
446                  mnc = gsm_input_mnc((char *)argv[2]);
447         int found = 0;
448
449         ms = get_ms(argv[0], vty);
450         if (!ms)
451                 return CMD_WARNING;
452         plmn = &ms->plmn;
453
454         if (!mcc) {
455                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
456                 return CMD_WARNING;
457         }
458         if (!mnc) {
459                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
460                 return CMD_WARNING;
461         }
462
463         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
464                 if (temp->mcc == mcc &&  temp->mnc == mnc)
465                         found = 1;
466         if (!found) {
467                 vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
468                 return CMD_WARNING;
469         }
470
471         nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
472         if (!nmsg)
473                 return CMD_WARNING;
474         ngm = (struct gsm322_msg *) nmsg->data;
475         ngm->mcc = mcc;
476         ngm->mnc = mnc;
477         gsm322_plmn_sendmsg(ms, nmsg);
478
479         return CMD_SUCCESS;
480 }
481
482 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
483         "Make a call\nName of MS (see \"show ms\")\nPhone number to call\n"
484         "Make an emergency call\nAnswer an incomming call\nHangup a call\n"
485         "Hold current active call\n")
486 {
487         struct osmocom_ms *ms;
488
489         ms = get_ms(argv[0], vty);
490         if (!ms)
491                 return CMD_WARNING;
492
493         switch (argv[1][0]) {
494         case 'a':
495                 mncc_answer(ms);
496                 break;
497         case 'h':
498                 if (argv[1][1] == 'a')
499                         mncc_hangup(ms);
500                 else
501                         mncc_hold(ms);
502                 break;
503         default:
504                 mncc_call(ms, (char *)argv[1]);
505         }
506
507         return CMD_SUCCESS;
508 }
509
510 DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]",
511         "Make a call\nName of MS (see \"show ms\")\n"
512         "Retrieve call on hold\nNumber of call to retrieve")
513 {
514         struct osmocom_ms *ms;
515
516         ms = get_ms(argv[0], vty);
517         if (!ms)
518                 return CMD_WARNING;
519
520         mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
521
522         return CMD_SUCCESS;
523 }
524
525 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
526         "Network ...\nShow results of network search (again)\n"
527         "Name of MS (see \"show ms\")")
528 {
529         struct osmocom_ms *ms;
530         struct gsm322_plmn *plmn;
531         struct gsm322_plmn_list *temp;
532
533         ms = get_ms(argv[0], vty);
534         if (!ms)
535                 return CMD_WARNING;
536         plmn = &ms->plmn;
537
538         if (ms->settings.plmn_mode != PLMN_MODE_AUTO
539          && plmn->state != GSM322_M3_NOT_ON_PLMN) {
540                 vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
541                 return CMD_WARNING;
542         }
543
544         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
545                 vty_out(vty, " Network %s, %s (%s, %s)%s",
546                         gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
547                         gsm_get_mcc(temp->mcc),
548                         gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
549
550         return CMD_SUCCESS;
551 }
552
553 DEFUN(network_search, network_search_cmd, "network search MS_NAME",
554         "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
555 {
556         struct osmocom_ms *ms;
557         struct msgb *nmsg;
558
559         ms = get_ms(argv[0], vty);
560         if (!ms)
561                 return CMD_WARNING;
562
563         nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
564         if (!nmsg)
565                 return CMD_WARNING;
566         gsm322_plmn_sendmsg(ms, nmsg);
567
568         return CMD_SUCCESS;
569 }
570
571 DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable",
572         "GPS receiver")
573 {
574         if (gps_open()) {
575                 gps.enable = 1;
576                 vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE);
577                 return CMD_WARNING;
578         }
579         gps.enable = 1;
580
581         return CMD_SUCCESS;
582 }
583
584 DEFUN(cfg_no_gps_enable, cfg_no_gps_enable_cmd, "no gps enable",
585         NO_STR "Disable GPS receiver")
586 {
587         if (gps.enable)
588                 gps_close();
589         gps.enable = 0;
590
591         return CMD_SUCCESS;
592 }
593
594 DEFUN(cfg_gps_device, cfg_gps_device_cmd, "gps device DEVICE",
595         "GPS receiver\nSelect serial device\n"
596         "Full path of serial device including /dev/")
597 {
598         strncpy(gps.device, argv[0], sizeof(gps.device));
599         gps.device[sizeof(gps.device) - 1] = '\0';
600         if (gps.enable) {
601                 gps_close();
602                 if (gps_open()) {
603                         vty_out(vty, "Failed to open GPS device!%s",
604                                 VTY_NEWLINE);
605                         return CMD_WARNING;
606                 }
607         }
608
609         return CMD_SUCCESS;
610 }
611
612 DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate "
613         "(default|4800|""9600|19200|38400|57600|115200)",
614         "GPS receiver\nSelect baud rate\nDefault, don't modify\n\n\n\n\n\n")
615 {
616         if (argv[0][0] == 'd')
617                 gps.baud = 0;
618         else
619                 gps.baud = atoi(argv[0]);
620         if (gps.enable) {
621                 gps_close();
622                 if (gps_open()) {
623                         gps.enable = 0;
624                         vty_out(vty, "Failed to open GPS device!%s",
625                                 VTY_NEWLINE);
626                         return CMD_WARNING;
627                 }
628         }
629
630         return CMD_SUCCESS;
631 }
632
633 /* per MS config */
634 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
635         "Select a mobile station to configure\nName of MS (see \"show ms\")")
636 {
637         struct osmocom_ms *ms;
638
639         ms = get_ms(argv[0], vty);
640         if (!ms)
641                 return CMD_WARNING;
642
643         vty->index = ms;
644         vty->node = MS_NODE;
645
646         return CMD_SUCCESS;
647 }
648
649 static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
650 {
651         struct gsm_settings *set = &ms->settings;
652
653         vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
654         switch(set->sim_type) {
655                 case GSM_SIM_TYPE_NONE:
656                 vty_out(vty, " sim none%s", VTY_NEWLINE);
657                 break;
658                 case GSM_SIM_TYPE_READER:
659                 vty_out(vty, " sim reader%s", VTY_NEWLINE);
660                 break;
661                 case GSM_SIM_TYPE_TEST:
662                 vty_out(vty, " sim test%s", VTY_NEWLINE);
663                 break;
664         }
665         vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
666                         == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
667         vty_out(vty, " imei %s %s%s", set->imei,
668                 set->imeisv + strlen(set->imei), VTY_NEWLINE);
669         if (set->imei_random)
670                 vty_out(vty, " imei-random %d%s", set->imei_random,
671                         VTY_NEWLINE);
672         else
673                 vty_out(vty, " imei-fixed%s", VTY_NEWLINE);
674         if (set->emergency_imsi[0])
675                 vty_out(vty, " emergency-imsi %s%s", set->emergency_imsi,
676                         VTY_NEWLINE);
677         else
678                 vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE);
679         vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE);
680         vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE);
681         vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE);
682         vty_out(vty, " test-sim%s", VTY_NEWLINE);
683         vty_out(vty, "  imsi %s%s", set->test_imsi, VTY_NEWLINE);
684         switch (set->test_ki_type) {
685         case GSM_SIM_KEY_XOR:
686                 vty_out(vty, "  ki xor %s%s", hexdump(set->test_ki, 12),
687                         VTY_NEWLINE);
688                 break;
689         case GSM_SIM_KEY_COMP128:
690                 vty_out(vty, "  ki comp128 %s%s", hexdump(set->test_ki, 16),
691                         VTY_NEWLINE);
692                 break;
693         }
694         vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
695                 VTY_NEWLINE);
696         if (set->test_rplmn_valid)
697                 vty_out(vty, "  rplmn %s %s%s",
698                         gsm_print_mcc(set->test_rplmn_mcc),
699                         gsm_print_mnc(set->test_rplmn_mnc),
700                         VTY_NEWLINE);
701         else
702                 vty_out(vty, "  no rplmn%s", VTY_NEWLINE);
703         vty_out(vty, "  hplmn-search %s%s", (set->test_always) ? "everywhere"
704                         : "foreign-country", VTY_NEWLINE);
705         vty_out(vty, " exit%s", VTY_NEWLINE);
706         if (set->alter_tx_power)
707                 if (set->alter_tx_power_value)
708                         vty_out(vty, " tx-power %d%s",
709                                 set->alter_tx_power_value, VTY_NEWLINE);
710                 else
711                         vty_out(vty, " tx-power full%s", VTY_NEWLINE);
712         else
713                 vty_out(vty, " tx-power auto%s", VTY_NEWLINE);
714         if (set->alter_delay)
715                 vty_out(vty, " simulated-delay %d%s", set->alter_delay,
716                         VTY_NEWLINE);
717         else
718                 vty_out(vty, " no simulated-delay%s", VTY_NEWLINE);
719         if (set->stick)
720                 vty_out(vty, " stick %d%s", set->stick_arfcn,
721                         VTY_NEWLINE);
722         else
723                 vty_out(vty, " no stick%s", VTY_NEWLINE);
724         if (set->no_lupd)
725                 vty_out(vty, " no location-updating%s", VTY_NEWLINE);
726         else
727                 vty_out(vty, " location-updating%s", VTY_NEWLINE);
728         vty_out(vty, "exit%s", VTY_NEWLINE);
729         vty_out(vty, "!%s", VTY_NEWLINE);
730 }
731
732 static int config_write_ms(struct vty *vty)
733 {
734         struct osmocom_ms *ms;
735
736         vty_out(vty, "gps device %s%s", gps.device, VTY_NEWLINE);
737         if (gps.baud)
738                 vty_out(vty, "gps baudrate %d%s", gps.baud, VTY_NEWLINE);
739         else
740                 vty_out(vty, "gps baudrate default%s", VTY_NEWLINE);
741         vty_out(vty, "%sgps enable%s", (gps.enable) ? "" : "no ", VTY_NEWLINE);
742         vty_out(vty, "!%s", VTY_NEWLINE);
743
744         llist_for_each_entry(ms, &ms_list, entity)
745                 config_write_ms_single(vty, ms);
746
747         return CMD_SUCCESS;
748 }
749
750 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)",
751         "Set SIM card type when powering on\nNo SIM interted\n"
752         "Use SIM from reader\nTest SIM inserted")
753 {
754         struct osmocom_ms *ms = vty->index;
755
756         switch (argv[0][0]) {
757         case 'n':
758                 ms->settings.sim_type = GSM_SIM_TYPE_NONE;
759                 break;
760         case 'r':
761                 ms->settings.sim_type = GSM_SIM_TYPE_READER;
762                 break;
763         case 't':
764                 ms->settings.sim_type = GSM_SIM_TYPE_TEST;
765                 break;
766         default:
767                 vty_out(vty, "unknown SIM type%s", VTY_NEWLINE);
768                 return CMD_WARNING;
769         }
770
771         return CMD_SUCCESS;
772 }
773
774 DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
775         "Set network selection mode\nAutomatic network selection\n"
776         "Manual network selection")
777 {
778         struct osmocom_ms *ms = vty->index;
779         struct msgb *nmsg;
780
781         if (!ms->plmn.state) {
782                 if (argv[0][0] == 'a')
783                         ms->settings.plmn_mode = PLMN_MODE_AUTO;
784                 else
785                         ms->settings.plmn_mode = PLMN_MODE_MANUAL;
786
787                 return CMD_SUCCESS;
788         }
789         if (argv[0][0] == 'a')
790                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
791         else
792                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
793         if (!nmsg)
794                 return CMD_WARNING;
795         gsm322_plmn_sendmsg(ms, nmsg);
796
797         return CMD_SUCCESS;
798 }
799
800 DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
801         "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
802         "Software version digit")
803 {
804         struct osmocom_ms *ms = vty->index;
805         char *error, *sv = "0";
806
807         if (argc >= 2)
808                 sv = (char *)argv[1];
809
810         error = gsm_check_imei(argv[0], sv);
811         if (error) {
812                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
813                 return CMD_WARNING;
814         }
815
816         strcpy(ms->settings.imei, argv[0]);
817         strcpy(ms->settings.imeisv, argv[0]);
818         strcpy(ms->settings.imeisv + 15, sv);
819
820         return CMD_SUCCESS;
821 }
822
823 DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
824         "Use fixed IMEI on every power on")
825 {
826         struct osmocom_ms *ms = vty->index;
827
828         ms->settings.imei_random = 0;
829
830         return CMD_SUCCESS;
831 }
832
833 DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
834         "Use random IMEI on every power on\n"
835         "Number of trailing digits to randomize")
836 {
837         struct osmocom_ms *ms = vty->index;
838
839         ms->settings.imei_random = atoi(argv[0]);
840
841         return CMD_SUCCESS;
842 }
843
844 DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi IMSI",
845         "Use special IMSI for emergency calls\n15 digits IMSI")
846 {
847         struct osmocom_ms *ms = vty->index;
848         char *error;
849
850         error = gsm_check_imsi(argv[0]);
851         if (error) {
852                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
853                 return CMD_WARNING;
854         }
855         strcpy(ms->settings.emergency_imsi, argv[0]);
856
857         return CMD_SUCCESS;
858 }
859
860 DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
861         NO_STR "Use IMSI of SIM or IMEI for emergency calls")
862 {
863         struct osmocom_ms *ms = vty->index;
864
865         ms->settings.emergency_imsi[0] = '\0';
866
867         return CMD_SUCCESS;
868 }
869
870 DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
871         NO_STR "Disallow waiting calls")
872 {
873         struct osmocom_ms *ms = vty->index;
874
875         ms->settings.cw = 0;
876
877         return CMD_SUCCESS;
878 }
879
880 DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
881         "Allow waiting calls")
882 {
883         struct osmocom_ms *ms = vty->index;
884
885         ms->settings.cw = 1;
886
887         return CMD_SUCCESS;
888 }
889
890 DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
891         "Force caller ID presentation")
892 {
893         struct osmocom_ms *ms = vty->index;
894
895         ms->settings.clip = 1;
896         ms->settings.clir = 0;
897
898         return CMD_SUCCESS;
899 }
900
901 DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
902         "Force caller ID restriction")
903 {
904         struct osmocom_ms *ms = vty->index;
905
906         ms->settings.clip = 0;
907         ms->settings.clir = 1;
908
909         return CMD_SUCCESS;
910 }
911
912 DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
913         NO_STR "Disable forcing of caller ID presentation")
914 {
915         struct osmocom_ms *ms = vty->index;
916
917         ms->settings.clip = 0;
918
919         return CMD_SUCCESS;
920 }
921
922 DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
923         NO_STR "Disable forcing of caller ID restriction")
924 {
925         struct osmocom_ms *ms = vty->index;
926
927         ms->settings.clir = 0;
928
929         return CMD_SUCCESS;
930 }
931
932 DEFUN(cfg_ms_tx_power, cfg_ms_tx_power_cmd, "tx-power (auto|full)",
933         "Set the way to choose transmit power\nControlled by BTS\n"
934         "Always full power\nFixed GSM power value if supported")
935 {
936         struct osmocom_ms *ms = vty->index;
937
938         switch (argv[0][0]) {
939         case 'a':
940                 ms->settings.alter_tx_power = 0;
941                 break;
942         case 'f':
943                 ms->settings.alter_tx_power = 1;
944                 ms->settings.alter_tx_power_value = 0;
945                 break;
946         }
947
948         return CMD_SUCCESS;
949 }
950
951 DEFUN(cfg_ms_tx_power_val, cfg_ms_tx_power_val_cmd, "tx-power <0-31>",
952         "Set the way to choose transmit power\n"
953         "Fixed GSM power value if supported")
954 {
955         struct osmocom_ms *ms = vty->index;
956
957         ms->settings.alter_tx_power = 1;
958         ms->settings.alter_tx_power_value = atoi(argv[0]);
959
960         return CMD_SUCCESS;
961 }
962
963 DEFUN(cfg_ms_sim_delay, cfg_ms_sim_delay_cmd, "simulated-delay <-128-127>",
964         "Simulate a lower or higher distance from the BTS\n"
965         "Delay in half bits (distance in 553.85 meter steps)")
966 {
967         struct osmocom_ms *ms = vty->index;
968
969         ms->settings.alter_delay = atoi(argv[0]);
970
971         return CMD_SUCCESS;
972 }
973
974 DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
975         NO_STR "Do not simulate a lower or higher distance from the BTS")
976 {
977         struct osmocom_ms *ms = vty->index;
978
979         ms->settings.alter_delay = 0;
980
981         return CMD_SUCCESS;
982 }
983
984 DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023>",
985         "Stick to the given cell\nARFCN of the cell to stick to")
986 {
987         struct osmocom_ms *ms = vty->index;
988
989         ms->settings.stick = 1;
990         ms->settings.stick_arfcn = atoi(argv[0]);
991
992         return CMD_SUCCESS;
993 }
994
995 DEFUN(cfg_ms_no_stick, cfg_ms_no_stick_cmd, "no stick",
996         NO_STR "Do not stick to any cell")
997 {
998         struct osmocom_ms *ms = vty->index;
999
1000         ms->settings.stick = 0;
1001
1002         return CMD_SUCCESS;
1003 }
1004
1005 DEFUN(cfg_ms_lupd, cfg_ms_lupd_cmd, "location-updating",
1006         "Allow location updating")
1007 {
1008         struct osmocom_ms *ms = vty->index;
1009
1010         ms->settings.no_lupd = 0;
1011
1012         return CMD_SUCCESS;
1013 }
1014
1015 DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating",
1016         NO_STR "Do not allow location updating")
1017 {
1018         struct osmocom_ms *ms = vty->index;
1019
1020         ms->settings.no_lupd = 1;
1021
1022         return CMD_SUCCESS;
1023 }
1024
1025 /* per testsim config */
1026 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
1027         "Configure test SIM emulation")
1028 {
1029         vty->node = TESTSIM_NODE;
1030
1031         return CMD_SUCCESS;
1032 }
1033
1034 static int config_write_dummy(struct vty *vty)
1035 {
1036         return CMD_SUCCESS;
1037 }
1038
1039 DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
1040         "Set IMSI on test card\n15 digits IMSI")
1041 {
1042         struct osmocom_ms *ms = vty->index;
1043         char *error = gsm_check_imsi(argv[0]);
1044
1045         if (error) {
1046                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1047                 return CMD_WARNING;
1048         }
1049
1050         strcpy(ms->settings.test_imsi, argv[0]);
1051
1052         return CMD_SUCCESS;
1053 }
1054
1055 #define HEX_STR "\nByte as two digits hexadecimal"
1056 DEFUN(cfg_test_ki_xor, cfg_test_ki_xor_cmd, "ki xor HEX HEX HEX HEX HEX HEX "
1057         "HEX HEX HEX HEX HEX HEX",
1058         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1059         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR)
1060 {
1061         struct osmocom_ms *ms = vty->index;
1062         struct gsm_settings *set = &ms->settings;
1063         uint8_t ki[12];
1064         const char *p;
1065         int i;
1066
1067         for (i = 0; i < 12; i++) {
1068                 p = argv[i];
1069                 if (!strncmp(p, "0x", 2))
1070                         p += 2;
1071                 if (strlen(p) != 2) {
1072                         vty_out(vty, "Expecting two digits hex value (with or "
1073                                 "without 0x in front)%s", VTY_NEWLINE);
1074                         return CMD_WARNING;
1075                 }
1076                 ki[i] = strtoul(p, NULL, 16);
1077         }
1078
1079         set->test_ki_type = GSM_SIM_KEY_XOR;
1080         memcpy(set->test_ki, ki, 12);
1081         return CMD_SUCCESS;
1082 }
1083
1084 DEFUN(cfg_test_ki_comp128, cfg_test_ki_comp128_cmd, "ki comp128 HEX HEX HEX "
1085         "HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX",
1086         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1087         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR
1088         HEX_STR HEX_STR HEX_STR HEX_STR)
1089 {
1090         struct osmocom_ms *ms = vty->index;
1091         struct gsm_settings *set = &ms->settings;
1092         uint8_t ki[16];
1093         const char *p;
1094         int i;
1095
1096         for (i = 0; i < 16; i++) {
1097                 p = argv[i];
1098                 if (!strncmp(p, "0x", 2))
1099                         p += 2;
1100                 if (strlen(p) != 2) {
1101                         vty_out(vty, "Expecting two digits hex value (with or "
1102                                 "without 0x in front)%s", VTY_NEWLINE);
1103                         return CMD_WARNING;
1104                 }
1105                 ki[i] = strtoul(p, NULL, 16);
1106         }
1107
1108         set->test_ki_type = GSM_SIM_KEY_COMP128;
1109         memcpy(set->test_ki, ki, 16);
1110         return CMD_SUCCESS;
1111 }
1112
1113 DEFUN(cfg_test_barr, cfg_test_barr_cmd, "barred-access",
1114         "Allow access to barred cells")
1115 {
1116         struct osmocom_ms *ms = vty->index;
1117
1118         ms->settings.test_barr = 1;
1119
1120         return CMD_SUCCESS;
1121 }
1122
1123 DEFUN(cfg_test_no_barr, cfg_test_no_barr_cmd, "no barred-access",
1124         NO_STR "Deny access to barred cells")
1125 {
1126         struct osmocom_ms *ms = vty->index;
1127
1128         ms->settings.test_barr = 0;
1129
1130         return CMD_SUCCESS;
1131 }
1132
1133 DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
1134         NO_STR "Unset Registered PLMN")
1135 {
1136         struct osmocom_ms *ms = vty->index;
1137
1138         ms->settings.test_rplmn_valid = 0;
1139
1140         return CMD_SUCCESS;
1141 }
1142
1143 DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC",
1144         "Set Registered PLMN\nMobile Country Code\nMobile Network Code")
1145 {
1146         struct osmocom_ms *ms = vty->index;
1147         uint16_t mcc = gsm_input_mcc((char *)argv[0]),
1148                  mnc = gsm_input_mnc((char *)argv[1]);
1149
1150         if (!mcc) {
1151                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
1152                 return CMD_WARNING;
1153         }
1154         if (!mnc) {
1155                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
1156                 return CMD_WARNING;
1157         }
1158         ms->settings.test_rplmn_valid = 1;
1159         ms->settings.test_rplmn_mcc = mcc;
1160         ms->settings.test_rplmn_mnc = mnc;
1161
1162         return CMD_SUCCESS;
1163 }
1164
1165 DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-country)",
1166         "Set Home PLMN search mode\n"
1167         "Search for HPLMN when on any other network\n"
1168         "Search for HPLMN when in a different country")
1169 {
1170         struct osmocom_ms *ms = vty->index;
1171
1172         switch (argv[0][0]) {
1173         case 'e':
1174                 ms->settings.test_always = 1;
1175                 break;
1176         case 'f':
1177                 ms->settings.test_always = 0;
1178                 break;
1179         }
1180
1181         return CMD_SUCCESS;
1182 }
1183
1184 enum node_type ms_vty_go_parent(struct vty *vty)
1185 {
1186         switch (vty->node) {
1187         case MS_NODE:
1188                 vty->node = CONFIG_NODE;
1189                 vty->index = NULL;
1190                 break;
1191         case TESTSIM_NODE:
1192                 vty->node = MS_NODE;
1193                 break;
1194         default:
1195                 vty->node = CONFIG_NODE;
1196         }
1197
1198         return vty->node;
1199 }
1200
1201 /* Down vty node level. */
1202 gDEFUN(ournode_exit,
1203        ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
1204 {
1205         switch (vty->node) {
1206         case MS_NODE:
1207                 vty->node = CONFIG_NODE;
1208                 vty->index = NULL;
1209                 break;
1210         case TESTSIM_NODE:
1211                 vty->node = MS_NODE;
1212                 break;
1213         default:
1214                 break;
1215         }
1216         return CMD_SUCCESS;
1217 }
1218
1219 /* End of configuration. */
1220 gDEFUN(ournode_end,
1221        ournode_end_cmd, "end", "End current mode and change to enable mode.")
1222 {
1223         switch (vty->node) {
1224         case VIEW_NODE:
1225         case ENABLE_NODE:
1226                 /* Nothing to do. */
1227                 break;
1228         case CONFIG_NODE:
1229         case VTY_NODE:
1230         case MS_NODE:
1231         case TESTSIM_NODE:
1232                 vty_config_unlock(vty);
1233                 vty->node = ENABLE_NODE;
1234                 vty->index = NULL;
1235                 vty->index_sub = NULL;
1236                 break;
1237         default:
1238                 break;
1239         }
1240         return CMD_SUCCESS;
1241 }
1242
1243 int ms_vty_init(void)
1244 {
1245         install_element_ve(&show_ms_cmd);
1246         install_element_ve(&show_subscr_cmd);
1247         install_element_ve(&show_support_cmd);
1248         install_element_ve(&show_states_cmd);
1249         install_element_ve(&show_cell_cmd);
1250         install_element_ve(&show_cell_si_cmd);
1251         install_element_ve(&show_ba_cmd);
1252         install_element_ve(&show_forb_la_cmd);
1253         install_element_ve(&show_forb_plmn_cmd);
1254         install_element_ve(&monitor_network_cmd);
1255         install_element_ve(&no_monitor_network_cmd);
1256
1257         install_element(ENABLE_NODE, &sim_test_cmd);
1258         install_element(ENABLE_NODE, &sim_reader_cmd);
1259         install_element(ENABLE_NODE, &sim_remove_cmd);
1260         install_element(ENABLE_NODE, &sim_pin_cmd);
1261         install_element(ENABLE_NODE, &network_search_cmd);
1262         install_element(ENABLE_NODE, &network_show_cmd);
1263         install_element(ENABLE_NODE, &network_select_cmd);
1264         install_element(ENABLE_NODE, &call_cmd);
1265         install_element(ENABLE_NODE, &call_retr_cmd);
1266
1267         install_element(CONFIG_NODE, &cfg_gps_device_cmd);
1268         install_element(CONFIG_NODE, &cfg_gps_baud_cmd);
1269         install_element(CONFIG_NODE, &cfg_gps_enable_cmd);
1270         install_element(CONFIG_NODE, &cfg_no_gps_enable_cmd);
1271
1272         install_element(CONFIG_NODE, &cfg_ms_cmd);
1273         install_element(CONFIG_NODE, &ournode_end_cmd);
1274         install_node(&ms_node, config_write_ms);
1275         install_default(MS_NODE);
1276         install_element(MS_NODE, &ournode_exit_cmd);
1277         install_element(MS_NODE, &ournode_end_cmd);
1278         install_element(MS_NODE, &cfg_ms_sim_cmd);
1279         install_element(MS_NODE, &cfg_ms_mode_cmd);
1280         install_element(MS_NODE, &cfg_ms_imei_cmd);
1281         install_element(MS_NODE, &cfg_ms_imei_fixed_cmd);
1282         install_element(MS_NODE, &cfg_ms_imei_random_cmd);
1283         install_element(MS_NODE, &cfg_ms_no_emerg_imsi_cmd);
1284         install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
1285         install_element(MS_NODE, &cfg_ms_cw_cmd);
1286         install_element(MS_NODE, &cfg_ms_no_cw_cmd);
1287         install_element(MS_NODE, &cfg_ms_clip_cmd);
1288         install_element(MS_NODE, &cfg_ms_clir_cmd);
1289         install_element(MS_NODE, &cfg_ms_no_clip_cmd);
1290         install_element(MS_NODE, &cfg_ms_no_clir_cmd);
1291         install_element(MS_NODE, &cfg_ms_testsim_cmd);
1292         install_element(MS_NODE, &cfg_ms_tx_power_cmd);
1293         install_element(MS_NODE, &cfg_ms_tx_power_val_cmd);
1294         install_element(MS_NODE, &cfg_ms_sim_delay_cmd);
1295         install_element(MS_NODE, &cfg_ms_no_sim_delay_cmd);
1296         install_element(MS_NODE, &cfg_ms_stick_cmd);
1297         install_element(MS_NODE, &cfg_ms_no_stick_cmd);
1298         install_element(MS_NODE, &cfg_ms_lupd_cmd);
1299         install_element(MS_NODE, &cfg_ms_no_lupd_cmd);
1300
1301         install_node(&testsim_node, config_write_dummy);
1302         install_default(TESTSIM_NODE);
1303         install_element(TESTSIM_NODE, &ournode_exit_cmd);
1304         install_element(TESTSIM_NODE, &ournode_end_cmd);
1305         install_element(TESTSIM_NODE, &cfg_test_imsi_cmd);
1306         install_element(TESTSIM_NODE, &cfg_test_ki_xor_cmd);
1307         install_element(TESTSIM_NODE, &cfg_test_ki_comp128_cmd);
1308         install_element(TESTSIM_NODE, &cfg_test_barr_cmd);
1309         install_element(TESTSIM_NODE, &cfg_test_no_barr_cmd);
1310         install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd);
1311         install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd);
1312         install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd);
1313
1314         return 0;
1315 }
1316
1317 void vty_notify(struct osmocom_ms *ms, const char *fmt, ...)
1318 {
1319         struct telnet_connection *connection;
1320         char buffer[1000];
1321         va_list args;
1322         struct vty *vty;
1323
1324         if (fmt) {
1325                 va_start(args, fmt);
1326                 vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
1327                 buffer[sizeof(buffer) - 1] = '\0';
1328                 va_end(args);
1329
1330                 if (!buffer[0])
1331                         return;
1332         }
1333
1334         llist_for_each_entry(connection, &active_connections, entry) {
1335                 vty = connection->vty;
1336                 if (!vty)
1337                         continue;
1338                 if (!fmt) {
1339                         vty_out(vty, "%s%% (MS %s)%s", VTY_NEWLINE, ms->name,
1340                                 VTY_NEWLINE);
1341                         continue;
1342                 }
1343                 if (buffer[strlen(buffer) - 1] == '\n') {
1344                         buffer[strlen(buffer) - 1] = '\0';
1345                         vty_out(vty, "%% %s%s", buffer, VTY_NEWLINE);
1346                         buffer[strlen(buffer)] = '\n';
1347                 } else
1348                         vty_out(vty, "%% %s", buffer);
1349         }
1350 }
1351