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