[layer23] Notify user when config change requires restart to take effect
[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 int vty_reading = 0;
81
82 static void vty_restart(struct vty *vty)
83 {
84         if (vty_reading)
85                 return;
86         vty_out(vty, "You must restart for change take effect!%s", VTY_NEWLINE);
87 }
88
89 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
90 {
91         struct osmocom_ms *ms;
92
93         llist_for_each_entry(ms, &ms_list, entity) {
94                 if (!strcmp(ms->name, name))
95                         return ms;
96         }
97         vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
98
99         return NULL;
100 }
101
102 DEFUN(show_ms, show_ms_cmd, "show ms",
103         SHOW_STR "Display available MS entities\n")
104 {
105         struct osmocom_ms *ms;
106
107         llist_for_each_entry(ms, &ms_list, entity) {
108                 struct gsm_settings *set = &ms->settings;
109
110                 vty_out(vty, "MS NAME: %s%s", ms->name, VTY_NEWLINE);
111                 vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE);
112                 vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE);
113                 if (set->imei_random)
114                         vty_out(vty, " IMEI generation: random (%d trailing "
115                                 "digits)%s", set->imei_random, VTY_NEWLINE);
116                 else
117                         vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE);
118                 vty_out(vty, " network selection mode: %s%s",
119                         (set->plmn_mode == PLMN_MODE_AUTO)
120                                 ? "automatic" : "manual", VTY_NEWLINE);
121         }
122
123         return CMD_SUCCESS;
124 }
125
126 DEFUN(show_support, show_support_cmd, "show support [ms_name]",
127         SHOW_STR "Display information about MS support\n"
128         "Name of MS (see \"show ms\")")
129 {
130         struct osmocom_ms *ms;
131
132         if (argc) {
133                 ms = get_ms(argv[0], vty);
134                 if (!ms)
135                         return CMD_WARNING;
136                 gsm_support_dump(&ms->support, print_vty, vty);
137         } else {
138                 llist_for_each_entry(ms, &ms_list, entity) {
139                         gsm_support_dump(&ms->support, print_vty, vty);
140                         vty_out(vty, "%s", VTY_NEWLINE);
141                 }
142         }
143
144         return CMD_SUCCESS;
145 }
146
147 static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty)
148 {
149         struct gsm_trans *trans;
150
151         vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE);
152         if (ms->settings.plmn_mode == PLMN_MODE_AUTO)
153                 vty_out(vty, " automatic network selection: %s%s", 
154                         plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
155         else
156                 vty_out(vty, " manual network selection: %s%s", 
157                         plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
158         vty_out(vty, " cell selection: %s%s", 
159                 cs_state_names[ms->cellsel.state], VTY_NEWLINE);
160         vty_out(vty, " radio ressource layer: %s%s", 
161                 gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
162         vty_out(vty, " mobility management layer: %s", 
163                 gsm48_mm_state_names[ms->mmlayer.state]);
164         if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
165                 vty_out(vty, ", %s", 
166                         gsm48_mm_substate_names[ms->mmlayer.substate]);
167         vty_out(vty, "%s", VTY_NEWLINE);
168         llist_for_each_entry(trans, &ms->trans_list, entry) {
169                 vty_out(vty, " call control: %s%s", 
170                         gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
171         }
172 }
173
174 DEFUN(show_states, show_states_cmd, "show states [ms_name]",
175         SHOW_STR "Display current states of given MS\n"
176         "Name of MS (see \"show ms\")")
177 {
178         struct osmocom_ms *ms;
179
180         if (argc) {
181                 ms = get_ms(argv[0], vty);
182                 if (!ms)
183                         return CMD_WARNING;
184                 gsm_states_dump(ms, vty);
185         } else {
186                 llist_for_each_entry(ms, &ms_list, entity) {
187                         gsm_states_dump(ms, vty);
188                         vty_out(vty, "%s", VTY_NEWLINE);
189                 }
190         }
191
192         return CMD_SUCCESS;
193 }
194
195 DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]",
196         SHOW_STR "Display information about subscriber\n"
197         "Name of MS (see \"show ms\")")
198 {
199         struct osmocom_ms *ms;
200
201         if (argc) {
202                 ms = get_ms(argv[0], vty);
203                 if (!ms)
204                         return CMD_WARNING;
205                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
206         } else {
207                 llist_for_each_entry(ms, &ms_list, entity) {
208                         gsm_subscr_dump(&ms->subscr, print_vty, vty);
209                         vty_out(vty, "%s", VTY_NEWLINE);
210                 }
211         }
212
213         return CMD_SUCCESS;
214 }
215
216 DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
217         SHOW_STR "Display information about received cells\n"
218         "Name of MS (see \"show ms\")")
219 {
220         struct osmocom_ms *ms;
221
222         ms = get_ms(argv[0], vty);
223         if (!ms)
224                 return CMD_WARNING;
225
226         gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
227                 vty);
228
229         return CMD_SUCCESS;
230 }
231
232 DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>",
233         SHOW_STR "Display information about received cell\n"
234         "Name of MS (see \"show ms\")\nRadio frequency number")
235 {
236         struct osmocom_ms *ms;
237         int i;
238         struct gsm48_sysinfo *s;
239
240         ms = get_ms(argv[0], vty);
241         if (!ms)
242                 return CMD_WARNING;
243
244         i = atoi(argv[1]);
245         if (i < 0 || i > 1023) {
246                 vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s",
247                         argv[1], VTY_NEWLINE);
248                 return CMD_WARNING;
249         }
250         s = ms->cellsel.list[i].sysinfo;
251         if (!s) {
252                 vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s",
253                         argv[1], VTY_NEWLINE);
254                 return CMD_SUCCESS;
255         }
256
257         gsm48_sysinfo_dump(s, i, print_vty, vty);
258
259         return CMD_SUCCESS;
260 }
261
262 DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]",
263         SHOW_STR "Display information about band allocations\n"
264         "Name of MS (see \"show ms\")\nMobile Country Code\n"
265         "Mobile Network Code")
266 {
267         struct osmocom_ms *ms;
268         uint16_t mcc = 0, mnc = 0;
269
270         ms = get_ms(argv[0], vty);
271         if (!ms)
272                 return CMD_WARNING;
273
274         if (argc >= 3) {
275                 mcc = gsm_input_mcc((char *)argv[1]);
276                 mnc = gsm_input_mnc((char *)argv[2]);
277                 if (!mcc) {
278                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
279                         return CMD_WARNING;
280                 }
281                 if (!mnc) {
282                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
283                         return CMD_WARNING;
284                 }
285         }
286
287         gsm322_dump_ba_list(&ms->cellsel, mcc, mnc, print_vty, vty);
288
289         return CMD_SUCCESS;
290 }
291
292 DEFUN(show_forb_plmn, show_forb_plmn_cmd, "show forbidden plmn MS_NAME",
293         SHOW_STR "Display information about forbidden cells / networks\n"
294         "Display forbidden PLMNs\nName of MS (see \"show ms\")")
295 {
296         struct osmocom_ms *ms;
297
298         ms = get_ms(argv[0], vty);
299         if (!ms)
300                 return CMD_WARNING;
301
302         gsm_subscr_dump_forbidden_plmn(ms, print_vty, vty);
303
304         return CMD_SUCCESS;
305 }
306
307 DEFUN(show_forb_la, show_forb_la_cmd, "show forbidden location-area MS_NAME",
308         SHOW_STR "Display information about forbidden cells / networks\n"
309         "Display forbidden location areas\nName of MS (see \"show ms\")")
310 {
311         struct osmocom_ms *ms;
312
313         ms = get_ms(argv[0], vty);
314         if (!ms)
315                 return CMD_WARNING;
316
317         gsm322_dump_forbidden_la(ms, print_vty, vty);
318
319         return CMD_SUCCESS;
320 }
321
322 DEFUN(monitor_network, monitor_network_cmd, "monitor network MS_NAME",
323         "Monitor...\nMonitor network information\nName of MS (see \"show ms\")")
324 {
325         struct osmocom_ms *ms;
326
327         ms = get_ms(argv[0], vty);
328         if (!ms)
329                 return CMD_WARNING;
330
331         gsm48_rr_start_monitor(ms);
332
333         return CMD_SUCCESS;
334 }
335
336 DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME",
337         NO_STR "Monitor...\nDeactivate monitor of network information\n"
338         "Name of MS (see \"show ms\")")
339 {
340         struct osmocom_ms *ms;
341
342         ms = get_ms(argv[0], vty);
343         if (!ms)
344                 return CMD_WARNING;
345
346         gsm48_rr_stop_monitor(ms);
347
348         return CMD_SUCCESS;
349 }
350
351 DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]",
352         "SIM actions\nInsert test card\nName of MS (see \"show ms\")\n"
353         "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN")
354 {
355         struct osmocom_ms *ms;
356         uint16_t mcc = 0x001, mnc = 0x01f;
357
358         ms = get_ms(argv[0], vty);
359         if (!ms)
360                 return CMD_WARNING;
361
362         if (ms->subscr.sim_valid) {
363                 vty_out(vty, "SIM already presend, remove first!%s",
364                         VTY_NEWLINE);
365                 return CMD_WARNING;
366         }
367
368         if (argc >= 3) {
369                 mcc = gsm_input_mcc((char *)argv[1]);
370                 mnc = gsm_input_mnc((char *)argv[2]);
371                 if (!mcc) {
372                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
373                         return CMD_WARNING;
374                 }
375                 if (!mnc) {
376                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
377                         return CMD_WARNING;
378                 }
379         }
380
381         gsm_subscr_testcard(ms, mcc, mnc);
382
383         return CMD_SUCCESS;
384 }
385
386 DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
387         "SIM actions\nSelect SIM from reader\nName of MS (see \"show ms\")")
388 {
389         struct osmocom_ms *ms;
390
391         ms = get_ms(argv[0], vty);
392         if (!ms)
393                 return CMD_WARNING;
394
395         if (ms->subscr.sim_valid) {
396                 vty_out(vty, "SIM already presend, remove first!%s",
397                         VTY_NEWLINE);
398                 return CMD_WARNING;
399         }
400
401         gsm_subscr_simcard(ms);
402
403         return CMD_SUCCESS;
404 }
405
406 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
407         "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")")
408 {
409         struct osmocom_ms *ms;
410
411         ms = get_ms(argv[0], vty);
412         if (!ms)
413                 return CMD_WARNING;
414
415         if (!ms->subscr.sim_valid) {
416                 vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
417                 return CMD_WARNING;
418         }
419
420         gsm_subscr_remove(ms);
421
422         return CMD_SUCCESS;
423 }
424
425 DEFUN(sim_pin, sim_pin_cmd, "sim pin MS_NAME PIN",
426         "SIM actions\nEnter PIN for SIM card\nName of MS (see \"show ms\")\n"
427         "PIN number")
428 {
429         struct osmocom_ms *ms;
430
431         ms = get_ms(argv[0], vty);
432         if (!ms)
433                 return CMD_WARNING;
434
435         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
436                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
437                 return CMD_WARNING;
438         }
439
440         if (!ms->subscr.sim_pin_required) {
441                 vty_out(vty, "No PIN is required at this time!%s", VTY_NEWLINE);
442                 return CMD_WARNING;
443         }
444
445         gsm_subscr_sim_pin(ms, (char *)argv[1], "", 0);
446
447         return CMD_SUCCESS;
448 }
449
450 DEFUN(sim_disable_pin, sim_disable_pin_cmd, "sim disable-pin MS_NAME PIN",
451         "SIM actions\nDisable PIN of SIM card\nName of MS (see \"show ms\")\n"
452         "PIN number")
453 {
454         struct osmocom_ms *ms;
455
456         ms = get_ms(argv[0], vty);
457         if (!ms)
458                 return CMD_WARNING;
459
460         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
461                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
462                 return CMD_WARNING;
463         }
464
465         gsm_subscr_sim_pin(ms, (char *)argv[1], "", -1);
466
467         return CMD_SUCCESS;
468 }
469
470 DEFUN(sim_enable_pin, sim_enable_pin_cmd, "sim enable-pin MS_NAME PIN",
471         "SIM actions\nEnable PIN of SIM card\nName of MS (see \"show ms\")\n"
472         "PIN number")
473 {
474         struct osmocom_ms *ms;
475
476         ms = get_ms(argv[0], vty);
477         if (!ms)
478                 return CMD_WARNING;
479
480         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
481                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
482                 return CMD_WARNING;
483         }
484
485         gsm_subscr_sim_pin(ms, (char *)argv[1], "", 1);
486
487         return CMD_SUCCESS;
488 }
489
490 DEFUN(sim_change_pin, sim_change_pin_cmd, "sim change-pin MS_NAME OLD NEW",
491         "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
492         "Old PIN number\nNew PIN number")
493 {
494         struct osmocom_ms *ms;
495
496         ms = get_ms(argv[0], vty);
497         if (!ms)
498                 return CMD_WARNING;
499
500         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
501                 vty_out(vty, "Old PIN must be in range 4..8!%s", VTY_NEWLINE);
502                 return CMD_WARNING;
503         }
504         if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
505                 vty_out(vty, "New PIN must be in range 4..8!%s", VTY_NEWLINE);
506                 return CMD_WARNING;
507         }
508
509         gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 2);
510
511         return CMD_SUCCESS;
512 }
513
514 DEFUN(sim_unblock_pin, sim_unblock_pin_cmd, "sim unblock-pin MS_NAME PUC NEW",
515         "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
516         "Personal Unblock Key\nNew PIN number")
517 {
518         struct osmocom_ms *ms;
519
520         ms = get_ms(argv[0], vty);
521         if (!ms)
522                 return CMD_WARNING;
523
524         if (strlen(argv[1]) != 8) {
525                 vty_out(vty, "PUC must be 8 digits!%s", VTY_NEWLINE);
526                 return CMD_WARNING;
527         }
528         if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
529                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
530                 return CMD_WARNING;
531         }
532
533         gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 99);
534
535         return CMD_SUCCESS;
536 }
537
538 DEFUN(sim_lai, sim_lai_cmd, "sim lai MS_NAME MCC MNC LAC",
539         "SIM actions\nChange LAI of SIM card\nName of MS (see \"show ms\")\n"
540         "Mobile Country Code\nMobile Network Code\nLocation Area Code "
541         " (use 0000 to remove LAI)")
542 {
543         struct osmocom_ms *ms;
544         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
545                  mnc = gsm_input_mnc((char *)argv[2]),
546                  lac = strtoul(argv[3], NULL, 16);
547
548         ms = get_ms(argv[0], vty);
549         if (!ms)
550                 return CMD_WARNING;
551
552         if (!mcc) {
553                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
554                 return CMD_WARNING;
555         }
556         if (!mnc) {
557                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
558                 return CMD_WARNING;
559         }
560
561         ms->subscr.mcc = mcc;
562         ms->subscr.mnc = mnc;
563         ms->subscr.lac = lac;
564         ms->subscr.tmsi = 0xffffffff;
565
566         gsm_subscr_write_loci(ms);
567
568         return CMD_SUCCESS;
569 }
570
571 DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
572         "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
573         "Mobile Country Code\nMobile Network Code")
574 {
575         struct osmocom_ms *ms;
576         struct gsm322_plmn *plmn;
577         struct msgb *nmsg;
578         struct gsm322_msg *ngm;
579         struct gsm322_plmn_list *temp;
580         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
581                  mnc = gsm_input_mnc((char *)argv[2]);
582         int found = 0;
583
584         ms = get_ms(argv[0], vty);
585         if (!ms)
586                 return CMD_WARNING;
587         plmn = &ms->plmn;
588
589         if (!mcc) {
590                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
591                 return CMD_WARNING;
592         }
593         if (!mnc) {
594                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
595                 return CMD_WARNING;
596         }
597
598         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
599                 if (temp->mcc == mcc &&  temp->mnc == mnc)
600                         found = 1;
601         if (!found) {
602                 vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
603                 return CMD_WARNING;
604         }
605
606         nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
607         if (!nmsg)
608                 return CMD_WARNING;
609         ngm = (struct gsm322_msg *) nmsg->data;
610         ngm->mcc = mcc;
611         ngm->mnc = mnc;
612         gsm322_plmn_sendmsg(ms, nmsg);
613
614         return CMD_SUCCESS;
615 }
616
617 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
618         "Make a call\nName of MS (see \"show ms\")\nPhone number to call "
619         "(Use digits '0123456789*#abc', and '+' to dial international)\n"
620         "Make an emergency call\nAnswer an incomming call\nHangup a call\n"
621         "Hold current active call\n")
622 {
623         struct osmocom_ms *ms;
624         int i;
625
626         ms = get_ms(argv[0], vty);
627         if (!ms)
628                 return CMD_WARNING;
629
630         switch (argv[1][0]) {
631         case 'a':
632                 mncc_answer(ms);
633                 break;
634         case 'h':
635                 if (argv[1][1] == 'a')
636                         mncc_hangup(ms);
637                 else
638                         mncc_hold(ms);
639                 break;
640         default:
641                 for (i = 0; i < strlen(argv[1]); i++) {
642                         /* allow international notation with + */
643                         if (i == 0 && argv[1][i] == '+')
644                                 continue;
645                         if (!(argv[1][i] >= '0' && argv[1][i] <= '9')
646                          && argv[1][i] != '*'
647                          && argv[1][i] != '#'
648                          && !(argv[1][i] >= 'a' && argv[1][i] <= 'c')) {
649                                 vty_out(vty, "Invalid digit '%c'%s", argv[1][i],
650                                         VTY_NEWLINE);
651                                 return CMD_WARNING;
652                         }
653                 }
654                 mncc_call(ms, (char *)argv[1]);
655         }
656
657         return CMD_SUCCESS;
658 }
659
660 DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]",
661         "Make a call\nName of MS (see \"show ms\")\n"
662         "Retrieve call on hold\nNumber of call to retrieve")
663 {
664         struct osmocom_ms *ms;
665
666         ms = get_ms(argv[0], vty);
667         if (!ms)
668                 return CMD_WARNING;
669
670         mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
671
672         return CMD_SUCCESS;
673 }
674
675 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
676         "Network ...\nShow results of network search (again)\n"
677         "Name of MS (see \"show ms\")")
678 {
679         struct osmocom_ms *ms;
680         struct gsm322_plmn *plmn;
681         struct gsm322_plmn_list *temp;
682
683         ms = get_ms(argv[0], vty);
684         if (!ms)
685                 return CMD_WARNING;
686         plmn = &ms->plmn;
687
688         if (ms->settings.plmn_mode != PLMN_MODE_AUTO
689          && plmn->state != GSM322_M3_NOT_ON_PLMN) {
690                 vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
691                 return CMD_WARNING;
692         }
693
694         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
695                 vty_out(vty, " Network %s, %s (%s, %s)%s",
696                         gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
697                         gsm_get_mcc(temp->mcc),
698                         gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
699
700         return CMD_SUCCESS;
701 }
702
703 DEFUN(network_search, network_search_cmd, "network search MS_NAME",
704         "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
705 {
706         struct osmocom_ms *ms;
707         struct msgb *nmsg;
708
709         ms = get_ms(argv[0], vty);
710         if (!ms)
711                 return CMD_WARNING;
712
713         nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
714         if (!nmsg)
715                 return CMD_WARNING;
716         gsm322_plmn_sendmsg(ms, nmsg);
717
718         return CMD_SUCCESS;
719 }
720
721 DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable",
722         "GPS receiver")
723 {
724         if (gps_open()) {
725                 gps.enable = 1;
726                 vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE);
727                 return CMD_WARNING;
728         }
729         gps.enable = 1;
730
731         return CMD_SUCCESS;
732 }
733
734 DEFUN(cfg_no_gps_enable, cfg_no_gps_enable_cmd, "no gps enable",
735         NO_STR "Disable GPS receiver")
736 {
737         if (gps.enable)
738                 gps_close();
739         gps.enable = 0;
740
741         return CMD_SUCCESS;
742 }
743
744 DEFUN(cfg_gps_device, cfg_gps_device_cmd, "gps device DEVICE",
745         "GPS receiver\nSelect serial device\n"
746         "Full path of serial device including /dev/")
747 {
748         strncpy(gps.device, argv[0], sizeof(gps.device));
749         gps.device[sizeof(gps.device) - 1] = '\0';
750         if (gps.enable) {
751                 gps_close();
752                 if (gps_open()) {
753                         vty_out(vty, "Failed to open GPS device!%s",
754                                 VTY_NEWLINE);
755                         return CMD_WARNING;
756                 }
757         }
758
759         return CMD_SUCCESS;
760 }
761
762 DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate "
763         "(default|4800|""9600|19200|38400|57600|115200)",
764         "GPS receiver\nSelect baud rate\nDefault, don't modify\n\n\n\n\n\n")
765 {
766         if (argv[0][0] == 'd')
767                 gps.baud = 0;
768         else
769                 gps.baud = atoi(argv[0]);
770         if (gps.enable) {
771                 gps_close();
772                 if (gps_open()) {
773                         gps.enable = 0;
774                         vty_out(vty, "Failed to open GPS device!%s",
775                                 VTY_NEWLINE);
776                         return CMD_WARNING;
777                 }
778         }
779
780         return CMD_SUCCESS;
781 }
782
783 /* per MS config */
784 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
785         "Select a mobile station to configure\nName of MS (see \"show ms\")")
786 {
787         struct osmocom_ms *ms;
788
789         ms = get_ms(argv[0], vty);
790         if (!ms)
791                 return CMD_WARNING;
792
793         vty->index = ms;
794         vty->node = MS_NODE;
795
796         return CMD_SUCCESS;
797 }
798
799 static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
800 {
801         struct gsm_support *sup = &ms->support;
802         struct gsm_settings *set = &ms->settings;
803
804         vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
805         switch(set->sim_type) {
806                 case GSM_SIM_TYPE_NONE:
807                 vty_out(vty, " sim none%s", VTY_NEWLINE);
808                 break;
809                 case GSM_SIM_TYPE_READER:
810                 vty_out(vty, " sim reader%s", VTY_NEWLINE);
811                 break;
812                 case GSM_SIM_TYPE_TEST:
813                 vty_out(vty, " sim test%s", VTY_NEWLINE);
814                 break;
815         }
816         vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
817                         == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
818         vty_out(vty, " imei %s %s%s", set->imei,
819                 set->imeisv + strlen(set->imei), VTY_NEWLINE);
820         if (set->imei_random)
821                 vty_out(vty, " imei-random %d%s", set->imei_random,
822                         VTY_NEWLINE);
823         else
824                 vty_out(vty, " imei-fixed%s", VTY_NEWLINE);
825         if (set->emergency_imsi[0])
826                 vty_out(vty, " emergency-imsi %s%s", set->emergency_imsi,
827                         VTY_NEWLINE);
828         else
829                 vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE);
830         vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE);
831         vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE);
832         vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE);
833         vty_out(vty, " test-sim%s", VTY_NEWLINE);
834         vty_out(vty, "  imsi %s%s", set->test_imsi, VTY_NEWLINE);
835         switch (set->test_ki_type) {
836         case GSM_SIM_KEY_XOR:
837                 vty_out(vty, "  ki xor %s%s", hexdump(set->test_ki, 12),
838                         VTY_NEWLINE);
839                 break;
840         case GSM_SIM_KEY_COMP128:
841                 vty_out(vty, "  ki comp128 %s%s", hexdump(set->test_ki, 16),
842                         VTY_NEWLINE);
843                 break;
844         }
845         vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
846                 VTY_NEWLINE);
847         if (set->test_rplmn_valid)
848                 vty_out(vty, "  rplmn %s %s%s",
849                         gsm_print_mcc(set->test_rplmn_mcc),
850                         gsm_print_mnc(set->test_rplmn_mnc),
851                         VTY_NEWLINE);
852         else
853                 vty_out(vty, "  no rplmn%s", VTY_NEWLINE);
854         vty_out(vty, "  hplmn-search %s%s", (set->test_always) ? "everywhere"
855                         : "foreign-country", VTY_NEWLINE);
856         vty_out(vty, " exit%s", VTY_NEWLINE);
857         vty_out(vty, " min-rxlev %d%s", set->min_rxlev_db, VTY_NEWLINE);
858         if (set->alter_tx_power)
859                 if (set->alter_tx_power_value)
860                         vty_out(vty, " tx-power %d%s",
861                                 set->alter_tx_power_value, VTY_NEWLINE);
862                 else
863                         vty_out(vty, " tx-power full%s", VTY_NEWLINE);
864         else
865                 vty_out(vty, " tx-power auto%s", VTY_NEWLINE);
866         if (set->alter_delay)
867                 vty_out(vty, " simulated-delay %d%s", set->alter_delay,
868                         VTY_NEWLINE);
869         else
870                 vty_out(vty, " no simulated-delay%s", VTY_NEWLINE);
871         if (set->stick)
872                 vty_out(vty, " stick %d%s", set->stick_arfcn,
873                         VTY_NEWLINE);
874         else
875                 vty_out(vty, " no stick%s", VTY_NEWLINE);
876         if (set->no_lupd)
877                 vty_out(vty, " no location-updating%s", VTY_NEWLINE);
878         else
879                 vty_out(vty, " location-updating%s", VTY_NEWLINE);
880         if (sup->full_v1 || sup->full_v2 || sup->full_v3) {
881                 /* mandatory anyway */
882                 vty_out(vty, " codec full-speed%s%s",
883                         (!set->half_prefer) ? " prefer" : "",
884                         VTY_NEWLINE);
885         }
886         if (sup->half_v1 || sup->half_v3) {
887                 if (set->half)
888                         vty_out(vty, " codec half-speed%s%s",
889                                 (set->half_prefer) ? " prefer" : "",
890                                 VTY_NEWLINE);
891                 else
892                         vty_out(vty, " no codec half-speed%s", VTY_NEWLINE);
893         }
894         vty_out(vty, "exit%s", VTY_NEWLINE);
895         vty_out(vty, "!%s", VTY_NEWLINE);
896 }
897
898 static int config_write_ms(struct vty *vty)
899 {
900         struct osmocom_ms *ms;
901
902         vty_out(vty, "gps device %s%s", gps.device, VTY_NEWLINE);
903         if (gps.baud)
904                 vty_out(vty, "gps baudrate %d%s", gps.baud, VTY_NEWLINE);
905         else
906                 vty_out(vty, "gps baudrate default%s", VTY_NEWLINE);
907         vty_out(vty, "%sgps enable%s", (gps.enable) ? "" : "no ", VTY_NEWLINE);
908         vty_out(vty, "!%s", VTY_NEWLINE);
909
910         llist_for_each_entry(ms, &ms_list, entity)
911                 config_write_ms_single(vty, ms);
912
913         return CMD_SUCCESS;
914 }
915
916 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)",
917         "Set SIM card type when powering on\nNo SIM interted\n"
918         "Use SIM from reader\nTest SIM inserted")
919 {
920         struct osmocom_ms *ms = vty->index;
921
922         switch (argv[0][0]) {
923         case 'n':
924                 ms->settings.sim_type = GSM_SIM_TYPE_NONE;
925                 break;
926         case 'r':
927                 ms->settings.sim_type = GSM_SIM_TYPE_READER;
928                 break;
929         case 't':
930                 ms->settings.sim_type = GSM_SIM_TYPE_TEST;
931                 break;
932         default:
933                 vty_out(vty, "unknown SIM type%s", VTY_NEWLINE);
934                 return CMD_WARNING;
935         }
936
937         vty_restart(vty);
938         return CMD_SUCCESS;
939 }
940
941 DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
942         "Set network selection mode\nAutomatic network selection\n"
943         "Manual network selection")
944 {
945         struct osmocom_ms *ms = vty->index;
946         struct msgb *nmsg;
947
948         if (!ms->plmn.state) {
949                 if (argv[0][0] == 'a')
950                         ms->settings.plmn_mode = PLMN_MODE_AUTO;
951                 else
952                         ms->settings.plmn_mode = PLMN_MODE_MANUAL;
953
954                 return CMD_SUCCESS;
955         }
956         if (argv[0][0] == 'a')
957                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
958         else
959                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
960         if (!nmsg)
961                 return CMD_WARNING;
962         gsm322_plmn_sendmsg(ms, nmsg);
963
964         return CMD_SUCCESS;
965 }
966
967 DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
968         "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
969         "Software version digit")
970 {
971         struct osmocom_ms *ms = vty->index;
972         char *error, *sv = "0";
973
974         if (argc >= 2)
975                 sv = (char *)argv[1];
976
977         error = gsm_check_imei(argv[0], sv);
978         if (error) {
979                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
980                 return CMD_WARNING;
981         }
982
983         strcpy(ms->settings.imei, argv[0]);
984         strcpy(ms->settings.imeisv, argv[0]);
985         strcpy(ms->settings.imeisv + 15, sv);
986
987         return CMD_SUCCESS;
988 }
989
990 DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
991         "Use fixed IMEI on every power on")
992 {
993         struct osmocom_ms *ms = vty->index;
994
995         ms->settings.imei_random = 0;
996
997         vty_restart(vty);
998         return CMD_SUCCESS;
999 }
1000
1001 DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
1002         "Use random IMEI on every power on\n"
1003         "Number of trailing digits to randomize")
1004 {
1005         struct osmocom_ms *ms = vty->index;
1006
1007         ms->settings.imei_random = atoi(argv[0]);
1008
1009         vty_restart(vty);
1010         return CMD_SUCCESS;
1011 }
1012
1013 DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi IMSI",
1014         "Use special IMSI for emergency calls\n15 digits IMSI")
1015 {
1016         struct osmocom_ms *ms = vty->index;
1017         char *error;
1018
1019         error = gsm_check_imsi(argv[0]);
1020         if (error) {
1021                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1022                 return CMD_WARNING;
1023         }
1024         strcpy(ms->settings.emergency_imsi, argv[0]);
1025
1026         return CMD_SUCCESS;
1027 }
1028
1029 DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
1030         NO_STR "Use IMSI of SIM or IMEI for emergency calls")
1031 {
1032         struct osmocom_ms *ms = vty->index;
1033
1034         ms->settings.emergency_imsi[0] = '\0';
1035
1036         return CMD_SUCCESS;
1037 }
1038
1039 DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
1040         NO_STR "Disallow waiting calls")
1041 {
1042         struct osmocom_ms *ms = vty->index;
1043
1044         ms->settings.cw = 0;
1045
1046         return CMD_SUCCESS;
1047 }
1048
1049 DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
1050         "Allow waiting calls")
1051 {
1052         struct osmocom_ms *ms = vty->index;
1053
1054         ms->settings.cw = 1;
1055
1056         return CMD_SUCCESS;
1057 }
1058
1059 DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
1060         "Force caller ID presentation")
1061 {
1062         struct osmocom_ms *ms = vty->index;
1063
1064         ms->settings.clip = 1;
1065         ms->settings.clir = 0;
1066
1067         return CMD_SUCCESS;
1068 }
1069
1070 DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
1071         "Force caller ID restriction")
1072 {
1073         struct osmocom_ms *ms = vty->index;
1074
1075         ms->settings.clip = 0;
1076         ms->settings.clir = 1;
1077
1078         return CMD_SUCCESS;
1079 }
1080
1081 DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
1082         NO_STR "Disable forcing of caller ID presentation")
1083 {
1084         struct osmocom_ms *ms = vty->index;
1085
1086         ms->settings.clip = 0;
1087
1088         return CMD_SUCCESS;
1089 }
1090
1091 DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
1092         NO_STR "Disable forcing of caller ID restriction")
1093 {
1094         struct osmocom_ms *ms = vty->index;
1095
1096         ms->settings.clir = 0;
1097
1098         return CMD_SUCCESS;
1099 }
1100
1101 DEFUN(cfg_ms_min_rxlev, cfg_ms_min_rxlev_cmd, "min-rxlev <-110--47>",
1102         "Set the minimum receive level to select a cell\n"
1103         "Minimum receive level from -110 dBm to -47 dBm")
1104 {
1105         struct osmocom_ms *ms = vty->index;
1106
1107         ms->settings.min_rxlev_db = atoi(argv[0]);
1108
1109         return CMD_SUCCESS;
1110 }
1111
1112 DEFUN(cfg_ms_tx_power, cfg_ms_tx_power_cmd, "tx-power (auto|full)",
1113         "Set the way to choose transmit power\nControlled by BTS\n"
1114         "Always full power\nFixed GSM power value if supported")
1115 {
1116         struct osmocom_ms *ms = vty->index;
1117
1118         switch (argv[0][0]) {
1119         case 'a':
1120                 ms->settings.alter_tx_power = 0;
1121                 break;
1122         case 'f':
1123                 ms->settings.alter_tx_power = 1;
1124                 ms->settings.alter_tx_power_value = 0;
1125                 break;
1126         }
1127
1128         return CMD_SUCCESS;
1129 }
1130
1131 DEFUN(cfg_ms_tx_power_val, cfg_ms_tx_power_val_cmd, "tx-power <0-31>",
1132         "Set the way to choose transmit power\n"
1133         "Fixed GSM power value if supported")
1134 {
1135         struct osmocom_ms *ms = vty->index;
1136
1137         ms->settings.alter_tx_power = 1;
1138         ms->settings.alter_tx_power_value = atoi(argv[0]);
1139
1140         return CMD_SUCCESS;
1141 }
1142
1143 DEFUN(cfg_ms_sim_delay, cfg_ms_sim_delay_cmd, "simulated-delay <-128-127>",
1144         "Simulate a lower or higher distance from the BTS\n"
1145         "Delay in half bits (distance in 553.85 meter steps)")
1146 {
1147         struct osmocom_ms *ms = vty->index;
1148
1149         ms->settings.alter_delay = atoi(argv[0]);
1150         gsm48_rr_alter_delay(ms);
1151
1152         return CMD_SUCCESS;
1153 }
1154
1155 DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
1156         NO_STR "Do not simulate a lower or higher distance from the BTS")
1157 {
1158         struct osmocom_ms *ms = vty->index;
1159
1160         ms->settings.alter_delay = 0;
1161         gsm48_rr_alter_delay(ms);
1162
1163         return CMD_SUCCESS;
1164 }
1165
1166 DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023>",
1167         "Stick to the given cell\nARFCN of the cell to stick to")
1168 {
1169         struct osmocom_ms *ms = vty->index;
1170
1171         ms->settings.stick = 1;
1172         ms->settings.stick_arfcn = atoi(argv[0]);
1173
1174         return CMD_SUCCESS;
1175 }
1176
1177 DEFUN(cfg_ms_no_stick, cfg_ms_no_stick_cmd, "no stick",
1178         NO_STR "Do not stick to any cell")
1179 {
1180         struct osmocom_ms *ms = vty->index;
1181
1182         ms->settings.stick = 0;
1183
1184         return CMD_SUCCESS;
1185 }
1186
1187 DEFUN(cfg_ms_lupd, cfg_ms_lupd_cmd, "location-updating",
1188         "Allow location updating")
1189 {
1190         struct osmocom_ms *ms = vty->index;
1191
1192         ms->settings.no_lupd = 0;
1193
1194         return CMD_SUCCESS;
1195 }
1196
1197 DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating",
1198         NO_STR "Do not allow location updating")
1199 {
1200         struct osmocom_ms *ms = vty->index;
1201
1202         ms->settings.no_lupd = 1;
1203
1204         return CMD_SUCCESS;
1205 }
1206
1207 DEFUN(cfg_codec_full, cfg_ms_codec_full_cmd, "codec full-speed",
1208         "Enable codec\nFull speed speech codec")
1209 {
1210         struct osmocom_ms *ms = vty->index;
1211         struct gsm_support *sup = &ms->support;
1212
1213         if (!sup->full_v1 && !sup->full_v2 && !sup->full_v3) {
1214                 vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
1215                 return CMD_WARNING;
1216         }
1217
1218         return CMD_SUCCESS;
1219 }
1220
1221 DEFUN(cfg_codec_full_pref, cfg_ms_codec_full_pref_cmd, "codec full-speed "
1222         "prefer",
1223         "Enable codec\nFull speed speech codec\nPrefer this codec")
1224 {
1225         struct osmocom_ms *ms = vty->index;
1226         struct gsm_support *sup = &ms->support;
1227
1228         if (!sup->full_v1 && !sup->full_v2 && !sup->full_v3) {
1229                 vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
1230                 return CMD_WARNING;
1231         }
1232
1233         ms->settings.half_prefer = 0;
1234
1235         return CMD_SUCCESS;
1236 }
1237
1238 DEFUN(cfg_codec_half, cfg_ms_codec_half_cmd, "codec half-speed",
1239         "Enable codec\nHalf speed speech codec")
1240 {
1241         struct osmocom_ms *ms = vty->index;
1242         struct gsm_support *sup = &ms->support;
1243
1244         if (!sup->half_v1 && !sup->half_v3) {
1245                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1246                 return CMD_WARNING;
1247         }
1248
1249         ms->settings.half = 1;
1250
1251         return CMD_SUCCESS;
1252 }
1253
1254 DEFUN(cfg_codec_half_pref, cfg_ms_codec_half_pref_cmd, "codec half-speed "
1255         "prefer",
1256         "Enable codec\nHalf speed speech codec\nPrefer this codec")
1257 {
1258         struct osmocom_ms *ms = vty->index;
1259         struct gsm_support *sup = &ms->support;
1260
1261         if (!sup->half_v1 && !sup->half_v3) {
1262                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1263                 return CMD_WARNING;
1264         }
1265
1266         ms->settings.half = 1;
1267         ms->settings.half_prefer = 1;
1268
1269         return CMD_SUCCESS;
1270 }
1271
1272 DEFUN(cfg_no_codec_half, cfg_ms_no_codec_half_cmd, "no codec half-speed",
1273         NO_STR "Disable codec\nHalf speed speech codec")
1274 {
1275         struct osmocom_ms *ms = vty->index;
1276         struct gsm_support *sup = &ms->support;
1277
1278         if (!sup->half_v1 && !sup->half_v3) {
1279                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1280                 return CMD_WARNING;
1281         }
1282
1283         ms->settings.half = 0;
1284         ms->settings.half_prefer = 0;
1285
1286         return CMD_SUCCESS;
1287 }
1288
1289 /* per testsim config */
1290 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
1291         "Configure test SIM emulation")
1292 {
1293         vty->node = TESTSIM_NODE;
1294
1295         return CMD_SUCCESS;
1296 }
1297
1298 static int config_write_dummy(struct vty *vty)
1299 {
1300         return CMD_SUCCESS;
1301 }
1302
1303 DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
1304         "Set IMSI on test card\n15 digits IMSI")
1305 {
1306         struct osmocom_ms *ms = vty->index;
1307         char *error = gsm_check_imsi(argv[0]);
1308
1309         if (error) {
1310                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1311                 return CMD_WARNING;
1312         }
1313
1314         strcpy(ms->settings.test_imsi, argv[0]);
1315
1316         vty_restart(vty);
1317         return CMD_SUCCESS;
1318 }
1319
1320 #define HEX_STR "\nByte as two digits hexadecimal"
1321 DEFUN(cfg_test_ki_xor, cfg_test_ki_xor_cmd, "ki xor HEX HEX HEX HEX HEX HEX "
1322         "HEX HEX HEX HEX HEX HEX",
1323         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1324         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR)
1325 {
1326         struct osmocom_ms *ms = vty->index;
1327         struct gsm_settings *set = &ms->settings;
1328         uint8_t ki[12];
1329         const char *p;
1330         int i;
1331
1332         for (i = 0; i < 12; i++) {
1333                 p = argv[i];
1334                 if (!strncmp(p, "0x", 2))
1335                         p += 2;
1336                 if (strlen(p) != 2) {
1337                         vty_out(vty, "Expecting two digits hex value (with or "
1338                                 "without 0x in front)%s", VTY_NEWLINE);
1339                         return CMD_WARNING;
1340                 }
1341                 ki[i] = strtoul(p, NULL, 16);
1342         }
1343
1344         set->test_ki_type = GSM_SIM_KEY_XOR;
1345         memcpy(set->test_ki, ki, 12);
1346         return CMD_SUCCESS;
1347 }
1348
1349 DEFUN(cfg_test_ki_comp128, cfg_test_ki_comp128_cmd, "ki comp128 HEX HEX HEX "
1350         "HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX",
1351         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1352         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR
1353         HEX_STR HEX_STR HEX_STR HEX_STR)
1354 {
1355         struct osmocom_ms *ms = vty->index;
1356         struct gsm_settings *set = &ms->settings;
1357         uint8_t ki[16];
1358         const char *p;
1359         int i;
1360
1361         for (i = 0; i < 16; i++) {
1362                 p = argv[i];
1363                 if (!strncmp(p, "0x", 2))
1364                         p += 2;
1365                 if (strlen(p) != 2) {
1366                         vty_out(vty, "Expecting two digits hex value (with or "
1367                                 "without 0x in front)%s", VTY_NEWLINE);
1368                         return CMD_WARNING;
1369                 }
1370                 ki[i] = strtoul(p, NULL, 16);
1371         }
1372
1373         set->test_ki_type = GSM_SIM_KEY_COMP128;
1374         memcpy(set->test_ki, ki, 16);
1375         return CMD_SUCCESS;
1376 }
1377
1378 DEFUN(cfg_test_barr, cfg_test_barr_cmd, "barred-access",
1379         "Allow access to barred cells")
1380 {
1381         struct osmocom_ms *ms = vty->index;
1382
1383         ms->settings.test_barr = 1;
1384
1385         return CMD_SUCCESS;
1386 }
1387
1388 DEFUN(cfg_test_no_barr, cfg_test_no_barr_cmd, "no barred-access",
1389         NO_STR "Deny access to barred cells")
1390 {
1391         struct osmocom_ms *ms = vty->index;
1392
1393         ms->settings.test_barr = 0;
1394
1395         return CMD_SUCCESS;
1396 }
1397
1398 DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
1399         NO_STR "Unset Registered PLMN")
1400 {
1401         struct osmocom_ms *ms = vty->index;
1402
1403         ms->settings.test_rplmn_valid = 0;
1404
1405         vty_restart(vty);
1406         return CMD_SUCCESS;
1407 }
1408
1409 DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC",
1410         "Set Registered PLMN\nMobile Country Code\nMobile Network Code")
1411 {
1412         struct osmocom_ms *ms = vty->index;
1413         uint16_t mcc = gsm_input_mcc((char *)argv[0]),
1414                  mnc = gsm_input_mnc((char *)argv[1]);
1415
1416         if (!mcc) {
1417                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
1418                 return CMD_WARNING;
1419         }
1420         if (!mnc) {
1421                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
1422                 return CMD_WARNING;
1423         }
1424         ms->settings.test_rplmn_valid = 1;
1425         ms->settings.test_rplmn_mcc = mcc;
1426         ms->settings.test_rplmn_mnc = mnc;
1427
1428         vty_restart(vty);
1429         return CMD_SUCCESS;
1430 }
1431
1432 DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-country)",
1433         "Set Home PLMN search mode\n"
1434         "Search for HPLMN when on any other network\n"
1435         "Search for HPLMN when in a different country")
1436 {
1437         struct osmocom_ms *ms = vty->index;
1438
1439         switch (argv[0][0]) {
1440         case 'e':
1441                 ms->settings.test_always = 1;
1442                 break;
1443         case 'f':
1444                 ms->settings.test_always = 0;
1445                 break;
1446         }
1447
1448         vty_restart(vty);
1449         return CMD_SUCCESS;
1450 }
1451
1452 enum node_type ms_vty_go_parent(struct vty *vty)
1453 {
1454         switch (vty->node) {
1455         case MS_NODE:
1456                 vty->node = CONFIG_NODE;
1457                 vty->index = NULL;
1458                 break;
1459         case TESTSIM_NODE:
1460                 vty->node = MS_NODE;
1461                 break;
1462         default:
1463                 vty->node = CONFIG_NODE;
1464         }
1465
1466         return vty->node;
1467 }
1468
1469 /* Down vty node level. */
1470 gDEFUN(ournode_exit,
1471        ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
1472 {
1473         switch (vty->node) {
1474         case MS_NODE:
1475                 vty->node = CONFIG_NODE;
1476                 vty->index = NULL;
1477                 break;
1478         case TESTSIM_NODE:
1479                 vty->node = MS_NODE;
1480                 break;
1481         default:
1482                 break;
1483         }
1484         return CMD_SUCCESS;
1485 }
1486
1487 /* End of configuration. */
1488 gDEFUN(ournode_end,
1489        ournode_end_cmd, "end", "End current mode and change to enable mode.")
1490 {
1491         switch (vty->node) {
1492         case VIEW_NODE:
1493         case ENABLE_NODE:
1494                 /* Nothing to do. */
1495                 break;
1496         case CONFIG_NODE:
1497         case VTY_NODE:
1498         case MS_NODE:
1499         case TESTSIM_NODE:
1500                 vty_config_unlock(vty);
1501                 vty->node = ENABLE_NODE;
1502                 vty->index = NULL;
1503                 vty->index_sub = NULL;
1504                 break;
1505         default:
1506                 break;
1507         }
1508         return CMD_SUCCESS;
1509 }
1510
1511 int ms_vty_init(void)
1512 {
1513         install_element_ve(&show_ms_cmd);
1514         install_element_ve(&show_subscr_cmd);
1515         install_element_ve(&show_support_cmd);
1516         install_element_ve(&show_states_cmd);
1517         install_element_ve(&show_cell_cmd);
1518         install_element_ve(&show_cell_si_cmd);
1519         install_element_ve(&show_ba_cmd);
1520         install_element_ve(&show_forb_la_cmd);
1521         install_element_ve(&show_forb_plmn_cmd);
1522         install_element_ve(&monitor_network_cmd);
1523         install_element_ve(&no_monitor_network_cmd);
1524
1525         install_element(ENABLE_NODE, &sim_test_cmd);
1526         install_element(ENABLE_NODE, &sim_reader_cmd);
1527         install_element(ENABLE_NODE, &sim_remove_cmd);
1528         install_element(ENABLE_NODE, &sim_pin_cmd);
1529         install_element(ENABLE_NODE, &sim_disable_pin_cmd);
1530         install_element(ENABLE_NODE, &sim_enable_pin_cmd);
1531         install_element(ENABLE_NODE, &sim_change_pin_cmd);
1532         install_element(ENABLE_NODE, &sim_unblock_pin_cmd);
1533         install_element(ENABLE_NODE, &sim_lai_cmd);
1534         install_element(ENABLE_NODE, &network_search_cmd);
1535         install_element(ENABLE_NODE, &network_show_cmd);
1536         install_element(ENABLE_NODE, &network_select_cmd);
1537         install_element(ENABLE_NODE, &call_cmd);
1538         install_element(ENABLE_NODE, &call_retr_cmd);
1539
1540         install_element(CONFIG_NODE, &cfg_gps_device_cmd);
1541         install_element(CONFIG_NODE, &cfg_gps_baud_cmd);
1542         install_element(CONFIG_NODE, &cfg_gps_enable_cmd);
1543         install_element(CONFIG_NODE, &cfg_no_gps_enable_cmd);
1544
1545         install_element(CONFIG_NODE, &cfg_ms_cmd);
1546         install_element(CONFIG_NODE, &ournode_end_cmd);
1547         install_node(&ms_node, config_write_ms);
1548         install_default(MS_NODE);
1549         install_element(MS_NODE, &ournode_exit_cmd);
1550         install_element(MS_NODE, &ournode_end_cmd);
1551         install_element(MS_NODE, &cfg_ms_sim_cmd);
1552         install_element(MS_NODE, &cfg_ms_mode_cmd);
1553         install_element(MS_NODE, &cfg_ms_imei_cmd);
1554         install_element(MS_NODE, &cfg_ms_imei_fixed_cmd);
1555         install_element(MS_NODE, &cfg_ms_imei_random_cmd);
1556         install_element(MS_NODE, &cfg_ms_no_emerg_imsi_cmd);
1557         install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
1558         install_element(MS_NODE, &cfg_ms_cw_cmd);
1559         install_element(MS_NODE, &cfg_ms_no_cw_cmd);
1560         install_element(MS_NODE, &cfg_ms_clip_cmd);
1561         install_element(MS_NODE, &cfg_ms_clir_cmd);
1562         install_element(MS_NODE, &cfg_ms_no_clip_cmd);
1563         install_element(MS_NODE, &cfg_ms_no_clir_cmd);
1564         install_element(MS_NODE, &cfg_ms_testsim_cmd);
1565         install_element(MS_NODE, &cfg_ms_min_rxlev_cmd);
1566         install_element(MS_NODE, &cfg_ms_tx_power_cmd);
1567         install_element(MS_NODE, &cfg_ms_tx_power_val_cmd);
1568         install_element(MS_NODE, &cfg_ms_sim_delay_cmd);
1569         install_element(MS_NODE, &cfg_ms_no_sim_delay_cmd);
1570         install_element(MS_NODE, &cfg_ms_stick_cmd);
1571         install_element(MS_NODE, &cfg_ms_no_stick_cmd);
1572         install_element(MS_NODE, &cfg_ms_lupd_cmd);
1573         install_element(MS_NODE, &cfg_ms_no_lupd_cmd);
1574         install_element(MS_NODE, &cfg_ms_codec_full_cmd);
1575         install_element(MS_NODE, &cfg_ms_codec_full_pref_cmd);
1576         install_element(MS_NODE, &cfg_ms_codec_half_cmd);
1577         install_element(MS_NODE, &cfg_ms_codec_half_pref_cmd);
1578         install_element(MS_NODE, &cfg_ms_no_codec_half_cmd);
1579         install_node(&testsim_node, config_write_dummy);
1580         install_default(TESTSIM_NODE);
1581         install_element(TESTSIM_NODE, &ournode_exit_cmd);
1582         install_element(TESTSIM_NODE, &ournode_end_cmd);
1583         install_element(TESTSIM_NODE, &cfg_test_imsi_cmd);
1584         install_element(TESTSIM_NODE, &cfg_test_ki_xor_cmd);
1585         install_element(TESTSIM_NODE, &cfg_test_ki_comp128_cmd);
1586         install_element(TESTSIM_NODE, &cfg_test_barr_cmd);
1587         install_element(TESTSIM_NODE, &cfg_test_no_barr_cmd);
1588         install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd);
1589         install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd);
1590         install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd);
1591
1592         return 0;
1593 }
1594
1595 void vty_notify(struct osmocom_ms *ms, const char *fmt, ...)
1596 {
1597         struct telnet_connection *connection;
1598         char buffer[1000];
1599         va_list args;
1600         struct vty *vty;
1601
1602         if (fmt) {
1603                 va_start(args, fmt);
1604                 vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
1605                 buffer[sizeof(buffer) - 1] = '\0';
1606                 va_end(args);
1607
1608                 if (!buffer[0])
1609                         return;
1610         }
1611
1612         llist_for_each_entry(connection, &active_connections, entry) {
1613                 vty = connection->vty;
1614                 if (!vty)
1615                         continue;
1616                 if (!fmt) {
1617                         vty_out(vty, "%s%% (MS %s)%s", VTY_NEWLINE, ms->name,
1618                                 VTY_NEWLINE);
1619                         continue;
1620                 }
1621                 if (buffer[strlen(buffer) - 1] == '\n') {
1622                         buffer[strlen(buffer) - 1] = '\0';
1623                         vty_out(vty, "%% %s%s", buffer, VTY_NEWLINE);
1624                         buffer[strlen(buffer)] = '\n';
1625                 } else
1626                         vty_out(vty, "%% %s", buffer);
1627         }
1628 }
1629