[layer23] Removed cloned VTY and replaced it by libosmovty.
[osmocom-bb.git] / src / host / layer23 / src / 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 <osmocom/vty.h>
29 #include <osmocom/vty/telnet_interface.h>
30
31 #include <osmocore/gsm48.h>
32 #include <osmocom/osmocom_data.h>
33 #include <osmocom/networks.h>
34 #include <osmocom/mncc.h>
35 #include <osmocom/transaction.h>
36
37 int mncc_call(struct osmocom_ms *ms, char *number);
38 int mncc_hangup(struct osmocom_ms *ms);
39 int mncc_answer(struct osmocom_ms *ms);
40 int mncc_hold(struct osmocom_ms *ms);
41 int mncc_retrieve(struct osmocom_ms *ms, int number);
42
43 extern struct llist_head ms_list;
44 extern struct llist_head active_connections;
45
46 struct cmd_node ms_node = {
47         MS_NODE,
48         "%s(ms)#",
49         1
50 };
51
52 struct cmd_node testsim_node = {
53         TESTSIM_NODE,
54         "%s(test-sim)#",
55         1
56 };
57
58 static void print_vty(void *priv, const char *fmt, ...)
59 {
60         char buffer[1000];
61         struct vty *vty = priv;
62         va_list args;
63
64         va_start(args, fmt);
65         vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
66         buffer[sizeof(buffer) - 1] = '\0';
67         va_end(args);
68
69         if (buffer[0]) {
70                 if (buffer[strlen(buffer) - 1] == '\n') {
71                         buffer[strlen(buffer) - 1] = '\0';
72                         vty_out(vty, "%s%s", buffer, VTY_NEWLINE);
73                 } else
74                         vty_out(vty, "%s", buffer);
75         }
76 }
77
78 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
79 {
80         struct osmocom_ms *ms;
81
82         llist_for_each_entry(ms, &ms_list, entity) {
83                 if (!strcmp(ms->name, name))
84                         return ms;
85         }
86         vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
87
88         return NULL;
89 }
90
91 DEFUN(show_ms, show_ms_cmd, "show ms",
92         SHOW_STR "Display available MS entities\n")
93 {
94         struct osmocom_ms *ms;
95
96         llist_for_each_entry(ms, &ms_list, entity) {
97                 struct gsm_settings *set = &ms->settings;
98
99                 vty_out(vty, "MS NAME: %s%s", ms->name, VTY_NEWLINE);
100                 vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE);
101                 vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE);
102                 if (set->imei_random)
103                         vty_out(vty, " IMEI generation: random (%d trailing "
104                                 "digits)%s", set->imei_random, VTY_NEWLINE);
105                 else
106                         vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE);
107                 vty_out(vty, " network selection mode: %s%s",
108                         (set->plmn_mode == PLMN_MODE_AUTO)
109                                 ? "automatic" : "manual", VTY_NEWLINE);
110         }
111
112         return CMD_SUCCESS;
113 }
114
115 DEFUN(show_support, show_support_cmd, "show support [ms_name]",
116         SHOW_STR "Display information about MS support\n"
117         "Name of MS (see \"show ms\")")
118 {
119         struct osmocom_ms *ms;
120
121         if (argc) {
122                 ms = get_ms(argv[0], vty);
123                 if (!ms)
124                         return CMD_WARNING;
125                 gsm_support_dump(&ms->support, print_vty, vty);
126         } else {
127                 llist_for_each_entry(ms, &ms_list, entity) {
128                         gsm_support_dump(&ms->support, print_vty, vty);
129                         vty_out(vty, "%s", VTY_NEWLINE);
130                 }
131         }
132
133         return CMD_SUCCESS;
134 }
135
136 static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty)
137 {
138         struct gsm_trans *trans;
139
140         vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE);
141         if (ms->settings.plmn_mode == PLMN_MODE_AUTO)
142                 vty_out(vty, " automatic network selection: %s%s", 
143                         plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
144         else
145                 vty_out(vty, " manual network selection: %s%s", 
146                         plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
147         vty_out(vty, " cell selection: %s%s", 
148                 cs_state_names[ms->cellsel.state], VTY_NEWLINE);
149         vty_out(vty, " radio ressource layer: %s%s", 
150                 gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
151         vty_out(vty, " mobility management layer: %s", 
152                 gsm48_mm_state_names[ms->mmlayer.state]);
153         if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
154                 vty_out(vty, ", %s", 
155                         gsm48_mm_substate_names[ms->mmlayer.substate]);
156         vty_out(vty, "%s", VTY_NEWLINE);
157         llist_for_each_entry(trans, &ms->trans_list, entry) {
158                 vty_out(vty, " call control: %s%s", 
159                         gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
160         }
161 }
162
163 DEFUN(show_states, show_states_cmd, "show states [ms_name]",
164         SHOW_STR "Display current states of given MS\n"
165         "Name of MS (see \"show ms\")")
166 {
167         struct osmocom_ms *ms;
168
169         if (argc) {
170                 ms = get_ms(argv[0], vty);
171                 if (!ms)
172                         return CMD_WARNING;
173                 gsm_states_dump(ms, vty);
174         } else {
175                 llist_for_each_entry(ms, &ms_list, entity) {
176                         gsm_states_dump(ms, vty);
177                         vty_out(vty, "%s", VTY_NEWLINE);
178                 }
179         }
180
181         return CMD_SUCCESS;
182 }
183
184 DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]",
185         SHOW_STR "Display information about subscriber\n"
186         "Name of MS (see \"show ms\")")
187 {
188         struct osmocom_ms *ms;
189
190         if (argc) {
191                 ms = get_ms(argv[0], vty);
192                 if (!ms)
193                         return CMD_WARNING;
194                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
195         } else {
196                 llist_for_each_entry(ms, &ms_list, entity) {
197                         gsm_subscr_dump(&ms->subscr, print_vty, vty);
198                         vty_out(vty, "%s", VTY_NEWLINE);
199                 }
200         }
201
202         return CMD_SUCCESS;
203 }
204
205 DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
206         SHOW_STR "Display information about received cells\n"
207         "Name of MS (see \"show ms\")")
208 {
209         struct osmocom_ms *ms;
210
211         ms = get_ms(argv[0], vty);
212         if (!ms)
213                 return CMD_WARNING;
214
215         gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
216                 vty);
217
218         return CMD_SUCCESS;
219 }
220
221 DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>",
222         SHOW_STR "Display information about received cell\n"
223         "Name of MS (see \"show ms\")\nRadio frequency number")
224 {
225         struct osmocom_ms *ms;
226         int i;
227         struct gsm48_sysinfo *s;
228
229         ms = get_ms(argv[0], vty);
230         if (!ms)
231                 return CMD_WARNING;
232
233         i = atoi(argv[1]);
234         if (i < 0 || i > 1023) {
235                 vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s",
236                         argv[1], VTY_NEWLINE);
237                 return CMD_WARNING;
238         }
239         s = ms->cellsel.list[i].sysinfo;
240         if (!s) {
241                 vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s",
242                         argv[1], VTY_NEWLINE);
243                 return CMD_SUCCESS;
244         }
245
246         gsm48_sysinfo_dump(s, i, print_vty, vty);
247
248         return CMD_SUCCESS;
249 }
250
251 DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]",
252         SHOW_STR "Display information about band allocations\n"
253         "Name of MS (see \"show ms\")\nMobile Country Code\n"
254         "Mobile Network Code")
255 {
256         struct osmocom_ms *ms;
257         uint16_t mcc = 0, mnc = 0;
258
259         ms = get_ms(argv[0], vty);
260         if (!ms)
261                 return CMD_WARNING;
262
263         if (argc >= 3) {
264                 mcc = gsm_input_mcc((char *)argv[1]);
265                 mnc = gsm_input_mnc((char *)argv[2]);
266                 if (!mcc) {
267                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
268                         return CMD_WARNING;
269                 }
270                 if (!mnc) {
271                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
272                         return CMD_WARNING;
273                 }
274         }
275
276         gsm322_dump_ba_list(&ms->cellsel, mcc, mnc, print_vty, vty);
277
278         return CMD_SUCCESS;
279 }
280
281 DEFUN(show_forb_plmn, show_forb_plmn_cmd, "show forbidden plmn MS_NAME",
282         SHOW_STR "Display information about forbidden cells / networks\n"
283         "Display forbidden PLMNs\nName of MS (see \"show ms\")")
284 {
285         struct osmocom_ms *ms;
286
287         ms = get_ms(argv[0], vty);
288         if (!ms)
289                 return CMD_WARNING;
290
291         gsm_subscr_dump_forbidden_plmn(ms, print_vty, vty);
292
293         return CMD_SUCCESS;
294 }
295
296 DEFUN(show_forb_la, show_forb_la_cmd, "show forbidden location-area MS_NAME",
297         SHOW_STR "Display information about forbidden cells / networks\n"
298         "Display forbidden location areas\nName of MS (see \"show ms\")")
299 {
300         struct osmocom_ms *ms;
301
302         ms = get_ms(argv[0], vty);
303         if (!ms)
304                 return CMD_WARNING;
305
306         gsm322_dump_forbidden_la(ms, print_vty, vty);
307
308         return CMD_SUCCESS;
309 }
310
311 DEFUN(insert_test, insert_test_cmd, "insert testcard MS_NAME [mcc] [mnc]",
312         "Insert ...\nInsert test card\nName of MS (see \"show ms\")\n"
313         "Mobile Country Code\nMobile Network Code")
314 {
315         struct osmocom_ms *ms;
316         uint16_t mcc = 1, mnc = 1;
317
318         ms = get_ms(argv[0], vty);
319         if (!ms)
320                 return CMD_WARNING;
321
322         if (ms->subscr.sim_valid) {
323                 vty_out(vty, "Sim already presend, remove first!%s",
324                         VTY_NEWLINE);
325                 return CMD_WARNING;
326         }
327
328         if (argc >= 3) {
329                 mcc = gsm_input_mcc((char *)argv[1]);
330                 mnc = gsm_input_mnc((char *)argv[2]);
331                 if (!mcc) {
332                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
333                         return CMD_WARNING;
334                 }
335                 if (!mnc) {
336                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
337                         return CMD_WARNING;
338                 }
339         }
340
341         gsm_subscr_testcard(ms);
342
343         return CMD_SUCCESS;
344 }
345
346 DEFUN(remove_sim, remove_sim_cmd, "remove sim MS_NAME",
347         "Remove ...\nRemove SIM card\nName of MS (see \"show ms\")")
348 {
349         struct osmocom_ms *ms;
350
351         ms = get_ms(argv[0], vty);
352         if (!ms)
353                 return CMD_WARNING;
354
355         if (!ms->subscr.sim_valid) {
356                 vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
357                 return CMD_WARNING;
358         }
359
360         gsm_subscr_remove(ms);
361
362         return CMD_SUCCESS;
363 }
364
365 DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
366         "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
367         "Mobile Country Code\nMobile Network Code")
368 {
369         struct osmocom_ms *ms;
370         struct gsm322_plmn *plmn;
371         struct msgb *nmsg;
372         struct gsm322_msg *ngm;
373         struct gsm322_plmn_list *temp;
374         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
375                  mnc = gsm_input_mnc((char *)argv[2]);
376         int found = 0;
377
378         ms = get_ms(argv[0], vty);
379         if (!ms)
380                 return CMD_WARNING;
381         plmn = &ms->plmn;
382
383         if (!mcc) {
384                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
385                 return CMD_WARNING;
386         }
387         if (!mnc) {
388                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
389                 return CMD_WARNING;
390         }
391
392         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
393                 if (temp->mcc == mcc &&  temp->mnc == mnc)
394                         found = 1;
395         if (!found) {
396                 vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
397                 return CMD_WARNING;
398         }
399
400         nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOSE_PLMN);
401         if (!nmsg)
402                 return CMD_WARNING;
403         ngm = (struct gsm322_msg *) nmsg->data;
404         ngm->mcc = mcc;
405         ngm->mnc = mnc;
406         gsm322_plmn_sendmsg(ms, nmsg);
407
408         return CMD_SUCCESS;
409 }
410
411 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
412         "Make a call\nName of MS (see \"show ms\")\nPhone number to call\n"
413         "Make an emergency call\nAnswer an incomming call\nHangup a call\n"
414         "Hold current active call\n")
415 {
416         struct osmocom_ms *ms;
417
418         ms = get_ms(argv[0], vty);
419         if (!ms)
420                 return CMD_WARNING;
421
422         switch (argv[1][0]) {
423         case 'a':
424                 mncc_answer(ms);
425                 break;
426         case 'h':
427                 if (argv[1][1] == 'a')
428                         mncc_hangup(ms);
429                 else
430                         mncc_hold(ms);
431                 break;
432         default:
433                 mncc_call(ms, (char *)argv[1]);
434         }
435
436         return CMD_SUCCESS;
437 }
438
439 DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]",
440         "Make a call\nName of MS (see \"show ms\")\n"
441         "Retrieve call on hold\nNumber of call to retrieve")
442 {
443         struct osmocom_ms *ms;
444
445         ms = get_ms(argv[0], vty);
446         if (!ms)
447                 return CMD_WARNING;
448
449         mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
450
451         return CMD_SUCCESS;
452 }
453
454 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
455         "Network ...\nShow results of network search (again)\n"
456         "Name of MS (see \"show ms\")")
457 {
458         struct osmocom_ms *ms;
459         struct gsm322_plmn *plmn;
460         struct gsm322_plmn_list *temp;
461
462         ms = get_ms(argv[0], vty);
463         if (!ms)
464                 return CMD_WARNING;
465         plmn = &ms->plmn;
466
467         if (ms->settings.plmn_mode != PLMN_MODE_AUTO
468          && plmn->state != GSM322_M3_NOT_ON_PLMN) {
469                 vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
470                 return CMD_WARNING;
471         }
472
473         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
474                 vty_out(vty, " Network %s, %s (%s, %s)%s",
475                         gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
476                         gsm_get_mcc(temp->mcc),
477                         gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
478
479         return CMD_SUCCESS;
480 }
481
482 DEFUN(network_search, network_search_cmd, "network search MS_NAME",
483         "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
484 {
485         struct osmocom_ms *ms;
486         struct msgb *nmsg;
487
488         ms = get_ms(argv[0], vty);
489         if (!ms)
490                 return CMD_WARNING;
491
492         nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
493         if (!nmsg)
494                 return CMD_WARNING;
495         gsm322_plmn_sendmsg(ms, nmsg);
496
497         return CMD_SUCCESS;
498 }
499
500 /* per MS config */
501 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
502         "Select a mobile station to configure\nName of MS (see \"show ms\")")
503 {
504         struct osmocom_ms *ms;
505
506         ms = get_ms(argv[0], vty);
507         if (!ms)
508                 return CMD_WARNING;
509
510         vty->index = ms;
511         vty->node = MS_NODE;
512
513         return CMD_SUCCESS;
514 }
515
516 static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
517 {
518         struct gsm_settings *set = &ms->settings;
519
520         vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
521         switch(ms->settings.simtype) {
522                 case GSM_SIM_TYPE_NONE:
523                 vty_out(vty, " sim none%s", VTY_NEWLINE);
524                 break;
525                 case GSM_SIM_TYPE_SLOT:
526                 vty_out(vty, " sim slot%s", VTY_NEWLINE);
527                 break;
528                 case GSM_SIM_TYPE_TEST:
529                 vty_out(vty, " sim test%s", VTY_NEWLINE);
530                 break;
531         }
532         vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
533                         == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
534         vty_out(vty, " imei %s %s%s", set->imei,
535                 set->imeisv + strlen(set->imei), VTY_NEWLINE);
536         if (set->imei_random)
537                 vty_out(vty, " imei-random %d%s", set->imei_random,
538                         VTY_NEWLINE);
539         else
540                 vty_out(vty, " imei-fixed%s", VTY_NEWLINE);
541         vty_out(vty, " emergency-imsi %s%s", (ms->settings.emergency_imsi[0]) ?
542                 ms->settings.emergency_imsi : "none", VTY_NEWLINE);
543         vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE);
544         vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE);
545         vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE);
546         vty_out(vty, " test-sim%s", VTY_NEWLINE);
547         vty_out(vty, "  imsi %s%s", ms->settings.test_imsi, VTY_NEWLINE);
548         vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
549                 VTY_NEWLINE);
550         if (ms->settings.test_rplmn_valid)
551                 vty_out(vty, "  rplmn %s %s%s",
552                         gsm_print_mcc(ms->settings.test_rplmn_mcc),
553                         gsm_print_mnc(ms->settings.test_rplmn_mnc),
554                         VTY_NEWLINE);
555         else
556                 vty_out(vty, "  no rplmn%s", VTY_NEWLINE);
557         vty_out(vty, "  hplmn-search %s%s", (set->test_always) ? "everywhere"
558                         : "foreign-country", VTY_NEWLINE);
559         vty_out(vty, " exit%s", VTY_NEWLINE);
560         vty_out(vty, "exit%s", VTY_NEWLINE);
561         vty_out(vty, "!%s", VTY_NEWLINE);
562 }
563
564 static int config_write_ms(struct vty *vty)
565 {
566         struct osmocom_ms *ms;
567
568         llist_for_each_entry(ms, &ms_list, entity)
569                 config_write_ms_single(vty, ms);
570
571         return CMD_SUCCESS;
572 }
573
574 DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
575         "Set network selection mode\nAutomatic network selection\n"
576         "Manual network selection")
577 {
578         struct osmocom_ms *ms = vty->index;
579         struct msgb *nmsg;
580
581         if (!ms->plmn.state) {
582                 if (argv[0][0] == 'a')
583                         ms->settings.plmn_mode = PLMN_MODE_AUTO;
584                 else
585                         ms->settings.plmn_mode = PLMN_MODE_MANUAL;
586
587                 return CMD_SUCCESS;
588         }
589         if (argv[0][0] == 'a')
590                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
591         else
592                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
593         if (!nmsg)
594                 return CMD_WARNING;
595         gsm322_plmn_sendmsg(ms, nmsg);
596
597         return CMD_SUCCESS;
598 }
599
600 DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
601         "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
602         "Software version digit")
603 {
604         struct osmocom_ms *ms = vty->index;
605         char *error, *sv = "0";
606
607         if (argc >= 2)
608                 sv = (char *)argv[1];
609
610         error = gsm_check_imei(argv[0], sv);
611         if (error) {
612                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
613                 return CMD_WARNING;
614         }
615
616         strcpy(ms->settings.imei, argv[0]);
617         strcpy(ms->settings.imeisv, argv[0]);
618         strcpy(ms->settings.imeisv + 15, sv);
619
620         return CMD_SUCCESS;
621 }
622
623 DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
624         "Use fixed IMEI on every power on")
625 {
626         struct osmocom_ms *ms = vty->index;
627
628         ms->settings.imei_random = 0;
629
630         return CMD_SUCCESS;
631 }
632
633 DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
634         "Use random IMEI on every power on\n"
635         "Number of trailing digits to randomize")
636 {
637         struct osmocom_ms *ms = vty->index;
638
639         ms->settings.imei_random = atoi(argv[0]);
640
641         return CMD_SUCCESS;
642 }
643
644 DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi (none|IMSI)",
645         "Use IMSI for emergency calls\n"
646         "Use IMSI of SIM or IMEI for emergency calls\n15 digits IMSI")
647 {
648         struct osmocom_ms *ms = vty->index;
649         char *error;
650
651         if (argv[0][0] == 'n') {
652                 ms->settings.emergency_imsi[0] = '\0';
653                 return CMD_SUCCESS;
654         }
655
656         error = gsm_check_imsi(argv[0]);
657         if (error) {
658                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
659                 return CMD_WARNING;
660         }
661         strcpy(ms->settings.emergency_imsi, argv[0]);
662
663         return CMD_SUCCESS;
664 }
665
666 DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
667         NO_STR "Disallow waiting calls")
668 {
669         struct osmocom_ms *ms = vty->index;
670
671         ms->settings.cw = 0;
672
673         return CMD_SUCCESS;
674 }
675
676 DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
677         "Allow waiting calls")
678 {
679         struct osmocom_ms *ms = vty->index;
680
681         ms->settings.cw = 1;
682
683         return CMD_SUCCESS;
684 }
685
686 DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
687         "Force caller ID presentation")
688 {
689         struct osmocom_ms *ms = vty->index;
690
691         ms->settings.clip = 1;
692         ms->settings.clir = 0;
693
694         return CMD_SUCCESS;
695 }
696
697 DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
698         "Force caller ID restriction")
699 {
700         struct osmocom_ms *ms = vty->index;
701
702         ms->settings.clip = 0;
703         ms->settings.clir = 1;
704
705         return CMD_SUCCESS;
706 }
707
708 DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
709         NO_STR "Disable forcing of caller ID presentation")
710 {
711         struct osmocom_ms *ms = vty->index;
712
713         ms->settings.clip = 0;
714
715         return CMD_SUCCESS;
716 }
717
718 DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
719         NO_STR "Disable forcing of caller ID restriction")
720 {
721         struct osmocom_ms *ms = vty->index;
722
723         ms->settings.clir = 0;
724
725         return CMD_SUCCESS;
726 }
727
728 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|test)",
729         "Set sim card type when powering on\nNo sim interted\n"
730         "Test sim inserted")
731 {
732         struct osmocom_ms *ms = vty->index;
733
734         switch (argv[0][0]) {
735         case 'n':
736                 ms->settings.simtype = GSM_SIM_TYPE_NONE;
737                 break;
738         case 's':
739                 ms->settings.simtype = GSM_SIM_TYPE_SLOT;
740                 break;
741         case 't':
742                 ms->settings.simtype = GSM_SIM_TYPE_TEST;
743                 break;
744         }
745
746         return CMD_SUCCESS;
747 }
748
749 /* per MS config */
750 DEFUN(cfg_testsim, cfg_testsim_cmd, "test-sim",
751         "Configure test SIM emulation")
752 {
753         vty->node = TESTSIM_NODE;
754
755         return CMD_SUCCESS;
756 }
757
758 static int config_write_dummy(struct vty *vty)
759 {
760         return CMD_SUCCESS;
761 }
762
763 DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
764         "Set IMSI on test card\n15 digits IMSI")
765 {
766         struct osmocom_ms *ms = vty->index;
767         char *error = gsm_check_imsi(argv[0]);
768
769         if (error) {
770                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
771                 return CMD_WARNING;
772         }
773
774         strcpy(ms->settings.test_imsi, argv[0]);
775
776         return CMD_SUCCESS;
777 }
778
779 DEFUN(cfg_test_barr, cfg_test_barr_cmd, "barred-access",
780         "Allow access to barred cells")
781 {
782         struct osmocom_ms *ms = vty->index;
783
784         ms->settings.test_barr = 1;
785
786         return CMD_SUCCESS;
787 }
788
789 DEFUN(cfg_test_no_barr, cfg_test_no_barr_cmd, "no barred-access",
790         NO_STR "Deny access to barred cells")
791 {
792         struct osmocom_ms *ms = vty->index;
793
794         ms->settings.test_barr = 0;
795
796         return CMD_SUCCESS;
797 }
798
799 DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
800         NO_STR "Unset Registered PLMN")
801 {
802         struct osmocom_ms *ms = vty->index;
803
804         ms->settings.test_rplmn_valid = 0;
805
806         return CMD_SUCCESS;
807 }
808
809 DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC",
810         "Set Registered PLMN\nMobile Country Code\nMobile Network Code")
811 {
812         struct osmocom_ms *ms = vty->index;
813         uint16_t mcc = gsm_input_mcc((char *)argv[0]),
814                  mnc = gsm_input_mnc((char *)argv[1]);
815
816         if (!mcc) {
817                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
818                 return CMD_WARNING;
819         }
820         if (!mnc) {
821                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
822                 return CMD_WARNING;
823         }
824         ms->settings.test_rplmn_valid = 1;
825         ms->settings.test_rplmn_mcc = mcc;
826         ms->settings.test_rplmn_mnc = mnc;
827
828         return CMD_SUCCESS;
829 }
830
831 DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-country)",
832         "Set Home PLMN search mode\n"
833         "Search for HPLMN when on any other network\n"
834         "Search for HPLMN when in a different country")
835 {
836         struct osmocom_ms *ms = vty->index;
837
838         switch (argv[0][0]) {
839         case 'e':
840                 ms->settings.test_always = 1;
841                 break;
842         case 'f':
843                 ms->settings.test_always = 0;
844                 break;
845         }
846
847         return CMD_SUCCESS;
848 }
849
850 enum node_type ms_vty_go_parent(struct vty *vty)
851 {
852         switch (vty->node) {
853         case MS_NODE:
854                 vty->node = CONFIG_NODE;
855                 vty->index = NULL;
856                 break;
857         case TESTSIM_NODE:
858                 vty->node = MS_NODE;
859                 break;
860         default:
861                 vty->node = CONFIG_NODE;
862         }
863
864         return vty->node;
865 }
866
867 /* Down vty node level. */
868 gDEFUN(ournode_exit,
869        ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
870 {
871         switch (vty->node) {
872         case MS_NODE:
873                 vty->node = CONFIG_NODE;
874                 vty->index = NULL;
875                 break;
876         case TESTSIM_NODE:
877                 vty->node = MS_NODE;
878                 break;
879         default:
880                 break;
881         }
882         return CMD_SUCCESS;
883 }
884
885 /* End of configuration. */
886 gDEFUN(ournode_end,
887        ournode_end_cmd, "end", "End current mode and change to enable mode.")
888 {
889         switch (vty->node) {
890         case VIEW_NODE:
891         case ENABLE_NODE:
892                 /* Nothing to do. */
893                 break;
894         case CONFIG_NODE:
895         case VTY_NODE:
896         case MS_NODE:
897         case TESTSIM_NODE:
898                 vty_config_unlock(vty);
899                 vty->node = ENABLE_NODE;
900                 vty->index = NULL;
901                 vty->index_sub = NULL;
902                 break;
903         default:
904                 break;
905         }
906         return CMD_SUCCESS;
907 }
908
909 int ms_vty_init(void)
910 {
911         install_element_ve(&show_ms_cmd);
912         install_element_ve(&show_subscr_cmd);
913         install_element_ve(&show_support_cmd);
914         install_element_ve(&show_states_cmd);
915         install_element_ve(&show_cell_cmd);
916         install_element_ve(&show_cell_si_cmd);
917         install_element_ve(&show_ba_cmd);
918         install_element_ve(&show_forb_la_cmd);
919         install_element_ve(&show_forb_plmn_cmd);
920
921         install_element(ENABLE_NODE, &insert_test_cmd);
922         install_element(ENABLE_NODE, &remove_sim_cmd);
923         install_element(ENABLE_NODE, &network_search_cmd);
924         install_element(ENABLE_NODE, &network_show_cmd);
925         install_element(ENABLE_NODE, &network_select_cmd);
926         install_element(ENABLE_NODE, &call_cmd);
927         install_element(ENABLE_NODE, &call_retr_cmd);
928
929         install_element(CONFIG_NODE, &cfg_ms_cmd);
930         install_element(CONFIG_NODE, &ournode_end_cmd);
931         install_node(&ms_node, config_write_ms);
932         install_default(MS_NODE);
933         install_element(MS_NODE, &ournode_exit_cmd);
934         install_element(MS_NODE, &ournode_end_cmd);
935         install_element(MS_NODE, &cfg_ms_mode_cmd);
936         install_element(MS_NODE, &cfg_ms_imei_cmd);
937         install_element(MS_NODE, &cfg_ms_imei_fixed_cmd);
938         install_element(MS_NODE, &cfg_ms_imei_random_cmd);
939         install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
940         install_element(MS_NODE, &cfg_ms_cw_cmd);
941         install_element(MS_NODE, &cfg_ms_no_cw_cmd);
942         install_element(MS_NODE, &cfg_ms_clip_cmd);
943         install_element(MS_NODE, &cfg_ms_clir_cmd);
944         install_element(MS_NODE, &cfg_ms_no_clip_cmd);
945         install_element(MS_NODE, &cfg_ms_no_clir_cmd);
946         install_element(MS_NODE, &cfg_ms_sim_cmd);
947
948         install_element(MS_NODE, &cfg_testsim_cmd);
949         install_node(&testsim_node, config_write_dummy);
950         install_default(TESTSIM_NODE);
951         install_element(TESTSIM_NODE, &ournode_exit_cmd);
952         install_element(TESTSIM_NODE, &ournode_end_cmd);
953         install_element(TESTSIM_NODE, &cfg_test_imsi_cmd);
954         install_element(TESTSIM_NODE, &cfg_test_barr_cmd);
955         install_element(TESTSIM_NODE, &cfg_test_no_barr_cmd);
956         install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd);
957         install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd);
958         install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd);
959
960         return 0;
961 }
962
963 void vty_notify(struct osmocom_ms *ms, const char *fmt, ...)
964 {
965         struct telnet_connection *connection;
966         char buffer[1000];
967         va_list args;
968         struct vty *vty;
969
970         if (fmt) {
971                 va_start(args, fmt);
972                 vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
973                 buffer[sizeof(buffer) - 1] = '\0';
974                 va_end(args);
975
976                 if (!buffer[0])
977                         return;
978         }
979
980         llist_for_each_entry(connection, &active_connections, entry) {
981                 vty = connection->vty;
982                 if (!vty)
983                         continue;
984                 if (!fmt) {
985                         vty_out(vty, "%s%% (MS %s)%s", VTY_NEWLINE, ms->name,
986                                 VTY_NEWLINE);
987                         continue;
988                 }
989                 if (buffer[strlen(buffer) - 1] == '\n') {
990                         buffer[strlen(buffer) - 1] = '\0';
991                         vty_out(vty, "%% %s%s", buffer, VTY_NEWLINE);
992                         buffer[strlen(buffer)] = '\n';
993                 } else
994                         vty_out(vty, "%% %s", buffer);
995         }
996 }
997