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