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