layer23: Split [2/2] -> The header files
[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/gsm48.h>
29
30 #include <osmocom/bb/common/osmocom_data.h>
31 #include <osmocom/bb/common/networks.h>
32 #include <osmocom/bb/mobile/mncc.h>
33 #include <osmocom/bb/mobile/transaction.h>
34 #include <osmocom/bb/mobile/vty.h>
35 #include <osmocom/vty/telnet_interface.h>
36
37 int mncc_call(struct osmocom_ms *ms, char *number);
38 int mncc_hangup(struct osmocom_ms *ms);
39 int mncc_answer(struct osmocom_ms *ms);
40 int mncc_hold(struct osmocom_ms *ms);
41 int mncc_retrieve(struct osmocom_ms *ms, int number);
42
43 extern struct llist_head ms_list;
44 extern struct llist_head active_connections;
45
46 struct cmd_node ms_node = {
47         MS_NODE,
48         "%s(ms)#",
49         1
50 };
51
52 struct cmd_node testsim_node = {
53         TESTSIM_NODE,
54         "%s(test-sim)#",
55         1
56 };
57
58 static void print_vty(void *priv, const char *fmt, ...)
59 {
60         char buffer[1000];
61         struct vty *vty = priv;
62         va_list args;
63
64         va_start(args, fmt);
65         vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
66         buffer[sizeof(buffer) - 1] = '\0';
67         va_end(args);
68
69         if (buffer[0]) {
70                 if (buffer[strlen(buffer) - 1] == '\n') {
71                         buffer[strlen(buffer) - 1] = '\0';
72                         vty_out(vty, "%s%s", buffer, VTY_NEWLINE);
73                 } else
74                         vty_out(vty, "%s", buffer);
75         }
76 }
77
78 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
79 {
80         struct osmocom_ms *ms;
81
82         llist_for_each_entry(ms, &ms_list, entity) {
83                 if (!strcmp(ms->name, name))
84                         return ms;
85         }
86         vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
87
88         return NULL;
89 }
90
91 DEFUN(show_ms, show_ms_cmd, "show ms",
92         SHOW_STR "Display available MS entities\n")
93 {
94         struct osmocom_ms *ms;
95
96         llist_for_each_entry(ms, &ms_list, entity) {
97                 struct gsm_settings *set = &ms->settings;
98
99                 vty_out(vty, "MS NAME: %s%s", ms->name, VTY_NEWLINE);
100                 vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE);
101                 vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE);
102                 if (set->imei_random)
103                         vty_out(vty, " IMEI generation: random (%d trailing "
104                                 "digits)%s", set->imei_random, VTY_NEWLINE);
105                 else
106                         vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE);
107                 vty_out(vty, " network selection mode: %s%s",
108                         (set->plmn_mode == PLMN_MODE_AUTO)
109                                 ? "automatic" : "manual", VTY_NEWLINE);
110         }
111
112         return CMD_SUCCESS;
113 }
114
115 DEFUN(show_support, show_support_cmd, "show support [ms_name]",
116         SHOW_STR "Display information about MS support\n"
117         "Name of MS (see \"show ms\")")
118 {
119         struct osmocom_ms *ms;
120
121         if (argc) {
122                 ms = get_ms(argv[0], vty);
123                 if (!ms)
124                         return CMD_WARNING;
125                 gsm_support_dump(&ms->support, print_vty, vty);
126         } else {
127                 llist_for_each_entry(ms, &ms_list, entity) {
128                         gsm_support_dump(&ms->support, print_vty, vty);
129                         vty_out(vty, "%s", VTY_NEWLINE);
130                 }
131         }
132
133         return CMD_SUCCESS;
134 }
135
136 static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty)
137 {
138         struct gsm_trans *trans;
139
140         vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE);
141         if (ms->settings.plmn_mode == PLMN_MODE_AUTO)
142                 vty_out(vty, " automatic network selection: %s%s", 
143                         plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
144         else
145                 vty_out(vty, " manual network selection: %s%s", 
146                         plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
147         vty_out(vty, " cell selection: %s%s", 
148                 cs_state_names[ms->cellsel.state], VTY_NEWLINE);
149         vty_out(vty, " radio ressource layer: %s%s", 
150                 gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
151         vty_out(vty, " mobility management layer: %s", 
152                 gsm48_mm_state_names[ms->mmlayer.state]);
153         if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
154                 vty_out(vty, ", %s", 
155                         gsm48_mm_substate_names[ms->mmlayer.substate]);
156         vty_out(vty, "%s", VTY_NEWLINE);
157         llist_for_each_entry(trans, &ms->trans_list, entry) {
158                 vty_out(vty, " call control: %s%s", 
159                         gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
160         }
161 }
162
163 DEFUN(show_states, show_states_cmd, "show states [ms_name]",
164         SHOW_STR "Display current states of given MS\n"
165         "Name of MS (see \"show ms\")")
166 {
167         struct osmocom_ms *ms;
168
169         if (argc) {
170                 ms = get_ms(argv[0], vty);
171                 if (!ms)
172                         return CMD_WARNING;
173                 gsm_states_dump(ms, vty);
174         } else {
175                 llist_for_each_entry(ms, &ms_list, entity) {
176                         gsm_states_dump(ms, vty);
177                         vty_out(vty, "%s", VTY_NEWLINE);
178                 }
179         }
180
181         return CMD_SUCCESS;
182 }
183
184 DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]",
185         SHOW_STR "Display information about subscriber\n"
186         "Name of MS (see \"show ms\")")
187 {
188         struct osmocom_ms *ms;
189
190         if (argc) {
191                 ms = get_ms(argv[0], vty);
192                 if (!ms)
193                         return CMD_WARNING;
194                 gsm_subscr_dump(&ms->subscr, print_vty, vty);
195         } else {
196                 llist_for_each_entry(ms, &ms_list, entity) {
197                         gsm_subscr_dump(&ms->subscr, print_vty, vty);
198                         vty_out(vty, "%s", VTY_NEWLINE);
199                 }
200         }
201
202         return CMD_SUCCESS;
203 }
204
205 DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
206         SHOW_STR "Display information about received cells\n"
207         "Name of MS (see \"show ms\")")
208 {
209         struct osmocom_ms *ms;
210
211         ms = get_ms(argv[0], vty);
212         if (!ms)
213                 return CMD_WARNING;
214
215         gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
216                 vty);
217
218         return CMD_SUCCESS;
219 }
220
221 DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>",
222         SHOW_STR "Display information about received cell\n"
223         "Name of MS (see \"show ms\")\nRadio frequency number")
224 {
225         struct osmocom_ms *ms;
226         int i;
227         struct gsm48_sysinfo *s;
228
229         ms = get_ms(argv[0], vty);
230         if (!ms)
231                 return CMD_WARNING;
232
233         i = atoi(argv[1]);
234         if (i < 0 || i > 1023) {
235                 vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s",
236                         argv[1], VTY_NEWLINE);
237                 return CMD_WARNING;
238         }
239         s = ms->cellsel.list[i].sysinfo;
240         if (!s) {
241                 vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s",
242                         argv[1], VTY_NEWLINE);
243                 return CMD_SUCCESS;
244         }
245
246         gsm48_sysinfo_dump(s, i, print_vty, vty);
247
248         return CMD_SUCCESS;
249 }
250
251 DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]",
252         SHOW_STR "Display information about band allocations\n"
253         "Name of MS (see \"show ms\")\nMobile Country Code\n"
254         "Mobile Network Code")
255 {
256         struct osmocom_ms *ms;
257         uint16_t mcc = 0, mnc = 0;
258
259         ms = get_ms(argv[0], vty);
260         if (!ms)
261                 return CMD_WARNING;
262
263         if (argc >= 3) {
264                 mcc = gsm_input_mcc((char *)argv[1]);
265                 mnc = gsm_input_mnc((char *)argv[2]);
266                 if (!mcc) {
267                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
268                         return CMD_WARNING;
269                 }
270                 if (!mnc) {
271                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
272                         return CMD_WARNING;
273                 }
274         }
275
276         gsm322_dump_ba_list(&ms->cellsel, mcc, mnc, print_vty, vty);
277
278         return CMD_SUCCESS;
279 }
280
281 DEFUN(show_forb_plmn, show_forb_plmn_cmd, "show forbidden plmn MS_NAME",
282         SHOW_STR "Display information about forbidden cells / networks\n"
283         "Display forbidden PLMNs\nName of MS (see \"show ms\")")
284 {
285         struct osmocom_ms *ms;
286
287         ms = get_ms(argv[0], vty);
288         if (!ms)
289                 return CMD_WARNING;
290
291         gsm_subscr_dump_forbidden_plmn(ms, print_vty, vty);
292
293         return CMD_SUCCESS;
294 }
295
296 DEFUN(show_forb_la, show_forb_la_cmd, "show forbidden location-area MS_NAME",
297         SHOW_STR "Display information about forbidden cells / networks\n"
298         "Display forbidden location areas\nName of MS (see \"show ms\")")
299 {
300         struct osmocom_ms *ms;
301
302         ms = get_ms(argv[0], vty);
303         if (!ms)
304                 return CMD_WARNING;
305
306         gsm322_dump_forbidden_la(ms, print_vty, vty);
307
308         return CMD_SUCCESS;
309 }
310
311 DEFUN(monitor_network, monitor_network_cmd, "monitor network MS_NAME",
312         "Monitor...\nMonitor network information\nName of MS (see \"show ms\")")
313 {
314         struct osmocom_ms *ms;
315
316         ms = get_ms(argv[0], vty);
317         if (!ms)
318                 return CMD_WARNING;
319
320         gsm48_rr_start_monitor(ms);
321
322         return CMD_SUCCESS;
323 }
324
325 DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME",
326         NO_STR "Monitor...\nDeactivate monitor of network information\n"
327         "Name of MS (see \"show ms\")")
328 {
329         struct osmocom_ms *ms;
330
331         ms = get_ms(argv[0], vty);
332         if (!ms)
333                 return CMD_WARNING;
334
335         gsm48_rr_stop_monitor(ms);
336
337         return CMD_SUCCESS;
338 }
339
340 DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]",
341         "SIM actions\nInsert test card\nName of MS (see \"show ms\")\n"
342         "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN")
343 {
344         struct osmocom_ms *ms;
345         uint16_t mcc = 0x001, mnc = 0x01f;
346
347         ms = get_ms(argv[0], vty);
348         if (!ms)
349                 return CMD_WARNING;
350
351         if (ms->subscr.sim_valid) {
352                 vty_out(vty, "Sim already presend, remove first!%s",
353                         VTY_NEWLINE);
354                 return CMD_WARNING;
355         }
356
357         if (argc >= 3) {
358                 mcc = gsm_input_mcc((char *)argv[1]);
359                 mnc = gsm_input_mnc((char *)argv[2]);
360                 if (!mcc) {
361                         vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
362                         return CMD_WARNING;
363                 }
364                 if (!mnc) {
365                         vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
366                         return CMD_WARNING;
367                 }
368         }
369
370         gsm_subscr_testcard(ms, mcc, mnc);
371
372         return CMD_SUCCESS;
373 }
374
375 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
376         "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")")
377 {
378         struct osmocom_ms *ms;
379
380         ms = get_ms(argv[0], vty);
381         if (!ms)
382                 return CMD_WARNING;
383
384         if (!ms->subscr.sim_valid) {
385                 vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
386                 return CMD_WARNING;
387         }
388
389         gsm_subscr_remove(ms);
390
391         return CMD_SUCCESS;
392 }
393
394 DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
395         "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
396         "Mobile Country Code\nMobile Network Code")
397 {
398         struct osmocom_ms *ms;
399         struct gsm322_plmn *plmn;
400         struct msgb *nmsg;
401         struct gsm322_msg *ngm;
402         struct gsm322_plmn_list *temp;
403         uint16_t mcc = gsm_input_mcc((char *)argv[1]),
404                  mnc = gsm_input_mnc((char *)argv[2]);
405         int found = 0;
406
407         ms = get_ms(argv[0], vty);
408         if (!ms)
409                 return CMD_WARNING;
410         plmn = &ms->plmn;
411
412         if (!mcc) {
413                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
414                 return CMD_WARNING;
415         }
416         if (!mnc) {
417                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
418                 return CMD_WARNING;
419         }
420
421         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
422                 if (temp->mcc == mcc &&  temp->mnc == mnc)
423                         found = 1;
424         if (!found) {
425                 vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
426                 return CMD_WARNING;
427         }
428
429         nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
430         if (!nmsg)
431                 return CMD_WARNING;
432         ngm = (struct gsm322_msg *) nmsg->data;
433         ngm->mcc = mcc;
434         ngm->mnc = mnc;
435         gsm322_plmn_sendmsg(ms, nmsg);
436
437         return CMD_SUCCESS;
438 }
439
440 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
441         "Make a call\nName of MS (see \"show ms\")\nPhone number to call\n"
442         "Make an emergency call\nAnswer an incomming call\nHangup a call\n"
443         "Hold current active call\n")
444 {
445         struct osmocom_ms *ms;
446
447         ms = get_ms(argv[0], vty);
448         if (!ms)
449                 return CMD_WARNING;
450
451         switch (argv[1][0]) {
452         case 'a':
453                 mncc_answer(ms);
454                 break;
455         case 'h':
456                 if (argv[1][1] == 'a')
457                         mncc_hangup(ms);
458                 else
459                         mncc_hold(ms);
460                 break;
461         default:
462                 mncc_call(ms, (char *)argv[1]);
463         }
464
465         return CMD_SUCCESS;
466 }
467
468 DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]",
469         "Make a call\nName of MS (see \"show ms\")\n"
470         "Retrieve call on hold\nNumber of call to retrieve")
471 {
472         struct osmocom_ms *ms;
473
474         ms = get_ms(argv[0], vty);
475         if (!ms)
476                 return CMD_WARNING;
477
478         mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
479
480         return CMD_SUCCESS;
481 }
482
483 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
484         "Network ...\nShow results of network search (again)\n"
485         "Name of MS (see \"show ms\")")
486 {
487         struct osmocom_ms *ms;
488         struct gsm322_plmn *plmn;
489         struct gsm322_plmn_list *temp;
490
491         ms = get_ms(argv[0], vty);
492         if (!ms)
493                 return CMD_WARNING;
494         plmn = &ms->plmn;
495
496         if (ms->settings.plmn_mode != PLMN_MODE_AUTO
497          && plmn->state != GSM322_M3_NOT_ON_PLMN) {
498                 vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
499                 return CMD_WARNING;
500         }
501
502         llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
503                 vty_out(vty, " Network %s, %s (%s, %s)%s",
504                         gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
505                         gsm_get_mcc(temp->mcc),
506                         gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
507
508         return CMD_SUCCESS;
509 }
510
511 DEFUN(network_search, network_search_cmd, "network search MS_NAME",
512         "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
513 {
514         struct osmocom_ms *ms;
515         struct msgb *nmsg;
516
517         ms = get_ms(argv[0], vty);
518         if (!ms)
519                 return CMD_WARNING;
520
521         nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
522         if (!nmsg)
523                 return CMD_WARNING;
524         gsm322_plmn_sendmsg(ms, nmsg);
525
526         return CMD_SUCCESS;
527 }
528
529 /* per MS config */
530 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
531         "Select a mobile station to configure\nName of MS (see \"show ms\")")
532 {
533         struct osmocom_ms *ms;
534
535         ms = get_ms(argv[0], vty);
536         if (!ms)
537                 return CMD_WARNING;
538
539         vty->index = ms;
540         vty->node = MS_NODE;
541
542         return CMD_SUCCESS;
543 }
544
545 static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
546 {
547         struct gsm_settings *set = &ms->settings;
548
549         vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
550         switch(set->simtype) {
551                 case GSM_SIM_TYPE_NONE:
552                 vty_out(vty, " sim none%s", VTY_NEWLINE);
553                 break;
554                 case GSM_SIM_TYPE_SLOT:
555                 vty_out(vty, " sim slot%s", VTY_NEWLINE);
556                 break;
557                 case GSM_SIM_TYPE_TEST:
558                 vty_out(vty, " sim test%s", VTY_NEWLINE);
559                 break;
560         }
561         vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
562                         == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
563         vty_out(vty, " imei %s %s%s", set->imei,
564                 set->imeisv + strlen(set->imei), VTY_NEWLINE);
565         if (set->imei_random)
566                 vty_out(vty, " imei-random %d%s", set->imei_random,
567                         VTY_NEWLINE);
568         else
569                 vty_out(vty, " imei-fixed%s", VTY_NEWLINE);
570         if (set->emergency_imsi[0])
571                 vty_out(vty, " emergency-imsi %s%s", set->emergency_imsi,
572                         VTY_NEWLINE);
573         else
574                 vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE);
575         vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE);
576         vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE);
577         vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE);
578         vty_out(vty, " test-sim%s", VTY_NEWLINE);
579         vty_out(vty, "  imsi %s%s", set->test_imsi, VTY_NEWLINE);
580         vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
581                 VTY_NEWLINE);
582         if (set->test_rplmn_valid)
583                 vty_out(vty, "  rplmn %s %s%s",
584                         gsm_print_mcc(set->test_rplmn_mcc),
585                         gsm_print_mnc(set->test_rplmn_mnc),
586                         VTY_NEWLINE);
587         else
588                 vty_out(vty, "  no rplmn%s", VTY_NEWLINE);
589         vty_out(vty, "  hplmn-search %s%s", (set->test_always) ? "everywhere"
590                         : "foreign-country", VTY_NEWLINE);
591         vty_out(vty, " exit%s", VTY_NEWLINE);
592         if (set->alter_tx_power)
593                 if (set->alter_tx_power_value)
594                         vty_out(vty, " tx-power %d%s",
595                                 set->alter_tx_power_value, VTY_NEWLINE);
596                 else
597                         vty_out(vty, " tx-power full%s", VTY_NEWLINE);
598         else
599                 vty_out(vty, " tx-power auto%s", VTY_NEWLINE);
600         if (set->alter_delay)
601                 vty_out(vty, " simulated-delay %d%s", set->alter_delay,
602                         VTY_NEWLINE);
603         else
604                 vty_out(vty, " no simulated-delay%s", VTY_NEWLINE);
605         if (set->stick)
606                 vty_out(vty, " stick %d%s", set->stick_arfcn,
607                         VTY_NEWLINE);
608         else
609                 vty_out(vty, " no stick%s", VTY_NEWLINE);
610         if (set->no_lupd)
611                 vty_out(vty, " no location-updating%s", VTY_NEWLINE);
612         else
613                 vty_out(vty, " location-updating%s", VTY_NEWLINE);
614         vty_out(vty, "exit%s", VTY_NEWLINE);
615         vty_out(vty, "!%s", VTY_NEWLINE);
616 }
617
618 static int config_write_ms(struct vty *vty)
619 {
620         struct osmocom_ms *ms;
621
622         llist_for_each_entry(ms, &ms_list, entity)
623                 config_write_ms_single(vty, ms);
624
625         return CMD_SUCCESS;
626 }
627
628 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|test)",
629         "Set sim card type when powering on\nNo sim interted\n"
630         "Test sim inserted")
631 {
632         struct osmocom_ms *ms = vty->index;
633
634         switch (argv[0][0]) {
635         case 'n':
636                 ms->settings.simtype = GSM_SIM_TYPE_NONE;
637                 break;
638         case 's':
639                 ms->settings.simtype = GSM_SIM_TYPE_SLOT;
640                 break;
641         case 't':
642                 ms->settings.simtype = GSM_SIM_TYPE_TEST;
643                 break;
644         }
645
646         return CMD_SUCCESS;
647 }
648
649 DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
650         "Set network selection mode\nAutomatic network selection\n"
651         "Manual network selection")
652 {
653         struct osmocom_ms *ms = vty->index;
654         struct msgb *nmsg;
655
656         if (!ms->plmn.state) {
657                 if (argv[0][0] == 'a')
658                         ms->settings.plmn_mode = PLMN_MODE_AUTO;
659                 else
660                         ms->settings.plmn_mode = PLMN_MODE_MANUAL;
661
662                 return CMD_SUCCESS;
663         }
664         if (argv[0][0] == 'a')
665                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
666         else
667                 nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
668         if (!nmsg)
669                 return CMD_WARNING;
670         gsm322_plmn_sendmsg(ms, nmsg);
671
672         return CMD_SUCCESS;
673 }
674
675 DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
676         "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
677         "Software version digit")
678 {
679         struct osmocom_ms *ms = vty->index;
680         char *error, *sv = "0";
681
682         if (argc >= 2)
683                 sv = (char *)argv[1];
684
685         error = gsm_check_imei(argv[0], sv);
686         if (error) {
687                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
688                 return CMD_WARNING;
689         }
690
691         strcpy(ms->settings.imei, argv[0]);
692         strcpy(ms->settings.imeisv, argv[0]);
693         strcpy(ms->settings.imeisv + 15, sv);
694
695         return CMD_SUCCESS;
696 }
697
698 DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
699         "Use fixed IMEI on every power on")
700 {
701         struct osmocom_ms *ms = vty->index;
702
703         ms->settings.imei_random = 0;
704
705         return CMD_SUCCESS;
706 }
707
708 DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
709         "Use random IMEI on every power on\n"
710         "Number of trailing digits to randomize")
711 {
712         struct osmocom_ms *ms = vty->index;
713
714         ms->settings.imei_random = atoi(argv[0]);
715
716         return CMD_SUCCESS;
717 }
718
719 DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi IMSI",
720         "Use special IMSI for emergency calls\n15 digits IMSI")
721 {
722         struct osmocom_ms *ms = vty->index;
723         char *error;
724
725         error = gsm_check_imsi(argv[0]);
726         if (error) {
727                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
728                 return CMD_WARNING;
729         }
730         strcpy(ms->settings.emergency_imsi, argv[0]);
731
732         return CMD_SUCCESS;
733 }
734
735 DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
736         NO_STR "Use IMSI of SIM or IMEI for emergency calls")
737 {
738         struct osmocom_ms *ms = vty->index;
739
740         ms->settings.emergency_imsi[0] = '\0';
741
742         return CMD_SUCCESS;
743 }
744
745 DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
746         NO_STR "Disallow waiting calls")
747 {
748         struct osmocom_ms *ms = vty->index;
749
750         ms->settings.cw = 0;
751
752         return CMD_SUCCESS;
753 }
754
755 DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
756         "Allow waiting calls")
757 {
758         struct osmocom_ms *ms = vty->index;
759
760         ms->settings.cw = 1;
761
762         return CMD_SUCCESS;
763 }
764
765 DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
766         "Force caller ID presentation")
767 {
768         struct osmocom_ms *ms = vty->index;
769
770         ms->settings.clip = 1;
771         ms->settings.clir = 0;
772
773         return CMD_SUCCESS;
774 }
775
776 DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
777         "Force caller ID restriction")
778 {
779         struct osmocom_ms *ms = vty->index;
780
781         ms->settings.clip = 0;
782         ms->settings.clir = 1;
783
784         return CMD_SUCCESS;
785 }
786
787 DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
788         NO_STR "Disable forcing of caller ID presentation")
789 {
790         struct osmocom_ms *ms = vty->index;
791
792         ms->settings.clip = 0;
793
794         return CMD_SUCCESS;
795 }
796
797 DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
798         NO_STR "Disable forcing of caller ID restriction")
799 {
800         struct osmocom_ms *ms = vty->index;
801
802         ms->settings.clir = 0;
803
804         return CMD_SUCCESS;
805 }
806
807 DEFUN(cfg_ms_tx_power, cfg_ms_tx_power_cmd, "tx-power (auto|full)",
808         "Set the way to choose transmit power\nControlled by BTS\n"
809         "Always full power\nFixed GSM power value if supported")
810 {
811         struct osmocom_ms *ms = vty->index;
812
813         switch (argv[0][0]) {
814         case 'a':
815                 ms->settings.alter_tx_power = 0;
816                 break;
817         case 'f':
818                 ms->settings.alter_tx_power = 1;
819                 ms->settings.alter_tx_power_value = 0;
820                 break;
821         }
822
823         return CMD_SUCCESS;
824 }
825
826 DEFUN(cfg_ms_tx_power_val, cfg_ms_tx_power_val_cmd, "tx-power <0-31>",
827         "Set the way to choose transmit power\n"
828         "Fixed GSM power value if supported")
829 {
830         struct osmocom_ms *ms = vty->index;
831
832         ms->settings.alter_tx_power = 1;
833         ms->settings.alter_tx_power_value = atoi(argv[0]);
834
835         return CMD_SUCCESS;
836 }
837
838 DEFUN(cfg_ms_sim_delay, cfg_ms_sim_delay_cmd, "simulated-delay <-128-127>",
839         "Simulate a lower or higher distance from the BTS\n"
840         "Delay in half bits (distance in 553.85 meter steps)")
841 {
842         struct osmocom_ms *ms = vty->index;
843
844         ms->settings.alter_delay = atoi(argv[0]);
845
846         return CMD_SUCCESS;
847 }
848
849 DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
850         NO_STR "Do not simulate a lower or higher distance from the BTS")
851 {
852         struct osmocom_ms *ms = vty->index;
853
854         ms->settings.alter_delay = 0;
855
856         return CMD_SUCCESS;
857 }
858
859 DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023>",
860         "Stick to the given cell\nARFCN of the cell to stick to")
861 {
862         struct osmocom_ms *ms = vty->index;
863
864         ms->settings.stick = 1;
865         ms->settings.stick_arfcn = atoi(argv[0]);
866
867         return CMD_SUCCESS;
868 }
869
870 DEFUN(cfg_ms_no_stick, cfg_ms_no_stick_cmd, "no stick",
871         NO_STR "Do not stick to any cell")
872 {
873         struct osmocom_ms *ms = vty->index;
874
875         ms->settings.stick = 0;
876
877         return CMD_SUCCESS;
878 }
879
880 DEFUN(cfg_ms_lupd, cfg_ms_lupd_cmd, "location-updating",
881         "Allow location updating")
882 {
883         struct osmocom_ms *ms = vty->index;
884
885         ms->settings.no_lupd = 0;
886
887         return CMD_SUCCESS;
888 }
889
890 DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating",
891         NO_STR "Do not allow location updating")
892 {
893         struct osmocom_ms *ms = vty->index;
894
895         ms->settings.no_lupd = 1;
896
897         return CMD_SUCCESS;
898 }
899
900 /* per testsim config */
901 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
902         "Configure test SIM emulation")
903 {
904         vty->node = TESTSIM_NODE;
905
906         return CMD_SUCCESS;
907 }
908
909 static int config_write_dummy(struct vty *vty)
910 {
911         return CMD_SUCCESS;
912 }
913
914 DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
915         "Set IMSI on test card\n15 digits IMSI")
916 {
917         struct osmocom_ms *ms = vty->index;
918         char *error = gsm_check_imsi(argv[0]);
919
920         if (error) {
921                 vty_out(vty, "%s%s", error, VTY_NEWLINE);
922                 return CMD_WARNING;
923         }
924
925         strcpy(ms->settings.test_imsi, argv[0]);
926
927         return CMD_SUCCESS;
928 }
929
930 DEFUN(cfg_test_barr, cfg_test_barr_cmd, "barred-access",
931         "Allow access to barred cells")
932 {
933         struct osmocom_ms *ms = vty->index;
934
935         ms->settings.test_barr = 1;
936
937         return CMD_SUCCESS;
938 }
939
940 DEFUN(cfg_test_no_barr, cfg_test_no_barr_cmd, "no barred-access",
941         NO_STR "Deny access to barred cells")
942 {
943         struct osmocom_ms *ms = vty->index;
944
945         ms->settings.test_barr = 0;
946
947         return CMD_SUCCESS;
948 }
949
950 DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
951         NO_STR "Unset Registered PLMN")
952 {
953         struct osmocom_ms *ms = vty->index;
954
955         ms->settings.test_rplmn_valid = 0;
956
957         return CMD_SUCCESS;
958 }
959
960 DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC",
961         "Set Registered PLMN\nMobile Country Code\nMobile Network Code")
962 {
963         struct osmocom_ms *ms = vty->index;
964         uint16_t mcc = gsm_input_mcc((char *)argv[0]),
965                  mnc = gsm_input_mnc((char *)argv[1]);
966
967         if (!mcc) {
968                 vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
969                 return CMD_WARNING;
970         }
971         if (!mnc) {
972                 vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
973                 return CMD_WARNING;
974         }
975         ms->settings.test_rplmn_valid = 1;
976         ms->settings.test_rplmn_mcc = mcc;
977         ms->settings.test_rplmn_mnc = mnc;
978
979         return CMD_SUCCESS;
980 }
981
982 DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-country)",
983         "Set Home PLMN search mode\n"
984         "Search for HPLMN when on any other network\n"
985         "Search for HPLMN when in a different country")
986 {
987         struct osmocom_ms *ms = vty->index;
988
989         switch (argv[0][0]) {
990         case 'e':
991                 ms->settings.test_always = 1;
992                 break;
993         case 'f':
994                 ms->settings.test_always = 0;
995                 break;
996         }
997
998         return CMD_SUCCESS;
999 }
1000
1001 enum node_type ms_vty_go_parent(struct vty *vty)
1002 {
1003         switch (vty->node) {
1004         case MS_NODE:
1005                 vty->node = CONFIG_NODE;
1006                 vty->index = NULL;
1007                 break;
1008         case TESTSIM_NODE:
1009                 vty->node = MS_NODE;
1010                 break;
1011         default:
1012                 vty->node = CONFIG_NODE;
1013         }
1014
1015         return vty->node;
1016 }
1017
1018 /* Down vty node level. */
1019 gDEFUN(ournode_exit,
1020        ournode_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
1021 {
1022         switch (vty->node) {
1023         case MS_NODE:
1024                 vty->node = CONFIG_NODE;
1025                 vty->index = NULL;
1026                 break;
1027         case TESTSIM_NODE:
1028                 vty->node = MS_NODE;
1029                 break;
1030         default:
1031                 break;
1032         }
1033         return CMD_SUCCESS;
1034 }
1035
1036 /* End of configuration. */
1037 gDEFUN(ournode_end,
1038        ournode_end_cmd, "end", "End current mode and change to enable mode.")
1039 {
1040         switch (vty->node) {
1041         case VIEW_NODE:
1042         case ENABLE_NODE:
1043                 /* Nothing to do. */
1044                 break;
1045         case CONFIG_NODE:
1046         case VTY_NODE:
1047         case MS_NODE:
1048         case TESTSIM_NODE:
1049                 vty_config_unlock(vty);
1050                 vty->node = ENABLE_NODE;
1051                 vty->index = NULL;
1052                 vty->index_sub = NULL;
1053                 break;
1054         default:
1055                 break;
1056         }
1057         return CMD_SUCCESS;
1058 }
1059
1060 int ms_vty_init(void)
1061 {
1062         install_element_ve(&show_ms_cmd);
1063         install_element_ve(&show_subscr_cmd);
1064         install_element_ve(&show_support_cmd);
1065         install_element_ve(&show_states_cmd);
1066         install_element_ve(&show_cell_cmd);
1067         install_element_ve(&show_cell_si_cmd);
1068         install_element_ve(&show_ba_cmd);
1069         install_element_ve(&show_forb_la_cmd);
1070         install_element_ve(&show_forb_plmn_cmd);
1071         install_element_ve(&monitor_network_cmd);
1072         install_element_ve(&no_monitor_network_cmd);
1073
1074         install_element(ENABLE_NODE, &sim_test_cmd);
1075         install_element(ENABLE_NODE, &sim_remove_cmd);
1076         install_element(ENABLE_NODE, &network_search_cmd);
1077         install_element(ENABLE_NODE, &network_show_cmd);
1078         install_element(ENABLE_NODE, &network_select_cmd);
1079         install_element(ENABLE_NODE, &call_cmd);
1080         install_element(ENABLE_NODE, &call_retr_cmd);
1081
1082         install_element(CONFIG_NODE, &cfg_ms_cmd);
1083         install_element(CONFIG_NODE, &ournode_end_cmd);
1084         install_node(&ms_node, config_write_ms);
1085         install_default(MS_NODE);
1086         install_element(MS_NODE, &ournode_exit_cmd);
1087         install_element(MS_NODE, &ournode_end_cmd);
1088         install_element(MS_NODE, &cfg_ms_sim_cmd);
1089         install_element(MS_NODE, &cfg_ms_mode_cmd);
1090         install_element(MS_NODE, &cfg_ms_imei_cmd);
1091         install_element(MS_NODE, &cfg_ms_imei_fixed_cmd);
1092         install_element(MS_NODE, &cfg_ms_imei_random_cmd);
1093         install_element(MS_NODE, &cfg_ms_no_emerg_imsi_cmd);
1094         install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
1095         install_element(MS_NODE, &cfg_ms_cw_cmd);
1096         install_element(MS_NODE, &cfg_ms_no_cw_cmd);
1097         install_element(MS_NODE, &cfg_ms_clip_cmd);
1098         install_element(MS_NODE, &cfg_ms_clir_cmd);
1099         install_element(MS_NODE, &cfg_ms_no_clip_cmd);
1100         install_element(MS_NODE, &cfg_ms_no_clir_cmd);
1101         install_element(MS_NODE, &cfg_ms_testsim_cmd);
1102         install_element(MS_NODE, &cfg_ms_tx_power_cmd);
1103         install_element(MS_NODE, &cfg_ms_tx_power_val_cmd);
1104         install_element(MS_NODE, &cfg_ms_sim_delay_cmd);
1105         install_element(MS_NODE, &cfg_ms_no_sim_delay_cmd);
1106         install_element(MS_NODE, &cfg_ms_stick_cmd);
1107         install_element(MS_NODE, &cfg_ms_no_stick_cmd);
1108         install_element(MS_NODE, &cfg_ms_lupd_cmd);
1109         install_element(MS_NODE, &cfg_ms_no_lupd_cmd);
1110
1111         install_node(&testsim_node, config_write_dummy);
1112         install_default(TESTSIM_NODE);
1113         install_element(TESTSIM_NODE, &ournode_exit_cmd);
1114         install_element(TESTSIM_NODE, &ournode_end_cmd);
1115         install_element(TESTSIM_NODE, &cfg_test_imsi_cmd);
1116         install_element(TESTSIM_NODE, &cfg_test_barr_cmd);
1117         install_element(TESTSIM_NODE, &cfg_test_no_barr_cmd);
1118         install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd);
1119         install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd);
1120         install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd);
1121
1122         return 0;
1123 }
1124
1125 void vty_notify(struct osmocom_ms *ms, const char *fmt, ...)
1126 {
1127         struct telnet_connection *connection;
1128         char buffer[1000];
1129         va_list args;
1130         struct vty *vty;
1131
1132         if (fmt) {
1133                 va_start(args, fmt);
1134                 vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
1135                 buffer[sizeof(buffer) - 1] = '\0';
1136                 va_end(args);
1137
1138                 if (!buffer[0])
1139                         return;
1140         }
1141
1142         llist_for_each_entry(connection, &active_connections, entry) {
1143                 vty = connection->vty;
1144                 if (!vty)
1145                         continue;
1146                 if (!fmt) {
1147                         vty_out(vty, "%s%% (MS %s)%s", VTY_NEWLINE, ms->name,
1148                                 VTY_NEWLINE);
1149                         continue;
1150                 }
1151                 if (buffer[strlen(buffer) - 1] == '\n') {
1152                         buffer[strlen(buffer) - 1] = '\0';
1153                         vty_out(vty, "%% %s%s", buffer, VTY_NEWLINE);
1154                         buffer[strlen(buffer)] = '\n';
1155                 } else
1156                         vty_out(vty, "%% %s", buffer);
1157         }
1158 }
1159