784886524f4f009e4a548c1d69dd720f09f06b11
[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
31 #include <osmocom/bb/common/osmocom_data.h>
32 #include <osmocom/bb/common/networks.h>
33 #include <osmocom/bb/mobile/mncc.h>
34 #include <osmocom/bb/mobile/transaction.h>
35 #include <osmocom/bb/mobile/vty.h>
36 #include <osmocom/bb/mobile/gps.h>
37 #include <osmocom/vty/telnet_interface.h>
38
39 int mncc_call(struct osmocom_ms *ms, char *number);
40 int mncc_hangup(struct osmocom_ms *ms);
41 int mncc_answer(struct osmocom_ms *ms);
42 int mncc_hold(struct osmocom_ms *ms);
43 int mncc_retrieve(struct osmocom_ms *ms, int number);
44
45 extern struct llist_head ms_list;
46 extern struct llist_head active_connections;
47
48 struct cmd_node ms_node = {
49         MS_NODE,
50         "%s(ms)#",
51         1
52 };
53
54 struct cmd_node testsim_node = {
55         TESTSIM_NODE,
56         "%s(test-sim)#",
57         1
58 };
59
60 static void print_vty(void *priv, const char *fmt, ...)
61 {
62         char buffer[1000];
63         struct vty *vty = priv;
64         va_list args;
65
66         va_start(args, fmt);
67         vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
68         buffer[sizeof(buffer) - 1] = '\0';
69         va_end(args);
70
71         if (buffer[0]) {
72                 if (buffer[strlen(buffer) - 1] == '\n') {
73                         buffer[strlen(buffer) - 1] = '\0';
74                         vty_out(vty, "%s%s", buffer, VTY_NEWLINE);
75                 } else
76                         vty_out(vty, "%s", buffer);
77         }
78 }
79
80 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
81 {
82         struct osmocom_ms *ms;
83
84         llist_for_each_entry(ms, &ms_list, entity) {
85                 if (!strcmp(ms->name, name))
86                         return ms;
87         }
88         vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
89
90         return NULL;
91 }
92
93 DEFUN(show_ms, show_ms_cmd, "show ms",
94         SHOW_STR "Display available MS entities\n")
95 {
96         struct osmocom_ms *ms;
97
98         llist_for_each_entry(ms, &ms_list, entity) {
99                 struct gsm_settings *set = &ms->settings;
100
101                 vty_out(vty, "MS NAME: %s%s", ms->name, VTY_NEWLINE);
102                 vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE);
103                 vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE);
104                 if (set->imei_random)
105                         vty_out(vty, " IMEI generation: random (%d trailing "
106                                 "digits)%s", set->imei_random, VTY_NEWLINE);
107                 else
108                         vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE);
109                 vty_out(vty, " network selection mode: %s%s",
110                         (set->plmn_mode == PLMN_MODE_AUTO)
111                                 ? "automatic" : "manual", VTY_NEWLINE);
112         }
113
114         return CMD_SUCCESS;
115 }
116
117 DEFUN(show_support, show_support_cmd, "show support [ms_name]",
118         SHOW_STR "Display information about MS support\n"
119         "Name of MS (see \"show ms\")")
120 {
121         struct osmocom_ms *ms;
122
123         if (argc) {
124                 ms = get_ms(argv[0], vty);
125                 if (!ms)
126                         return CMD_WARNING;
127                 gsm_support_dump(&ms->support, print_vty, vty);
128         } else {
129                 llist_for_each_entry(ms, &ms_list, entity) {
130                         gsm_support_dump(&ms->support, print_vty, vty);
131                         vty_out(vty, "%s", VTY_NEWLINE);
132                 }
133         }
134
135         return CMD_SUCCESS;
136 }
137
138 static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty)
139 {
140         struct gsm_trans *trans;
141
142         vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE);
143         if (ms->settings.plmn_mode == PLMN_MODE_AUTO)
144                 vty_out(vty, " automatic network selection: %s%s", 
145                         plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
146         else
147                 vty_out(vty, " manual network selection: %s%s", 
148                         plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
149         vty_out(vty, " cell selection: %s%s", 
150                 cs_state_names[ms->cellsel.state], VTY_NEWLINE);
151         vty_out(vty, " radio ressource layer: %s%s", 
152                 gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
153         vty_out(vty, " mobility management layer: %s", 
154                 gsm48_mm_state_names[ms->mmlayer.state]);
155         if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
156                 vty_out(vty, ", %s", 
157                         gsm48_mm_substate_names[ms->mmlayer.substate]);
158         vty_out(vty, "%s", VTY_NEWLINE);
159         llist_for_each_entry(trans, &ms->trans_list, entry) {
160                 vty_out(vty, " call control: %s%s", 
161                         gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
162         }
163 }
164
165 DEFUN(show_states, show_states_cmd, "show states [ms_name]",
166         SHOW_STR "Display current states of given MS\n"
167         "Name of MS (see \"show ms\")")
168 {
169         struct osmocom_ms *ms;
170
171         if (argc) {
172                 ms = get_ms(argv[0], vty);
173                 if (!ms)
174                         return CMD_WARNING;
175                 gsm_states_dump(ms, vty);
176         } else {
177                 llist_for_each_entry(ms, &ms_list, entity) {
178                         gsm_states_dump(ms, vty);
179                         vty_out(vty, "%s", VTY_NEWLINE);
180                 }
181         }
182
183         return CMD_SUCCESS;
184 }
185
186 DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]",
187         SHOW_STR "Display information about subscriber\n"
188         "Name of MS (see \"show ms\")")
189 {
190         struct osmocom_ms *ms;
191
192         if (argc) {
193                 ms = get_ms(argv[0], vty);
194                 if (!ms)
195                         return CMD_WARNING;
196                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
197         } else {
198                 llist_for_each_entry(ms, &ms_list, entity) {
199                         gsm_subscr_dump(&ms->subscr, print_vty, vty);
200                         vty_out(vty, "%s", VTY_NEWLINE);
201                 }
202         }
203
204         return CMD_SUCCESS;
205 }
206
207 DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
208         SHOW_STR "Display information about received cells\n"
209         "Name of MS (see \"show ms\")")
210 {
211         struct osmocom_ms *ms;
212
213         ms = get_ms(argv[0], vty);
214         if (!ms)
215                 return CMD_WARNING;
216
217         gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
218                 vty);
219
220         return CMD_SUCCESS;
221 }
222
223 DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>",
224         SHOW_STR "Display information about received cell\n"
225         "Name of MS (see \"show ms\")\nRadio frequency number")
226 {
227         struct osmocom_ms *ms;
228         int i;
229         struct gsm48_sysinfo *s;
230
231         ms = get_ms(argv[0], vty);
232         if (!ms)
233                 return CMD_WARNING;
234
235         i = atoi(argv[1]);
236         if (i < 0 || i > 1023) {
237                 vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s",
238                         argv[1], VTY_NEWLINE);
239                 return CMD_WARNING;
240         }
241         s = ms->cellsel.list[i].sysinfo;
242         if (!s) {
243                 vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s",
244                         argv[1], VTY_NEWLINE);
245                 return CMD_SUCCESS;
246         }
247
248         gsm48_sysinfo_dump(s, i, print_vty, vty);
249
250         return CMD_SUCCESS;
251 }
252
253 DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]",
254         SHOW_STR "Display information about band allocations\n"
255         "Name of MS (see \"show ms\")\nMobile Country Code\n"
256         "Mobile Network Code")
257 {
258         struct osmocom_ms *ms;
259         uint16_t mcc = 0, mnc = 0;
260
261         ms = get_ms(argv[0], vty);
262         if (!ms)
263                 return CMD_WARNING;
264
265         if (argc >= 3) {
266                 mcc = gsm_input_mcc((char *)argv[1]);
267                 mnc = gsm_input_mnc((char *)argv[2]);
268                 if (!mcc) {
269                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
270                         return CMD_WARNING;
271                 }
272                 if (!mnc) {
273                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
274                         return CMD_WARNING;
275                 }
276         }
277
278         gsm322_dump_ba_list(&ms->cellsel, mcc, mnc, print_vty, vty);
279
280         return CMD_SUCCESS;
281 }
282
283 DEFUN(show_forb_plmn, show_forb_plmn_cmd, "show forbidden plmn MS_NAME",
284         SHOW_STR "Display information about forbidden cells / networks\n"
285         "Display forbidden PLMNs\nName of MS (see \"show ms\")")
286 {
287         struct osmocom_ms *ms;
288
289         ms = get_ms(argv[0], vty);
290         if (!ms)
291                 return CMD_WARNING;
292
293         gsm_subscr_dump_forbidden_plmn(ms, print_vty, vty);
294
295         return CMD_SUCCESS;
296 }
297
298 DEFUN(show_forb_la, show_forb_la_cmd, "show forbidden location-area MS_NAME",
299         SHOW_STR "Display information about forbidden cells / networks\n"
300         "Display forbidden location areas\nName of MS (see \"show ms\")")
301 {
302         struct osmocom_ms *ms;
303
304         ms = get_ms(argv[0], vty);
305         if (!ms)
306                 return CMD_WARNING;
307
308         gsm322_dump_forbidden_la(ms, print_vty, vty);
309
310         return CMD_SUCCESS;
311 }
312
313 DEFUN(monitor_network, monitor_network_cmd, "monitor network MS_NAME",
314         "Monitor...\nMonitor network information\nName of MS (see \"show ms\")")
315 {
316         struct osmocom_ms *ms;
317
318         ms = get_ms(argv[0], vty);
319         if (!ms)
320                 return CMD_WARNING;
321
322         gsm48_rr_start_monitor(ms);
323
324         return CMD_SUCCESS;
325 }
326
327 DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME",
328         NO_STR "Monitor...\nDeactivate monitor of network information\n"
329         "Name of MS (see \"show ms\")")
330 {
331         struct osmocom_ms *ms;
332
333         ms = get_ms(argv[0], vty);
334         if (!ms)
335                 return CMD_WARNING;
336
337         gsm48_rr_stop_monitor(ms);
338
339         return CMD_SUCCESS;
340 }
341
342 DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]",
343         "SIM actions\nInsert test card\nName of MS (see \"show ms\")\n"
344         "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN")
345 {
346         struct osmocom_ms *ms;
347         uint16_t mcc = 0x001, mnc = 0x01f;
348
349         ms = get_ms(argv[0], vty);
350         if (!ms)
351                 return CMD_WARNING;
352
353         if (ms->subscr.sim_valid) {
354                 vty_out(vty, "SIM already presend, remove first!%s",
355                         VTY_NEWLINE);
356                 return CMD_WARNING;
357         }
358
359         if (argc >= 3) {
360                 mcc = gsm_input_mcc((char *)argv[1]);
361                 mnc = gsm_input_mnc((char *)argv[2]);
362                 if (!mcc) {
363                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
364                         return CMD_WARNING;
365                 }
366                 if (!mnc) {
367                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
368                         return CMD_WARNING;
369                 }
370         }
371
372         gsm_subscr_testcard(ms, mcc, mnc);
373
374         return CMD_SUCCESS;
375 }
376
377 DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
378         "SIM actions\nSelect SIM from reader\nName 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         if (ms->subscr.sim_valid) {
387                 vty_out(vty, "SIM already presend, remove first!%s",
388                         VTY_NEWLINE);
389                 return CMD_WARNING;
390         }
391
392         gsm_subscr_simcard(ms);
393
394         return CMD_SUCCESS;
395 }
396
397 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
398         "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")")
399 {
400         struct osmocom_ms *ms;
401
402         ms = get_ms(argv[0], vty);
403         if (!ms)
404                 return CMD_WARNING;
405
406         if (!ms->subscr.sim_valid) {
407                 vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
408                 return CMD_WARNING;
409         }
410
411         gsm_subscr_remove(ms);
412
413         return CMD_SUCCESS;
414 }
415
416 DEFUN(sim_pin, sim_pin_cmd, "sim pin MS_NAME PIN",
417         "SIM actions\nEnter PIN for SIM card\nName of MS (see \"show ms\")\n"
418         "PIN number")
419 {
420         struct osmocom_ms *ms;
421
422         ms = get_ms(argv[0], vty);
423         if (!ms)
424                 return CMD_WARNING;
425
426         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
427                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
428                 return CMD_WARNING;
429         }
430
431         if (!ms->subscr.sim_pin_required) {
432                 vty_out(vty, "No PIN is required at this time!%s", VTY_NEWLINE);
433                 return CMD_WARNING;
434         }
435
436         gsm_subscr_sim_pin(ms, (char *)argv[1], "", 0);
437
438         return CMD_SUCCESS;
439 }
440
441 DEFUN(sim_disable_pin, sim_disable_pin_cmd, "sim disable-pin MS_NAME PIN",
442         "SIM actions\nDisable PIN of SIM card\nName of MS (see \"show ms\")\n"
443         "PIN number")
444 {
445         struct osmocom_ms *ms;
446
447         ms = get_ms(argv[0], vty);
448         if (!ms)
449                 return CMD_WARNING;
450
451         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
452                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
453                 return CMD_WARNING;
454         }
455
456         gsm_subscr_sim_pin(ms, (char *)argv[1], "", -1);
457
458         return CMD_SUCCESS;
459 }
460
461 DEFUN(sim_enable_pin, sim_enable_pin_cmd, "sim enable-pin MS_NAME PIN",
462         "SIM actions\nEnable PIN of SIM card\nName of MS (see \"show ms\")\n"
463         "PIN number")
464 {
465         struct osmocom_ms *ms;
466
467         ms = get_ms(argv[0], vty);
468         if (!ms)
469                 return CMD_WARNING;
470
471         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
472                 vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
473                 return CMD_WARNING;
474         }
475
476         gsm_subscr_sim_pin(ms, (char *)argv[1], "", 1);
477
478         return CMD_SUCCESS;
479 }
480
481 DEFUN(sim_change_pin, sim_change_pin_cmd, "sim change-pin MS_NAME OLD NEW",
482         "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
483         "Old PIN number\nNew PIN number")
484 {
485         struct osmocom_ms *ms;
486
487         ms = get_ms(argv[0], vty);
488         if (!ms)
489                 return CMD_WARNING;
490
491         if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
492                 vty_out(vty, "Old PIN must be in range 4..8!%s", VTY_NEWLINE);
493                 return CMD_WARNING;
494         }
495         if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
496                 vty_out(vty, "New PIN must be in range 4..8!%s", VTY_NEWLINE);
497                 return CMD_WARNING;
498         }
499
500         gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 2);
501
502         return CMD_SUCCESS;
503 }
504
505 DEFUN(sim_unblock_pin, sim_unblock_pin_cmd, "sim unblock-pin MS_NAME PUC NEW",
506         "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
507         "Personal Unblock Key\nNew PIN number")
508 {
509         struct osmocom_ms *ms;
510
511         ms = get_ms(argv[0], vty);
512         if (!ms)
513                 return CMD_WARNING;
514
515         if (strlen(argv[1]) != 8) {
516                 vty_out(vty, "PUC must be 8 digits!%s", VTY_NEWLINE);
517                 return CMD_WARNING;
518         }
519         if (strlen(argv[2]) < 4 || strlen(argv[2]) > 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], (char *)argv[2], 99);
525
526         return CMD_SUCCESS;
527 }
528
529 DEFUN(sim_lai, sim_lai_cmd, "sim lai MS_NAME MCC MNC LAC",
530         "SIM actions\nChange LAI of SIM card\nName of MS (see \"show ms\")\n"
531         "Mobile Country Code\nMobile Network Code\nLocation Area Code "
532         " (use 0000 to remove LAI)")
533 {
534         struct osmocom_ms *ms;
535         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
536                  mnc = gsm_input_mnc((char *)argv[2]),
537                  lac = strtoul(argv[3], NULL, 16);
538
539         ms = get_ms(argv[0], vty);
540         if (!ms)
541                 return CMD_WARNING;
542
543         if (!mcc) {
544                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
545                 return CMD_WARNING;
546         }
547         if (!mnc) {
548                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
549                 return CMD_WARNING;
550         }
551
552         ms->subscr.mcc = mcc;
553         ms->subscr.mnc = mnc;
554         ms->subscr.lac = lac;
555         ms->subscr.tmsi = 0xffffffff;
556
557         gsm_subscr_write_loci(ms);
558
559         return CMD_SUCCESS;
560 }
561
562 DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
563         "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
564         "Mobile Country Code\nMobile Network Code")
565 {
566         struct osmocom_ms *ms;
567         struct gsm322_plmn *plmn;
568         struct msgb *nmsg;
569         struct gsm322_msg *ngm;
570         struct gsm322_plmn_list *temp;
571         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
572                  mnc = gsm_input_mnc((char *)argv[2]);
573         int found = 0;
574
575         ms = get_ms(argv[0], vty);
576         if (!ms)
577                 return CMD_WARNING;
578         plmn = &ms->plmn;
579
580         if (!mcc) {
581                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
582                 return CMD_WARNING;
583         }
584         if (!mnc) {
585                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
586                 return CMD_WARNING;
587         }
588
589         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
590                 if (temp->mcc == mcc &&  temp->mnc == mnc)
591                         found = 1;
592         if (!found) {
593                 vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
594                 return CMD_WARNING;
595         }
596
597         nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
598         if (!nmsg)
599                 return CMD_WARNING;
600         ngm = (struct gsm322_msg *) nmsg->data;
601         ngm->mcc = mcc;
602         ngm->mnc = mnc;
603         gsm322_plmn_sendmsg(ms, nmsg);
604
605         return CMD_SUCCESS;
606 }
607
608 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
609         "Make a call\nName of MS (see \"show ms\")\nPhone number to call "
610         "(Use digits '0123456789*#abc', and '+' to dial international)\n"
611         "Make an emergency call\nAnswer an incomming call\nHangup a call\n"
612         "Hold current active call\n")
613 {
614         struct osmocom_ms *ms;
615         int i;
616
617         ms = get_ms(argv[0], vty);
618         if (!ms)
619                 return CMD_WARNING;
620
621         switch (argv[1][0]) {
622         case 'a':
623                 mncc_answer(ms);
624                 break;
625         case 'h':
626                 if (argv[1][1] == 'a')
627                         mncc_hangup(ms);
628                 else
629                         mncc_hold(ms);
630                 break;
631         default:
632                 for (i = 0; i < strlen(argv[1]); i++) {
633                         /* allow international notation with + */
634                         if (i == 0 && argv[1][i] == '+')
635                                 continue;
636                         if (!(argv[1][i] >= '0' && argv[1][i] <= '9')
637                          && argv[1][i] != '*'
638                          && argv[1][i] != '#'
639                          && !(argv[1][i] >= 'a' && argv[1][i] <= 'c')) {
640                                 vty_out(vty, "Invalid digit '%c'%s", argv[1][i],
641                                         VTY_NEWLINE);
642                                 return CMD_WARNING;
643                         }
644                 }
645                 mncc_call(ms, (char *)argv[1]);
646         }
647
648         return CMD_SUCCESS;
649 }
650
651 DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]",
652         "Make a call\nName of MS (see \"show ms\")\n"
653         "Retrieve call on hold\nNumber of call to retrieve")
654 {
655         struct osmocom_ms *ms;
656
657         ms = get_ms(argv[0], vty);
658         if (!ms)
659                 return CMD_WARNING;
660
661         mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
662
663         return CMD_SUCCESS;
664 }
665
666 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
667         "Network ...\nShow results of network search (again)\n"
668         "Name of MS (see \"show ms\")")
669 {
670         struct osmocom_ms *ms;
671         struct gsm322_plmn *plmn;
672         struct gsm322_plmn_list *temp;
673
674         ms = get_ms(argv[0], vty);
675         if (!ms)
676                 return CMD_WARNING;
677         plmn = &ms->plmn;
678
679         if (ms->settings.plmn_mode != PLMN_MODE_AUTO
680          && plmn->state != GSM322_M3_NOT_ON_PLMN) {
681                 vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
682                 return CMD_WARNING;
683         }
684
685         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
686                 vty_out(vty, " Network %s, %s (%s, %s)%s",
687                         gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
688                         gsm_get_mcc(temp->mcc),
689                         gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
690
691         return CMD_SUCCESS;
692 }
693
694 DEFUN(network_search, network_search_cmd, "network search MS_NAME",
695         "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
696 {
697         struct osmocom_ms *ms;
698         struct msgb *nmsg;
699
700         ms = get_ms(argv[0], vty);
701         if (!ms)
702                 return CMD_WARNING;
703
704         nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
705         if (!nmsg)
706                 return CMD_WARNING;
707         gsm322_plmn_sendmsg(ms, nmsg);
708
709         return CMD_SUCCESS;
710 }
711
712 DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable",
713         "GPS receiver")
714 {
715         if (gps_open()) {
716                 gps.enable = 1;
717                 vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE);
718                 return CMD_WARNING;
719         }
720         gps.enable = 1;
721
722         return CMD_SUCCESS;
723 }
724
725 DEFUN(cfg_no_gps_enable, cfg_no_gps_enable_cmd, "no gps enable",
726         NO_STR "Disable GPS receiver")
727 {
728         if (gps.enable)
729                 gps_close();
730         gps.enable = 0;
731
732         return CMD_SUCCESS;
733 }
734
735 DEFUN(cfg_gps_device, cfg_gps_device_cmd, "gps device DEVICE",
736         "GPS receiver\nSelect serial device\n"
737         "Full path of serial device including /dev/")
738 {
739         strncpy(gps.device, argv[0], sizeof(gps.device));
740         gps.device[sizeof(gps.device) - 1] = '\0';
741         if (gps.enable) {
742                 gps_close();
743                 if (gps_open()) {
744                         vty_out(vty, "Failed to open GPS device!%s",
745                                 VTY_NEWLINE);
746                         return CMD_WARNING;
747                 }
748         }
749
750         return CMD_SUCCESS;
751 }
752
753 DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate "
754         "(default|4800|""9600|19200|38400|57600|115200)",
755         "GPS receiver\nSelect baud rate\nDefault, don't modify\n\n\n\n\n\n")
756 {
757         if (argv[0][0] == 'd')
758                 gps.baud = 0;
759         else
760                 gps.baud = atoi(argv[0]);
761         if (gps.enable) {
762                 gps_close();
763                 if (gps_open()) {
764                         gps.enable = 0;
765                         vty_out(vty, "Failed to open GPS device!%s",
766                                 VTY_NEWLINE);
767                         return CMD_WARNING;
768                 }
769         }
770
771         return CMD_SUCCESS;
772 }
773
774 /* per MS config */
775 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
776         "Select a mobile station to configure\nName of MS (see \"show ms\")")
777 {
778         struct osmocom_ms *ms;
779
780         ms = get_ms(argv[0], vty);
781         if (!ms)
782                 return CMD_WARNING;
783
784         vty->index = ms;
785         vty->node = MS_NODE;
786
787         return CMD_SUCCESS;
788 }
789
790 static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
791 {
792         struct gsm_support *sup = &ms->support;
793         struct gsm_settings *set = &ms->settings;
794
795         vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
796         switch(set->sim_type) {
797                 case GSM_SIM_TYPE_NONE:
798                 vty_out(vty, " sim none%s", VTY_NEWLINE);
799                 break;
800                 case GSM_SIM_TYPE_READER:
801                 vty_out(vty, " sim reader%s", VTY_NEWLINE);
802                 break;
803                 case GSM_SIM_TYPE_TEST:
804                 vty_out(vty, " sim test%s", VTY_NEWLINE);
805                 break;
806         }
807         vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
808                         == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
809         vty_out(vty, " imei %s %s%s", set->imei,
810                 set->imeisv + strlen(set->imei), VTY_NEWLINE);
811         if (set->imei_random)
812                 vty_out(vty, " imei-random %d%s", set->imei_random,
813                         VTY_NEWLINE);
814         else
815                 vty_out(vty, " imei-fixed%s", VTY_NEWLINE);
816         if (set->emergency_imsi[0])
817                 vty_out(vty, " emergency-imsi %s%s", set->emergency_imsi,
818                         VTY_NEWLINE);
819         else
820                 vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE);
821         vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE);
822         vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE);
823         vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE);
824         vty_out(vty, " test-sim%s", VTY_NEWLINE);
825         vty_out(vty, "  imsi %s%s", set->test_imsi, VTY_NEWLINE);
826         switch (set->test_ki_type) {
827         case GSM_SIM_KEY_XOR:
828                 vty_out(vty, "  ki xor %s%s", hexdump(set->test_ki, 12),
829                         VTY_NEWLINE);
830                 break;
831         case GSM_SIM_KEY_COMP128:
832                 vty_out(vty, "  ki comp128 %s%s", hexdump(set->test_ki, 16),
833                         VTY_NEWLINE);
834                 break;
835         }
836         vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
837                 VTY_NEWLINE);
838         if (set->test_rplmn_valid)
839                 vty_out(vty, "  rplmn %s %s%s",
840                         gsm_print_mcc(set->test_rplmn_mcc),
841                         gsm_print_mnc(set->test_rplmn_mnc),
842                         VTY_NEWLINE);
843         else
844                 vty_out(vty, "  no rplmn%s", VTY_NEWLINE);
845         vty_out(vty, "  hplmn-search %s%s", (set->test_always) ? "everywhere"
846                         : "foreign-country", VTY_NEWLINE);
847         vty_out(vty, " exit%s", VTY_NEWLINE);
848         vty_out(vty, " min-rxlev %d%s", set->min_rxlev_db, VTY_NEWLINE);
849         if (set->alter_tx_power)
850                 if (set->alter_tx_power_value)
851                         vty_out(vty, " tx-power %d%s",
852                                 set->alter_tx_power_value, VTY_NEWLINE);
853                 else
854                         vty_out(vty, " tx-power full%s", VTY_NEWLINE);
855         else
856                 vty_out(vty, " tx-power auto%s", VTY_NEWLINE);
857         if (set->alter_delay)
858                 vty_out(vty, " simulated-delay %d%s", set->alter_delay,
859                         VTY_NEWLINE);
860         else
861                 vty_out(vty, " no simulated-delay%s", VTY_NEWLINE);
862         if (set->stick)
863                 vty_out(vty, " stick %d%s", set->stick_arfcn,
864                         VTY_NEWLINE);
865         else
866                 vty_out(vty, " no stick%s", VTY_NEWLINE);
867         if (set->no_lupd)
868                 vty_out(vty, " no location-updating%s", VTY_NEWLINE);
869         else
870                 vty_out(vty, " location-updating%s", VTY_NEWLINE);
871         if (sup->full_v1 || sup->full_v2 || sup->full_v3) {
872                 /* mandatory anyway */
873                 vty_out(vty, " codec full-speed%s%s",
874                         (!set->half_prefer) ? " prefer" : "",
875                         VTY_NEWLINE);
876         }
877         if (sup->half_v1 || sup->half_v3) {
878                 if (set->half)
879                         vty_out(vty, " codec half-speed%s%s",
880                                 (set->half_prefer) ? " prefer" : "",
881                                 VTY_NEWLINE);
882                 else
883                         vty_out(vty, " no codec half-speed%s", VTY_NEWLINE);
884         }
885         vty_out(vty, "exit%s", VTY_NEWLINE);
886         vty_out(vty, "!%s", VTY_NEWLINE);
887 }
888
889 static int config_write_ms(struct vty *vty)
890 {
891         struct osmocom_ms *ms;
892
893         vty_out(vty, "gps device %s%s", gps.device, VTY_NEWLINE);
894         if (gps.baud)
895                 vty_out(vty, "gps baudrate %d%s", gps.baud, VTY_NEWLINE);
896         else
897                 vty_out(vty, "gps baudrate default%s", VTY_NEWLINE);
898         vty_out(vty, "%sgps enable%s", (gps.enable) ? "" : "no ", VTY_NEWLINE);
899         vty_out(vty, "!%s", VTY_NEWLINE);
900
901         llist_for_each_entry(ms, &ms_list, entity)
902                 config_write_ms_single(vty, ms);
903
904         return CMD_SUCCESS;
905 }
906
907 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)",
908         "Set SIM card type when powering on\nNo SIM interted\n"
909         "Use SIM from reader\nTest SIM inserted")
910 {
911         struct osmocom_ms *ms = vty->index;
912
913         switch (argv[0][0]) {
914         case 'n':
915                 ms->settings.sim_type = GSM_SIM_TYPE_NONE;
916                 break;
917         case 'r':
918                 ms->settings.sim_type = GSM_SIM_TYPE_READER;
919                 break;
920         case 't':
921                 ms->settings.sim_type = GSM_SIM_TYPE_TEST;
922                 break;
923         default:
924                 vty_out(vty, "unknown SIM type%s", VTY_NEWLINE);
925                 return CMD_WARNING;
926         }
927
928         return CMD_SUCCESS;
929 }
930
931 DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
932         "Set network selection mode\nAutomatic network selection\n"
933         "Manual network selection")
934 {
935         struct osmocom_ms *ms = vty->index;
936         struct msgb *nmsg;
937
938         if (!ms->plmn.state) {
939                 if (argv[0][0] == 'a')
940                         ms->settings.plmn_mode = PLMN_MODE_AUTO;
941                 else
942                         ms->settings.plmn_mode = PLMN_MODE_MANUAL;
943
944                 return CMD_SUCCESS;
945         }
946         if (argv[0][0] == 'a')
947                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
948         else
949                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
950         if (!nmsg)
951                 return CMD_WARNING;
952         gsm322_plmn_sendmsg(ms, nmsg);
953
954         return CMD_SUCCESS;
955 }
956
957 DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
958         "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
959         "Software version digit")
960 {
961         struct osmocom_ms *ms = vty->index;
962         char *error, *sv = "0";
963
964         if (argc >= 2)
965                 sv = (char *)argv[1];
966
967         error = gsm_check_imei(argv[0], sv);
968         if (error) {
969                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
970                 return CMD_WARNING;
971         }
972
973         strcpy(ms->settings.imei, argv[0]);
974         strcpy(ms->settings.imeisv, argv[0]);
975         strcpy(ms->settings.imeisv + 15, sv);
976
977         return CMD_SUCCESS;
978 }
979
980 DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
981         "Use fixed IMEI on every power on")
982 {
983         struct osmocom_ms *ms = vty->index;
984
985         ms->settings.imei_random = 0;
986
987         return CMD_SUCCESS;
988 }
989
990 DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
991         "Use random IMEI on every power on\n"
992         "Number of trailing digits to randomize")
993 {
994         struct osmocom_ms *ms = vty->index;
995
996         ms->settings.imei_random = atoi(argv[0]);
997
998         return CMD_SUCCESS;
999 }
1000
1001 DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi IMSI",
1002         "Use special IMSI for emergency calls\n15 digits IMSI")
1003 {
1004         struct osmocom_ms *ms = vty->index;
1005         char *error;
1006
1007         error = gsm_check_imsi(argv[0]);
1008         if (error) {
1009                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1010                 return CMD_WARNING;
1011         }
1012         strcpy(ms->settings.emergency_imsi, argv[0]);
1013
1014         return CMD_SUCCESS;
1015 }
1016
1017 DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
1018         NO_STR "Use IMSI of SIM or IMEI for emergency calls")
1019 {
1020         struct osmocom_ms *ms = vty->index;
1021
1022         ms->settings.emergency_imsi[0] = '\0';
1023
1024         return CMD_SUCCESS;
1025 }
1026
1027 DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
1028         NO_STR "Disallow waiting calls")
1029 {
1030         struct osmocom_ms *ms = vty->index;
1031
1032         ms->settings.cw = 0;
1033
1034         return CMD_SUCCESS;
1035 }
1036
1037 DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
1038         "Allow waiting calls")
1039 {
1040         struct osmocom_ms *ms = vty->index;
1041
1042         ms->settings.cw = 1;
1043
1044         return CMD_SUCCESS;
1045 }
1046
1047 DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
1048         "Force caller ID presentation")
1049 {
1050         struct osmocom_ms *ms = vty->index;
1051
1052         ms->settings.clip = 1;
1053         ms->settings.clir = 0;
1054
1055         return CMD_SUCCESS;
1056 }
1057
1058 DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
1059         "Force caller ID restriction")
1060 {
1061         struct osmocom_ms *ms = vty->index;
1062
1063         ms->settings.clip = 0;
1064         ms->settings.clir = 1;
1065
1066         return CMD_SUCCESS;
1067 }
1068
1069 DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
1070         NO_STR "Disable forcing of caller ID presentation")
1071 {
1072         struct osmocom_ms *ms = vty->index;
1073
1074         ms->settings.clip = 0;
1075
1076         return CMD_SUCCESS;
1077 }
1078
1079 DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
1080         NO_STR "Disable forcing of caller ID restriction")
1081 {
1082         struct osmocom_ms *ms = vty->index;
1083
1084         ms->settings.clir = 0;
1085
1086         return CMD_SUCCESS;
1087 }
1088
1089 DEFUN(cfg_ms_min_rxlev, cfg_ms_min_rxlev_cmd, "min-rxlev <-110--47>",
1090         "Set the minimum receive level to select a cell\n"
1091         "Minimum receive level from -110 dBm to -47 dBm")
1092 {
1093         struct osmocom_ms *ms = vty->index;
1094
1095         ms->settings.min_rxlev_db = atoi(argv[0]);
1096
1097         return CMD_SUCCESS;
1098 }
1099
1100 DEFUN(cfg_ms_tx_power, cfg_ms_tx_power_cmd, "tx-power (auto|full)",
1101         "Set the way to choose transmit power\nControlled by BTS\n"
1102         "Always full power\nFixed GSM power value if supported")
1103 {
1104         struct osmocom_ms *ms = vty->index;
1105
1106         switch (argv[0][0]) {
1107         case 'a':
1108                 ms->settings.alter_tx_power = 0;
1109                 break;
1110         case 'f':
1111                 ms->settings.alter_tx_power = 1;
1112                 ms->settings.alter_tx_power_value = 0;
1113                 break;
1114         }
1115
1116         return CMD_SUCCESS;
1117 }
1118
1119 DEFUN(cfg_ms_tx_power_val, cfg_ms_tx_power_val_cmd, "tx-power <0-31>",
1120         "Set the way to choose transmit power\n"
1121         "Fixed GSM power value if supported")
1122 {
1123         struct osmocom_ms *ms = vty->index;
1124
1125         ms->settings.alter_tx_power = 1;
1126         ms->settings.alter_tx_power_value = atoi(argv[0]);
1127
1128         return CMD_SUCCESS;
1129 }
1130
1131 DEFUN(cfg_ms_sim_delay, cfg_ms_sim_delay_cmd, "simulated-delay <-128-127>",
1132         "Simulate a lower or higher distance from the BTS\n"
1133         "Delay in half bits (distance in 553.85 meter steps)")
1134 {
1135         struct osmocom_ms *ms = vty->index;
1136
1137         ms->settings.alter_delay = atoi(argv[0]);
1138         gsm48_rr_alter_delay(ms);
1139
1140         return CMD_SUCCESS;
1141 }
1142
1143 DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
1144         NO_STR "Do not simulate a lower or higher distance from the BTS")
1145 {
1146         struct osmocom_ms *ms = vty->index;
1147
1148         ms->settings.alter_delay = 0;
1149         gsm48_rr_alter_delay(ms);
1150
1151         return CMD_SUCCESS;
1152 }
1153
1154 DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023>",
1155         "Stick to the given cell\nARFCN of the cell to stick to")
1156 {
1157         struct osmocom_ms *ms = vty->index;
1158
1159         ms->settings.stick = 1;
1160         ms->settings.stick_arfcn = atoi(argv[0]);
1161
1162         return CMD_SUCCESS;
1163 }
1164
1165 DEFUN(cfg_ms_no_stick, cfg_ms_no_stick_cmd, "no stick",
1166         NO_STR "Do not stick to any cell")
1167 {
1168         struct osmocom_ms *ms = vty->index;
1169
1170         ms->settings.stick = 0;
1171
1172         return CMD_SUCCESS;
1173 }
1174
1175 DEFUN(cfg_ms_lupd, cfg_ms_lupd_cmd, "location-updating",
1176         "Allow location updating")
1177 {
1178         struct osmocom_ms *ms = vty->index;
1179
1180         ms->settings.no_lupd = 0;
1181
1182         return CMD_SUCCESS;
1183 }
1184
1185 DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating",
1186         NO_STR "Do not allow location updating")
1187 {
1188         struct osmocom_ms *ms = vty->index;
1189
1190         ms->settings.no_lupd = 1;
1191
1192         return CMD_SUCCESS;
1193 }
1194
1195 DEFUN(cfg_codec_full, cfg_ms_codec_full_cmd, "codec full-speed",
1196         "Enable codec\nFull speed speech codec")
1197 {
1198         struct osmocom_ms *ms = vty->index;
1199         struct gsm_support *sup = &ms->support;
1200
1201         if (!sup->full_v1 && !sup->full_v2 && !sup->full_v3) {
1202                 vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
1203                 return CMD_WARNING;
1204         }
1205
1206         return CMD_SUCCESS;
1207 }
1208
1209 DEFUN(cfg_codec_full_pref, cfg_ms_codec_full_pref_cmd, "codec full-speed "
1210         "prefer",
1211         "Enable codec\nFull speed speech codec\nPrefer this codec")
1212 {
1213         struct osmocom_ms *ms = vty->index;
1214         struct gsm_support *sup = &ms->support;
1215
1216         if (!sup->full_v1 && !sup->full_v2 && !sup->full_v3) {
1217                 vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
1218                 return CMD_WARNING;
1219         }
1220
1221         ms->settings.half_prefer = 0;
1222
1223         return CMD_SUCCESS;
1224 }
1225
1226 DEFUN(cfg_codec_half, cfg_ms_codec_half_cmd, "codec half-speed",
1227         "Enable codec\nHalf speed speech codec")
1228 {
1229         struct osmocom_ms *ms = vty->index;
1230         struct gsm_support *sup = &ms->support;
1231
1232         if (!sup->half_v1 && !sup->half_v3) {
1233                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1234                 return CMD_WARNING;
1235         }
1236
1237         ms->settings.half = 1;
1238
1239         return CMD_SUCCESS;
1240 }
1241
1242 DEFUN(cfg_codec_half_pref, cfg_ms_codec_half_pref_cmd, "codec half-speed "
1243         "prefer",
1244         "Enable codec\nHalf speed speech codec\nPrefer this codec")
1245 {
1246         struct osmocom_ms *ms = vty->index;
1247         struct gsm_support *sup = &ms->support;
1248
1249         if (!sup->half_v1 && !sup->half_v3) {
1250                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1251                 return CMD_WARNING;
1252         }
1253
1254         ms->settings.half = 1;
1255         ms->settings.half_prefer = 1;
1256
1257         return CMD_SUCCESS;
1258 }
1259
1260 DEFUN(cfg_no_codec_half, cfg_ms_no_codec_half_cmd, "no codec half-speed",
1261         NO_STR "Disable codec\nHalf speed speech codec")
1262 {
1263         struct osmocom_ms *ms = vty->index;
1264         struct gsm_support *sup = &ms->support;
1265
1266         if (!sup->half_v1 && !sup->half_v3) {
1267                 vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
1268                 return CMD_WARNING;
1269         }
1270
1271         ms->settings.half = 0;
1272         ms->settings.half_prefer = 0;
1273
1274         return CMD_SUCCESS;
1275 }
1276
1277 /* per testsim config */
1278 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
1279         "Configure test SIM emulation")
1280 {
1281         vty->node = TESTSIM_NODE;
1282
1283         return CMD_SUCCESS;
1284 }
1285
1286 static int config_write_dummy(struct vty *vty)
1287 {
1288         return CMD_SUCCESS;
1289 }
1290
1291 DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
1292         "Set IMSI on test card\n15 digits IMSI")
1293 {
1294         struct osmocom_ms *ms = vty->index;
1295         char *error = gsm_check_imsi(argv[0]);
1296
1297         if (error) {
1298                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
1299                 return CMD_WARNING;
1300         }
1301
1302         strcpy(ms->settings.test_imsi, argv[0]);
1303
1304         return CMD_SUCCESS;
1305 }
1306
1307 #define HEX_STR "\nByte as two digits hexadecimal"
1308 DEFUN(cfg_test_ki_xor, cfg_test_ki_xor_cmd, "ki xor HEX HEX HEX HEX HEX HEX "
1309         "HEX HEX HEX HEX HEX HEX",
1310         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1311         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR)
1312 {
1313         struct osmocom_ms *ms = vty->index;
1314         struct gsm_settings *set = &ms->settings;
1315         uint8_t ki[12];
1316         const char *p;
1317         int i;
1318
1319         for (i = 0; i < 12; i++) {
1320                 p = argv[i];
1321                 if (!strncmp(p, "0x", 2))
1322                         p += 2;
1323                 if (strlen(p) != 2) {
1324                         vty_out(vty, "Expecting two digits hex value (with or "
1325                                 "without 0x in front)%s", VTY_NEWLINE);
1326                         return CMD_WARNING;
1327                 }
1328                 ki[i] = strtoul(p, NULL, 16);
1329         }
1330
1331         set->test_ki_type = GSM_SIM_KEY_XOR;
1332         memcpy(set->test_ki, ki, 12);
1333         return CMD_SUCCESS;
1334 }
1335
1336 DEFUN(cfg_test_ki_comp128, cfg_test_ki_comp128_cmd, "ki comp128 HEX HEX HEX "
1337         "HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX",
1338         "Set Key (Kc) on test card\nUse XOR algorithm" HEX_STR HEX_STR HEX_STR
1339         HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR HEX_STR
1340         HEX_STR HEX_STR HEX_STR HEX_STR)
1341 {
1342         struct osmocom_ms *ms = vty->index;
1343         struct gsm_settings *set = &ms->settings;
1344         uint8_t ki[16];
1345         const char *p;
1346         int i;
1347
1348         for (i = 0; i < 16; i++) {
1349                 p = argv[i];
1350                 if (!strncmp(p, "0x", 2))
1351                         p += 2;
1352                 if (strlen(p) != 2) {
1353                         vty_out(vty, "Expecting two digits hex value (with or "
1354                                 "without 0x in front)%s", VTY_NEWLINE);
1355                         return CMD_WARNING;
1356                 }
1357                 ki[i] = strtoul(p, NULL, 16);
1358         }
1359
1360         set->test_ki_type = GSM_SIM_KEY_COMP128;
1361         memcpy(set->test_ki, ki, 16);
1362         return CMD_SUCCESS;
1363 }
1364
1365 DEFUN(cfg_test_barr, cfg_test_barr_cmd, "barred-access",
1366         "Allow access to barred cells")
1367 {
1368         struct osmocom_ms *ms = vty->index;
1369
1370         ms->settings.test_barr = 1;
1371
1372         return CMD_SUCCESS;
1373 }
1374
1375 DEFUN(cfg_test_no_barr, cfg_test_no_barr_cmd, "no barred-access",
1376         NO_STR "Deny access to barred cells")
1377 {
1378         struct osmocom_ms *ms = vty->index;
1379
1380         ms->settings.test_barr = 0;
1381
1382         return CMD_SUCCESS;
1383 }
1384
1385 DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
1386         NO_STR "Unset Registered PLMN")
1387 {
1388         struct osmocom_ms *ms = vty->index;
1389
1390         ms->settings.test_rplmn_valid = 0;
1391
1392         return CMD_SUCCESS;
1393 }
1394
1395 DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC",
1396         "Set Registered PLMN\nMobile Country Code\nMobile Network Code")
1397 {
1398         struct osmocom_ms *ms = vty->index;
1399         uint16_t mcc = gsm_input_mcc((char *)argv[0]),
1400                  mnc = gsm_input_mnc((char *)argv[1]);
1401
1402         if (!mcc) {
1403                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
1404                 return CMD_WARNING;
1405         }
1406         if (!mnc) {
1407                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
1408                 return CMD_WARNING;
1409         }
1410         ms->settings.test_rplmn_valid = 1;
1411         ms->settings.test_rplmn_mcc = mcc;
1412         ms->settings.test_rplmn_mnc = mnc;
1413
1414         return CMD_SUCCESS;
1415 }
1416
1417 DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-country)",
1418         "Set Home PLMN search mode\n"
1419         "Search for HPLMN when on any other network\n"
1420         "Search for HPLMN when in a different country")
1421 {
1422         struct osmocom_ms *ms = vty->index;
1423
1424         switch (argv[0][0]) {
1425         case 'e':
1426                 ms->settings.test_always = 1;
1427                 break;
1428         case 'f':
1429                 ms->settings.test_always = 0;
1430                 break;
1431         }
1432
1433         return CMD_SUCCESS;
1434 }
1435
1436 enum node_type ms_vty_go_parent(struct vty *vty)
1437 {
1438         switch (vty->node) {
1439         case MS_NODE:
1440                 vty->node = CONFIG_NODE;
1441                 vty->index = NULL;
1442                 break;
1443         case TESTSIM_NODE:
1444                 vty->node = MS_NODE;
1445                 break;
1446         default:
1447                 vty->node = CONFIG_NODE;
1448         }
1449
1450         return vty->node;
1451 }
1452
1453 /* Down vty node level. */
1454 gDEFUN(ournode_exit,
1455        ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
1456 {
1457         switch (vty->node) {
1458         case MS_NODE:
1459                 vty->node = CONFIG_NODE;
1460                 vty->index = NULL;
1461                 break;
1462         case TESTSIM_NODE:
1463                 vty->node = MS_NODE;
1464                 break;
1465         default:
1466                 break;
1467         }
1468         return CMD_SUCCESS;
1469 }
1470
1471 /* End of configuration. */
1472 gDEFUN(ournode_end,
1473        ournode_end_cmd, "end", "End current mode and change to enable mode.")
1474 {
1475         switch (vty->node) {
1476         case VIEW_NODE:
1477         case ENABLE_NODE:
1478                 /* Nothing to do. */
1479                 break;
1480         case CONFIG_NODE:
1481         case VTY_NODE:
1482         case MS_NODE:
1483         case TESTSIM_NODE:
1484                 vty_config_unlock(vty);
1485                 vty->node = ENABLE_NODE;
1486                 vty->index = NULL;
1487                 vty->index_sub = NULL;
1488                 break;
1489         default:
1490                 break;
1491         }
1492         return CMD_SUCCESS;
1493 }
1494
1495 int ms_vty_init(void)
1496 {
1497         install_element_ve(&show_ms_cmd);
1498         install_element_ve(&show_subscr_cmd);
1499         install_element_ve(&show_support_cmd);
1500         install_element_ve(&show_states_cmd);
1501         install_element_ve(&show_cell_cmd);
1502         install_element_ve(&show_cell_si_cmd);
1503         install_element_ve(&show_ba_cmd);
1504         install_element_ve(&show_forb_la_cmd);
1505         install_element_ve(&show_forb_plmn_cmd);
1506         install_element_ve(&monitor_network_cmd);
1507         install_element_ve(&no_monitor_network_cmd);
1508
1509         install_element(ENABLE_NODE, &sim_test_cmd);
1510         install_element(ENABLE_NODE, &sim_reader_cmd);
1511         install_element(ENABLE_NODE, &sim_remove_cmd);
1512         install_element(ENABLE_NODE, &sim_pin_cmd);
1513         install_element(ENABLE_NODE, &sim_disable_pin_cmd);
1514         install_element(ENABLE_NODE, &sim_enable_pin_cmd);
1515         install_element(ENABLE_NODE, &sim_change_pin_cmd);
1516         install_element(ENABLE_NODE, &sim_unblock_pin_cmd);
1517         install_element(ENABLE_NODE, &sim_lai_cmd);
1518         install_element(ENABLE_NODE, &network_search_cmd);
1519         install_element(ENABLE_NODE, &network_show_cmd);
1520         install_element(ENABLE_NODE, &network_select_cmd);
1521         install_element(ENABLE_NODE, &call_cmd);
1522         install_element(ENABLE_NODE, &call_retr_cmd);
1523
1524         install_element(CONFIG_NODE, &cfg_gps_device_cmd);
1525         install_element(CONFIG_NODE, &cfg_gps_baud_cmd);
1526         install_element(CONFIG_NODE, &cfg_gps_enable_cmd);
1527         install_element(CONFIG_NODE, &cfg_no_gps_enable_cmd);
1528
1529         install_element(CONFIG_NODE, &cfg_ms_cmd);
1530         install_element(CONFIG_NODE, &ournode_end_cmd);
1531         install_node(&ms_node, config_write_ms);
1532         install_default(MS_NODE);
1533         install_element(MS_NODE, &ournode_exit_cmd);
1534         install_element(MS_NODE, &ournode_end_cmd);
1535         install_element(MS_NODE, &cfg_ms_sim_cmd);
1536         install_element(MS_NODE, &cfg_ms_mode_cmd);
1537         install_element(MS_NODE, &cfg_ms_imei_cmd);
1538         install_element(MS_NODE, &cfg_ms_imei_fixed_cmd);
1539         install_element(MS_NODE, &cfg_ms_imei_random_cmd);
1540         install_element(MS_NODE, &cfg_ms_no_emerg_imsi_cmd);
1541         install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
1542         install_element(MS_NODE, &cfg_ms_cw_cmd);
1543         install_element(MS_NODE, &cfg_ms_no_cw_cmd);
1544         install_element(MS_NODE, &cfg_ms_clip_cmd);
1545         install_element(MS_NODE, &cfg_ms_clir_cmd);
1546         install_element(MS_NODE, &cfg_ms_no_clip_cmd);
1547         install_element(MS_NODE, &cfg_ms_no_clir_cmd);
1548         install_element(MS_NODE, &cfg_ms_testsim_cmd);
1549         install_element(MS_NODE, &cfg_ms_min_rxlev_cmd);
1550         install_element(MS_NODE, &cfg_ms_tx_power_cmd);
1551         install_element(MS_NODE, &cfg_ms_tx_power_val_cmd);
1552         install_element(MS_NODE, &cfg_ms_sim_delay_cmd);
1553         install_element(MS_NODE, &cfg_ms_no_sim_delay_cmd);
1554         install_element(MS_NODE, &cfg_ms_stick_cmd);
1555         install_element(MS_NODE, &cfg_ms_no_stick_cmd);
1556         install_element(MS_NODE, &cfg_ms_lupd_cmd);
1557         install_element(MS_NODE, &cfg_ms_no_lupd_cmd);
1558         install_element(MS_NODE, &cfg_ms_codec_full_cmd);
1559         install_element(MS_NODE, &cfg_ms_codec_full_pref_cmd);
1560         install_element(MS_NODE, &cfg_ms_codec_half_cmd);
1561         install_element(MS_NODE, &cfg_ms_codec_half_pref_cmd);
1562         install_element(MS_NODE, &cfg_ms_no_codec_half_cmd);
1563         install_node(&testsim_node, config_write_dummy);
1564         install_default(TESTSIM_NODE);
1565         install_element(TESTSIM_NODE, &ournode_exit_cmd);
1566         install_element(TESTSIM_NODE, &ournode_end_cmd);
1567         install_element(TESTSIM_NODE, &cfg_test_imsi_cmd);
1568         install_element(TESTSIM_NODE, &cfg_test_ki_xor_cmd);
1569         install_element(TESTSIM_NODE, &cfg_test_ki_comp128_cmd);
1570         install_element(TESTSIM_NODE, &cfg_test_barr_cmd);
1571         install_element(TESTSIM_NODE, &cfg_test_no_barr_cmd);
1572         install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd);
1573         install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd);
1574         install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd);
1575
1576         return 0;
1577 }
1578
1579 void vty_notify(struct osmocom_ms *ms, const char *fmt, ...)
1580 {
1581         struct telnet_connection *connection;
1582         char buffer[1000];
1583         va_list args;
1584         struct vty *vty;
1585
1586         if (fmt) {
1587                 va_start(args, fmt);
1588                 vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
1589                 buffer[sizeof(buffer) - 1] = '\0';
1590                 va_end(args);
1591
1592                 if (!buffer[0])
1593                         return;
1594         }
1595
1596         llist_for_each_entry(connection, &active_connections, entry) {
1597                 vty = connection->vty;
1598                 if (!vty)
1599                         continue;
1600                 if (!fmt) {
1601                         vty_out(vty, "%s%% (MS %s)%s", VTY_NEWLINE, ms->name,
1602                                 VTY_NEWLINE);
1603                         continue;
1604                 }
1605                 if (buffer[strlen(buffer) - 1] == '\n') {
1606                         buffer[strlen(buffer) - 1] = '\0';
1607                         vty_out(vty, "%% %s%s", buffer, VTY_NEWLINE);
1608                         buffer[strlen(buffer)] = '\n';
1609                 } else
1610                         vty_out(vty, "%% %s", buffer);
1611         }
1612 }
1613