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