/* DESC: This script will scan Mobile2 and dial the appropriate SIM on Mobile1 * Copyright (C) 2013 NetModule AG, Switzerland * */ template operator { prio; sim; lai; apn; username; password; int operator (int p, int s, string l, string a, string usr, string pwd) { this.prio = p; this.sim = s; this.lai = l; this.apn = a; this.username = usr; this.password = pwd; return 0; } }; ME = argv[0]; /* script path */ ARGV1 = argv[1]; /* 1st script argument */ FORCE = 0; /* force operator switch even if wanlink is up */ VALID_ONLY = 1; /* only register to networks which are allowed by SIM */ SCAN_INTERVAL = 30; /* network scan interval in seconds */ TEST = 0; /* run test */ /* example list of operators */ OPCNT = 0; OPERATORS = mkarray(); OPERATORS[OPCNT++] = new operator (1, /* prio */ 0, /* SIM1 */ "22801", /* lai */ "corporate.swisscom.ch", /* apn */ "testprofil", /* username */ "temporary" /* password */ ); OPERATORS[OPCNT++] = new operator (2, /* prio */ 1, /* SIM2 */ "22802", /* lai */ "internet", /* apn */ "internet", /* username */ "internet" /* password */ ); OPERATORS[OPCNT++] = new operator (3, /* prio */ 2, /* EXT1 */ "26201", /* lai */ "internet.telekom", /* apn */ "tm", /* username */ "" /* password */ ); /* creates file at path */ int touch (string path) { fd = open(path, O_CREAT | O_WRONLY); if (fd < 0) return -1; close(fd); return 0; } /* checks if path exists */ int exists (string path) { fd = open(path, O_RDONLY); if (fd < 0) return 0; close(fd); return 1; } /* copies a file */ int copy (string from, string to) { fpin = fopen(from, "r"); if (is_void(fpin)) { nb_syslog("unable to open %s", from); return -1; } fpout = fopen(to, "w+"); if (is_void(fpout)) { fclose(fpin); nb_syslog("unable to open %s", to); return -1; } while (1) { buf = fread(fpin, 1024); if (is_void(buf)) break; len = strlen(buf); if (len == 0) break; fwrite(fpout, buf, len); } fclose(fpin); fclose(fpout); return 0; } /* mkdir -p */ int makedir (string path, int mode) { pc = explode(path); if (pc[0] != "/") { nb_syslog("no absolute directory given"); return -1; } len = length(pc); if (pc[len-1] != "/") pc[len++] = "/"; p = ""; for (i = 0; i < len; i++) { if (pc[i] == "/" && i > 0) { mkdir(p, mode); } p = strcat(p, pc[i]); } return 0; } /* returns operator index for specified lai */ int find_operator (string lai) { if (lai != "") { /* search by lai first */ for (o = 0; o < OPCNT; o++) { if (OPERATORS[o].lai == lai) return o; } } return -1; /* not a known operator */ } /* returns wwan interface index for specified sim index */ int find_wwan_interface (int sim) { for (o = 0; o < OPCNT; o++) { op = OPERATORS[o]; if (op.sim == sim) { return o; } } return -1; /* no wwan interface with this sim */ } /* returns current wwan interface index */ int current_operator () { n = nb_config_get("wanlink.0.name"); if (strlen(n) >= 5 && left(n, 4) == "wwan") { return (int)substr(n, 4, 1); } return -1; /* not configured */ } /* activates specified operator */ int activate_operator (int op) { current = current_operator(); if (current != -1 && current == op) { nb_syslog("wwan%d is already active", op); return 0; } nb_syslog("switching to wwan%d", op); if (nb_config_set(sprintf("wanlink.0.name=wwan%d", op)) != 0) { nb_syslog("unable to activate wwan%d", op); return -1; } /* re-configuration triggered */ nb_syslog("activated wwan%d", op); /* give modem some time to register */ nb_syslog("waiting for wwan%d to come up", op); sleep(30); /* needed for SIM switch */ /* wait for wanlink to come up */ for (i = 0; i < 20; i++) { sleep(10); nb_syslog("checking if wwan%d has come up", op); st = nb_status("wan"); ifc = struct_get(st, "WANLINK1_INTERFACE"); if (ifc != sprintf("WWAN%d", op+1)) { nb_syslog("wwan%d is not yet active"); continue; } state = struct_get(st, "WANLINK1_STATE"); if (state == "up") { nb_syslog("wwan%d is up now", op); return 0; } attempts = (int) struct_get(st, "WANLINK1_DIAL_ATTEMPTS"); nb_syslog("wwan%d has dialed for %d times", op, attempts); if (attempts > 2) { nb_syslog("giving up after %d dial attempts", attempts); return -1; } } nb_syslog("giving up waiting for wanlink"); return 0; } /* returns true if wanlink is up */ bool wanup () { st = nb_status("wan"); state = struct_get(st, "WANLINK1_STATE"); return (state == "up"); } /* scan test */ struct nb_scan_test () { return mkstruct( "NETWORK_COUNT", 2, "NETWORK1_NAME", "swisscom", "NETWORK1_LAI", "22801", "NETWORK1_STATUS", "available", "NETWORK2_NAME", "telekom", "NETWORK2_LAI", "26201", "NETWORK2_STATUS", "available" ); } /* installs config and script */ int install () { path = "/config"; cfg = sprintf("%s/user-config.cfg", path); makedir(sprintf("%s/files", path), S_IRUSR|S_IWUSR|S_IXUSR); touch(cfg); fp = fopen(cfg, "w"); if (!fp) { printf("ERROR: unable to open %s\n", cfg); return -1; } /* basic system config */ fwrite(fp, "config.version=1.3\n"); fwrite(fp, sprintf("admin.password=%s\n", nb_config_get("admin.password"))); /* set up OPERATORS */ for (o = 0; o < OPCNT; o++) { op = OPERATORS[o]; fwrite(fp, sprintf("sim.%d.lai=%s\n", op.sim, op.lai)); fwrite(fp, sprintf("wwan.%d.status=1\n", o)); fwrite(fp, sprintf("wwan.%d.card=0\n", o)); /* force wwan0 */ fwrite(fp, sprintf("wwan.%d.sim=%d\n", o, op.sim)); fwrite(fp, sprintf("wwan.%d.number=*99***1#\n", o)); fwrite(fp, sprintf("wwan.%d.username=%s\n", o, op.usename)); fwrite(fp, sprintf("wwan.%d.password=%s\n", o, op.password)); fwrite(fp, sprintf("wwan.%d.apn=%s\n", o, op.apn)); } /* enable first wwan interface */ fwrite(fp, "wanlink.0.name=wwan0\n"); fwrite(fp, "wanlink.0.prio=1\n"); fwrite(fp, "wanlink.0.weight=0\n"); fwrite(fp, "wanlink.0.mode=1\n"); /* install this script */ fwrite(fp, "sdk.status=1\n"); fwrite(fp, "sdk.trigger.0.name=SDK-STARTUP\n"); fwrite(fp, "sdk.trigger.0.event=sdk-startup\n"); fwrite(fp, "sdk.script.0.name=dynamic-operator\n"); fwrite(fp, "sdk.job.0.name=DYNAMIC-OPERATOR\n"); fwrite(fp, "sdk.job.0.trigger=0\n"); fwrite(fp, "sdk.job.0.script=0\n"); scriptpath = sprintf("%s/files/home/sdk/scripts/uploaded", path); makedir(scriptpath, S_IRUSR|S_IWUSR|S_IXUSR); fclose(fp); if (copy(ME, sprintf("%s/dynamic-operator", scriptpath)) != 0) { printf("ERROR: cannot copy script"); return -1; } return nb_update_config(sprintf("dir://%s", path)); } /* -------------------------------- main -------------------------------- */ nb_syslog("starting %s", ME); if (ARGV1 == "install") { /* script installation requested */ printf("installing script and its config\n"); if (install() != 0) { printf("unable to install script\n"); exit(1); } else { printf("successfully installed script\n"); } /* script will terminate at this point */ exit(0); } /* re-read operators */ OPCNT = 0; OPERATORS = mkarray(); for (i = 0; i < 14; i++) { status = nb_config_get(sprintf("wwan.%d.status", i)); if (status != "1") { continue; } sim = nb_config_get(sprintf("wwan.%d.sim", i)); if (sim < 0) { nb_syslog("invalid sim for wwan%d", i); continue; } lai = nb_config_get(sprintf("sim.%d.lai", sim)); OPERATORS[OPCNT].prio = i; OPERATORS[OPCNT].lai = lai; OPERATORS[OPCNT].sim = sim; OPERATORS[OPCNT].username = nb_config_get(sprintf("wwan.%d.username", i)); OPERATORS[OPCNT].password = nb_config_get(sprintf("wwan.%d.password", i)); OPERATORS[OPCNT].apn = nb_config_get(sprintf("wwan.%d.apn", i)); nb_syslog("added operator%d (prio %d, sim %d, lai %s)", OPCNT, i, sim, lai); OPCNT++; } while (1) { nb_syslog("sleeping"); sleep(SCAN_INTERVAL); /* get wanlink state */ up = wanup(); if (up) { nb_syslog("wanlink is up"); } else { nb_syslog("wanlink is down"); } /* get current operator */ current = current_operator(); if (current != -1) { nb_syslog("current is wwan%d", current); } if (up && current != -1) { nb_syslog("wwan%d is up", current); if (FORCE != 1) continue; } /* scan networks */ nb_syslog("scanning networks"); if (TEST == 1) { nets = nb_scan_test(); } else { nets = nb_scan_networks("Mobile2"); } nr_nets = struct_get(nets, "NETWORK_COUNT"); if (is_void(nr_nets) || nr_nets < 1) { nb_syslog("no networks found"); continue; } nb_syslog("%d networks found", nr_nets); best = -1; prio = -1; for (i = 1; i <= nr_nets; i++) { net = trim(struct_get(nets, sprintf("NETWORK%d_NAME", i))); lai = trim(struct_get(nets, sprintf("NETWORK%d_LAI", i))); status = trim(struct_get(nets, sprintf("NETWORK%d_STATUS", i))); nb_syslog("detected network '%s' (lai %s, status %s)", net, lai, status); if (VALID_ONLY == 1 && status != "available") continue; op = find_operator(lai, net); if (op == -1) { nb_syslog("network '%s' does not belong to a known operator", net); continue; } if (current != -1 && op == current) { /* skip current operator */ continue; } if (prio == -1 || OPERATORS[op].prio < prio) { best = op; prio = OPERATORS[op].prio; } } if (best != -1) { /* activate best operator */ activate_operator(best); } else { nb_syslog("no better operator found"); } } exit(0);