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