add template-configs, script to launch network

This is the set of scripts I've written for myself over the years to easily
configure and run Osmocom core networks on my lab computer. I hope this will be
useful to others as well.
diff --git a/README b/README
index 2b441db..d6ce60e 100644
--- a/README
+++ b/README
@@ -1,3 +1,12 @@
+=== WHAT IS THIS?
+
+* quickly build the entire Osmocom core network stack from source, with a
+  generated top-level makefile (see the rest of this README file below).
+
+* quickly configure, launch and tear down an entire Osmocom core network on
+  your box (see net/README).
+
+
 === Quick Start
 
 sudo apt install \
diff --git a/net/README b/net/README
new file mode 100644
index 0000000..a7b344f
--- /dev/null
+++ b/net/README
@@ -0,0 +1,106 @@
+=== WHAT IS THIS?
+
+* quickly configure, launch and tear down an entire Osmocom core network on
+  your box (see net/README).
+
+This is the set of tools I wrote for myself and use every day to run and test
+the Osmocom core network. I hope this helps, and I would appreciate
+contributions of any improvements you may have!
+
+
+=== Quick Start
+
+cp config_2g3g config_mine
+$EDITOR config_mine
+# update IP addresses and device names as required
+
+mkdir my_network
+cd my_network
+../cfg.sh ../config_mine ../tmpl_std
+
+./run.sh
+# Launches numerous x-terminals with one component running in each.
+# Logs and pcap traces are being taken automatically.
+
+# hit enter in the original first terminal to tear down all programs.
+# Enter a name to save logs, otherwise all logging will be stored
+# under autolog/<timestamp>
+
+Then possibly modify the config and refresh:
+
+# tweak config?
+$EDITOR ../config_mine
+../cfg.sh
+# picks up same ../config_mine and ../tmpl_std from last time
+
+# own templates?
+cp -r ../tmpl_std ../tmpl_mine
+$EDITOR ../tmpl_mine/*
+../cfg.sh ../tmpl_mine
+# picks up same ../config_mine from last time, and ../tmpl_mine from cmdline
+
+
+
+=== Config file templates
+
+A *directory* contains template files that are filled with specific values by the
+cfg.sh script (aided by fill_config.py). See e.g. tmpl_std/.
+
+A *file* contains local config items that are put into the templates. See e.g.
+config_2g3g.
+
+The cfg.sh script helps to fill the templates with the config values. Simply
+invoke cfg.sh with a dir argument (templates dir) and a file argument (specific
+config values).
+
+If one or both are omitted, the script tries to re-use the most recent paths,
+they were stored in local files '.last_config' and '.last_templates'.
+
+The result is a complete set of .cfg files that match your local machine and
+network config.
+
+
+=== Launch
+
+A run.sh script template (tmpl_std/run.sh) also gets filled with specifics and
+placed next to the .cfg files.
+
+run.sh uses sudo to start tcpdump, configure ip forwarding and masquerading
+(for the GGSN's APN tunnel required for data services).
+
+When you launch run.sh, many xterms are launched, and when hitting enter, all
+of them get destroyed again. This is obviously intended to be run on your
+desktop computer or laptop, not on a remote box. It may also make sense to
+launch all of them in the current shell, and maybe or maybe not switch off
+stderr logging; or to launch each component in a tmux window or whatnot -- if
+you figure out something in that line, I would be glad to get contributions and
+incorporate that.
+
+
+=== Logging and pcaps
+
+The run.sh script automatically stores all configs, logs and pcap traces in
+./autolog/<timestamp> dirs. After closing the components (by hitting enter),
+you may also enter a name for the logs, after which they are stored in
+./logs/<name>. The idea is to keep all important logs with a name, and that you
+can every now and then just 'rm -rf ./autolog' to make space.
+
+
+=== 3G
+
+You may notice that the templates include nano3G.txt files. These include a
+convenient listing of commands to connect to an ip.access nano3G DMI and
+connect it to the HNBGW as configured by the templates.
+
+
+=== 2G BTS
+
+At the time of writing, there are no osmo-bts.cfg files, since this is intended
+for the core network and BSC components only. Feel free to add!
+
+Typically you'd need to edit only the /etc/osmocom/osmo-bts.cfg to match your
+IP address and ipa unit-id:
+
+bts 0
+ oml remote-ip 192.168.0.123
+ ipa unit-id 1800 0
diff --git a/net/cfg.sh b/net/cfg.sh
new file mode 100755
index 0000000..4dda0af
--- /dev/null
+++ b/net/cfg.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+config_file=""
+tmpl_dir=""
+
+while test -n "$1"; do
+  arg="$1"
+  shift
+
+  if [ ! -e "$arg" ]; then
+    if [ -e "../$arg"]; then
+      arg="../$arg";
+    fi
+  fi
+
+  if [ -f "$arg" ]; then
+    if [ -n "$config_file" ]; then
+      echo "Error: more than one config file: '$config_file' and '$arg'"
+      exit 2
+    fi
+    config_file="$arg"
+  fi
+
+  if [ -d "$arg" ]; then
+    if [ -n "$tmpl_dir" ]; then
+      echo "Error: more than one template dir: '$tmpl_dir' and '$arg'"
+      exit 2
+    fi
+    tmpl_dir="$arg"
+  fi
+done
+
+if [ -z "$config_file" ]; then
+  config_file="$(cat .last_config)"
+fi
+
+if [ -z "$tmpl_dir" ]; then
+  tmpl_dir="$(cat .last_templates)"
+fi
+
+set -e
+../fill_config.py "$config_file" "$tmpl_dir"
+
+echo "$config_file" > .last_config
+echo "$tmpl_dir" > .last_templates
diff --git a/net/common_logging b/net/common_logging
new file mode 100644
index 0000000..0e3f21e
--- /dev/null
+++ b/net/common_logging
@@ -0,0 +1,23 @@
+log stderr
+ logging filter all 1
+ logging color 1
+ logging print level 1
+ logging print category 1
+ logging print category-hex 0
+ logging print file basename
+ #logging print timestamp date
+ logging print extended-timestamp 1
+ logging level all debug
+log file current_log/${_name}.log
+ logging filter all 1
+ logging color 1
+ logging print level 1
+ logging print category 1
+ logging print category-hex 0
+ logging print file basename
+ #logging print timestamp date
+ logging print extended-timestamp 1
+ logging level all debug
+log gsmtap 127.0.0.1
+ logging filter all 1
+ logging level all debug
diff --git a/net/config_2g3g b/net/config_2g3g
new file mode 100644
index 0000000..8e11614
--- /dev/null
+++ b/net/config_2g3g
@@ -0,0 +1,50 @@
+ETH_DEV=eth0
+APN_DEV=apn0
+
+PUBLIC_IP="192.168.0.23"
+PUBLIC_IP2="192.168.0.42"
+
+MCC=001
+MNC=01
+
+HLR_IP="127.0.0.1"
+
+MSC_PC="0.23.1"
+
+SGSN_IP="${PUBLIC_IP}"
+SGSN_PC="0.23.2"
+SGSN_GB_PORT=23000
+
+GBPROXY_IP="${PUBLIC_IP}"
+GBPROXY_GB_PORT=7777
+
+PCU_GB_PORT=23000
+
+MGW4MSC_IP="${PUBLIC_IP}"
+MGW4MSC_VTY_IP="127.0.0.1"
+
+BSC_IP="${PUBLIC_IP}"
+BSC_PC="0.42.0"
+MGW4BSC_IP="${PUBLIC_IP2}"
+MGW4BSC_PORT="12427"
+MGW4BSC_VTY_IP="127.0.0.2"
+
+HNBGW_PC="0.3.0"
+HNBGW_IP="${PUBLIC_IP}"
+
+GGSN_IP="${PUBLIC_IP2}"
+GGSN_DNS0="192.168.0.1"
+GGSN_DNS1="9.9.9.9"
+GGSN_NET="192.168.42.0/24"
+
+HNODEB_IP="192.168.0.124"
+UARFCN=4357
+SCRAMBLE=157
+LAC=1${UARFCN}
+RAC=11
+
+HNODEB_IP2="192.168.0.23"
+UARFCN2=4358
+SCRAMBLE2=258
+LAC2=2${UARFCN2}
+RAC2=22
diff --git a/net/fill_config.py b/net/fill_config.py
new file mode 100755
index 0000000..24ce303
--- /dev/null
+++ b/net/fill_config.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+
+import os, sys, re, shutil
+
+def get_arg(nr, default):
+  if len(sys.argv) > nr:
+    return sys.argv[nr]
+  return default
+
+local_config_file = os.path.realpath(get_arg(1, 'local_config'))
+tmpl_dir = get_arg(2, 'tmpl')
+
+if not os.path.isdir(tmpl_dir):
+  print("Template dir does not exist: %r" % tmpl_dir)
+  exit(1)
+
+print('using config file %r\non templates %r' % (local_config_file, tmpl_dir))
+
+# read in variable values from config file
+local_config = {}
+
+line_nr = 0
+for line in open(local_config_file):
+  line_nr += 1
+  line = line.strip('\n')
+  if not '=' in line:
+    if line:
+      print("Error: %r line %d: %r" % (local_config_file, line_nr, line))
+      exit(1)
+    continue
+
+  split_pos = line.find('=')
+  name = line[:split_pos]
+  val = line[split_pos + 1:]
+
+  if val.startswith('"') and val.endswith('"'):
+    val = val[1:-1]
+
+  if name in local_config:
+    print("Error: duplicate identifier in %r line %d: %r" % (local_config_file, line_nr, line))
+  local_config[name] = val
+
+print('config:\n\n' + '\n'.join('%s=%r' % (n,v) for n,v in local_config.items()))
+
+# replace variable names with above values recursively
+replace_re = re.compile('\$\{([A-Za-z0-9_]*)\}')
+command_re = re.compile('\$\{([A-Za-z0-9_]*)\(([^)]*)\)\}')
+
+idx = 0
+
+for tmpl_name in sorted(os.listdir(tmpl_dir)):
+  tmpl_src = os.path.join(tmpl_dir, tmpl_name)
+  dst = tmpl_name
+
+  local_config['_fname'] = tmpl_name
+  local_config['_name'] = os.path.splitext(tmpl_name)[0]
+  local_config['_idx0'] = str(idx)
+  idx += 1
+  local_config['_idx1'] = str(idx)
+
+  try:
+    result = open(tmpl_src).read()
+  except:
+    print('Error in %r' % tmpl_src)
+    raise
+
+  while True:
+    used_vars = set()
+    for m in command_re.finditer(result):
+      cmd = m.group(1)
+      arg = m.group(2)
+      if cmd == 'include':
+        include_path = os.path.join(tmpl_dir, arg)
+        if not os.path.isfile(include_path):
+          print('Error: included file does not exist: %r in %r' % (include_path, tmpl_src))
+          exit(1)
+        try:
+          incl = open(include_path).read()
+        except:
+          print('Cannot read %r for %r' % (include_path, tmpl_src))
+          raise
+        result = result.replace('${%s(%s)}' % (cmd, arg), incl)
+      else:
+        print('Error: unknown command: %r in %r' % (cmd, tmpl_src))
+        exit(1)
+
+    for m in replace_re.finditer(result):
+      name = m.group(1)
+      if not name in local_config:
+        print('Error: undefined var %r in %r' % (name, tmpl_src))
+        exit(1)
+      used_vars.add(name)
+
+    if not used_vars:
+      break
+
+    for var in used_vars:
+      result = result.replace('${%s}' % var, local_config.get(var))
+
+  with open(dst, 'w') as dst_file:
+    dst_file.write(result)
+
+  shutil.copymode(tmpl_src, dst)
+
+# vim: ts=2 sw=2 expandtab
diff --git a/net/stale_config.sh b/net/stale_config.sh
new file mode 100755
index 0000000..f849ce1
--- /dev/null
+++ b/net/stale_config.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+stale="0"
+for f in *.cfg; do
+  f="$(basename "$f")"
+  for g in $(find . -maxdepth 2 -name "$f" -or -name "common_logging") ; do
+    if [ "$f" -ot "$g" ]; then
+      stale="1"
+      echo "$f older than $g"
+    fi
+  done
+done
+
+if [ "$stale" = "1" ]; then
+  echo "Stale configs. Hit enter to continue anyway."
+  read ok_to_continue
+fi
diff --git a/net/tmpl_std/nano3G.txt b/net/tmpl_std/nano3G.txt
new file mode 100644
index 0000000..df6feb6
--- /dev/null
+++ b/net/tmpl_std/nano3G.txt
@@ -0,0 +1,18 @@
+ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -c aes128-cbc root@${HNODEB_IP}
+
+telnet ${HNODEB_IP} 8090
+
+set mcc="${MCC}"
+set mnc="${MNC}"
+set rfParamsCandidateList=({${UARFCN}, ${SCRAMBLE}, 1})
+set lacRacCandidateList=({${LAC}, (${RAC})})
+set hnbGwAddress="${HNBGW_IP}"
+action 2061
+action 1216
+action establishPermanentHnbGwConnection
+set csgAccessMode=CSG_ACCESS_MODE_CLOSED_ACCESS
+set accessControlList = ({"901700000014701",1,"14701"})
+
+set accessControlList = ({"901700000014701",1,"14701"},{"901700000014702",1,"14702"})
+
+set csgAccessMode=CSG_ACCESS_MODE_OPEN_ACCESS
diff --git a/net/tmpl_std/nano3G2.txt b/net/tmpl_std/nano3G2.txt
new file mode 100644
index 0000000..a5be62d
--- /dev/null
+++ b/net/tmpl_std/nano3G2.txt
@@ -0,0 +1,18 @@
+ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -c aes128-cbc root@${HNODEB_IP2}
+
+telnet ${HNODEB_IP2} 8090
+
+set mcc="${MCC}"
+set mnc="${MNC}"
+set rfParamsCandidateList=({${UARFCN2}, ${SCRAMBLE2}, 1})
+set lacRacCandidateList=({${LAC2}, (${RAC2})})
+set hnbGwAddress="${HNBGW_IP}"
+action 2061
+action 1216
+action establishPermanentHnbGwConnection
+set csgAccessMode=CSG_ACCESS_MODE_CLOSED_ACCESS
+set accessControlList = ({"901700000014702",1,"14702"})
+
+set accessControlList = ({"901700000014701",1,"14701"},{"901700000014702",1,"14702"})
+
+set csgAccessMode=CSG_ACCESS_MODE_OPEN_ACCESS
diff --git a/net/tmpl_std/osmo-bsc.cfg b/net/tmpl_std/osmo-bsc.cfg
new file mode 100644
index 0000000..3ca9b3e
--- /dev/null
+++ b/net/tmpl_std/osmo-bsc.cfg
@@ -0,0 +1,87 @@
+network
+ #meas-feed destination 172.18.18.18 8888
+ #meas-feed scenario foo23
+ network country code ${MCC}
+ mobile network code ${MNC}
+ encryption a5 1
+ bts 0
+  type sysmobts
+  band GSM-1800
+  location_area_code 23
+  cell reselection hysteresis 14
+  ip.access unit_id 1801 0
+  gprs mode gprs
+  gprs nsvc 0 remote ip ${GBPROXY_IP}
+  gprs nsvc 0 remote udp port ${GBPROXY_GB_PORT}
+  gprs nsvc 0 local udp port ${PCU_GB_PORT}
+  gprs nsvc 0 nsvci 1801
+  gprs nsei 1801
+  gprs cell bvci 1801
+  trx 0
+   rf_locked 0
+   arfcn 868
+   nominal power 23
+   max_power_red 20
+   timeslot 0
+    phys_chan_config CCCH+SDCCH4
+   timeslot 1
+    phys_chan_config SDCCH8
+   timeslot 2
+    phys_chan_config TCH/F
+   timeslot 3
+    phys_chan_config TCH/F
+   timeslot 4
+    phys_chan_config TCH/F
+   timeslot 5
+    phys_chan_config PDCH
+   timeslot 6
+    phys_chan_config PDCH
+   timeslot 7
+    phys_chan_config PDCH
+ bts 1
+  type sysmobts
+  band GSM-1800
+  location_area_code 42
+  cell reselection hysteresis 14
+  ip.access unit_id 1802 0
+  gprs mode gprs
+  gprs nsvc 0 remote ip ${GBPROXY_IP}
+  gprs nsvc 0 remote udp port ${GBPROXY_GB_PORT}
+  gprs nsvc 0 local udp port ${PCU_GB_PORT}
+  gprs nsvc 0 nsvci 1802
+  gprs nsei 1802
+  gprs cell bvci 1802
+  trx 0
+   rf_locked 0
+   arfcn 870
+   nominal power 23
+   max_power_red 20
+   timeslot 0
+    phys_chan_config CCCH+SDCCH4
+   timeslot 1
+    phys_chan_config SDCCH8
+   timeslot 2
+    phys_chan_config TCH/F
+   timeslot 3
+    phys_chan_config TCH/F
+   timeslot 4
+    phys_chan_config TCH/F
+   timeslot 5
+    phys_chan_config PDCH
+   timeslot 6
+    phys_chan_config PDCH
+   timeslot 7
+    phys_chan_config PDCH
+e1_input
+ e1_line 0 driver ipa
+msc 0
+ mgw remote-ip ${MGW4BSC_IP}
+ mgw remote-port ${MGW4BSC_PORT}
+ mgw endpoint-range 33 64
+ allow-emergency deny
+ codec-list fr1 hr1
+
+${include(../common_logging)}
+
+log stderr
+ logging level meas debug
diff --git a/net/tmpl_std/osmo-gbproxy.cfg b/net/tmpl_std/osmo-gbproxy.cfg
new file mode 100644
index 0000000..3bc075d
--- /dev/null
+++ b/net/tmpl_std/osmo-gbproxy.cfg
@@ -0,0 +1,21 @@
+gbproxy
+ sgsn nsei 101
+ns
+ nse 101 nsvci 101
+ nse 101 remote-role sgsn
+ nse 101 encapsulation udp
+ nse 101 remote-ip ${SGSN_IP}
+ nse 101 remote-port ${SGSN_GB_PORT}
+ timer tns-block 3
+ timer tns-block-retries 3
+ timer tns-reset 3
+ timer tns-reset-retries 3
+ timer tns-test 30
+ timer tns-alive 3
+ timer tns-alive-retries 10
+ encapsulation framerelay-gre enabled 0
+ encapsulation framerelay-gre local-ip ${GBPROXY_IP}
+ encapsulation udp local-ip ${GBPROXY_IP}
+ encapsulation udp local-port ${GBPROXY_GB_PORT}
+
+${include(../common_logging)}
diff --git a/net/tmpl_std/osmo-ggsn.cfg b/net/tmpl_std/osmo-ggsn.cfg
new file mode 100644
index 0000000..1e69f65
--- /dev/null
+++ b/net/tmpl_std/osmo-ggsn.cfg
@@ -0,0 +1,17 @@
+log stderr
+ logging level all debug
+ logging filter all 1
+ logging print category 1
+ggsn ggsn0
+ gtp bind-ip ${GGSN_IP}
+ apn internet
+  tun-device ${APN_DEV}
+  type-support v4
+  ip dns 0 ${GGSN_DNS0}
+  ip dns 1 ${GGSN_DNS1}
+  #ip ifconfig ${GGSN_NET}
+  ip prefix dynamic ${GGSN_NET}
+  no shutdown
+ default-apn internet
+ no shutdown ggsn
+${include(../common_logging)}
diff --git a/net/tmpl_std/osmo-hlr.cfg b/net/tmpl_std/osmo-hlr.cfg
new file mode 100644
index 0000000..baa765e
--- /dev/null
+++ b/net/tmpl_std/osmo-hlr.cfg
@@ -0,0 +1,4 @@
+hlr
+ ussd route prefix *1# internal own-msisdn
+ ussd route prefix *2# internal own-imsi
+${include(../common_logging)}
diff --git a/net/tmpl_std/osmo-hnbgw.cfg b/net/tmpl_std/osmo-hnbgw.cfg
new file mode 100644
index 0000000..a918b10
--- /dev/null
+++ b/net/tmpl_std/osmo-hnbgw.cfg
@@ -0,0 +1,5 @@
+hnbgw
+ iuh
+  local-ip ${HNBGW_IP}
+
+${include(../common_logging)}
diff --git a/net/tmpl_std/osmo-mgw-for-bsc.cfg b/net/tmpl_std/osmo-mgw-for-bsc.cfg
new file mode 100644
index 0000000..a6eddbf
--- /dev/null
+++ b/net/tmpl_std/osmo-mgw-for-bsc.cfg
@@ -0,0 +1,11 @@
+mgcp
+ bind ip ${MGW4BSC_IP}
+ # default port is 2427 (is used for MSC's MGW)
+ bind port ${MGW4BSC_PORT}
+ number endpoints 64
+line vty
+ # default VTY interface is on 127.0.0.1 (used for MSC's MGW)
+ bind ${MGW4BSC_VTY_IP}
+
+${include(../common_logging)}
+ logging level all info
diff --git a/net/tmpl_std/osmo-mgw-for-msc.cfg b/net/tmpl_std/osmo-mgw-for-msc.cfg
new file mode 100644
index 0000000..5803932
--- /dev/null
+++ b/net/tmpl_std/osmo-mgw-for-msc.cfg
@@ -0,0 +1,8 @@
+mgcp
+ bind ip ${MGW4MSC_IP}
+ number endpoints 64
+line vty
+ bind ${MGW4MSC_VTY_IP}
+
+${include(../common_logging)}
+ logging level all info
diff --git a/net/tmpl_std/osmo-msc.cfg b/net/tmpl_std/osmo-msc.cfg
new file mode 100644
index 0000000..108d85e
--- /dev/null
+++ b/net/tmpl_std/osmo-msc.cfg
@@ -0,0 +1,15 @@
+network
+ network country code ${MCC}
+ mobile network code ${MNC}
+ authentication required
+ encryption a5 0
+msc
+ mgw remote-ip ${MGW4MSC_IP}
+ mgw endpoint-range 1 32
+
+${include(../common_logging)}
+ logging level ref debug
+ logging level vlr debug
+log stderr
+ logging level ref debug
+ logging level vlr debug
diff --git a/net/tmpl_std/osmo-sgsn.cfg b/net/tmpl_std/osmo-sgsn.cfg
new file mode 100644
index 0000000..3b61ef3
--- /dev/null
+++ b/net/tmpl_std/osmo-sgsn.cfg
@@ -0,0 +1,12 @@
+sgsn
+ gtp local-ip ${SGSN_IP}
+ ggsn 0 remote-ip ${GGSN_IP}
+ ggsn 0 gtp-version 1
+ auth-policy remote
+ gsup remote-ip ${HLR_IP}
+ns
+ encapsulation udp local-ip ${SGSN_IP}
+ encapsulation udp local-port ${SGSN_GB_PORT}
+ encapsulation framerelay-gre enabled 0
+
+${include(../common_logging)}
diff --git a/net/tmpl_std/osmo-stp.cfg b/net/tmpl_std/osmo-stp.cfg
new file mode 100644
index 0000000..093bf86
--- /dev/null
+++ b/net/tmpl_std/osmo-stp.cfg
@@ -0,0 +1,6 @@
+cs7 instance 0
+ xua rkm routing-key-allocation dynamic-permitted
+ listen m3ua 2905
+  accept-asp-connections dynamic-permitted
+
+${include(../common_logging)}
diff --git a/net/tmpl_std/run.sh b/net/tmpl_std/run.sh
new file mode 100755
index 0000000..d9ec53d
--- /dev/null
+++ b/net/tmpl_std/run.sh
@@ -0,0 +1,125 @@
+#!/usr/bin/env bash
+../stale_config.sh
+
+dev="${ETH_DEV}"
+ip2="${PUBLIC_IP2}"
+apn="${APN_DEV}"
+
+sudo true || exit 1
+
+if [ -z "$(sudo iptables -L -t nat | grep MASQUERADE)" ]; then
+  sudo iptables -t nat -A POSTROUTING -s ${GGSN_NET} -o $dev -j MASQUERADE
+fi
+
+if [ "$(sudo cat /proc/sys/net/ipv4/ip_forward)" = "0" ]; then
+  sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
+fi
+
+if [ -z "$(ip tuntap show | grep $apn)" ]; then
+  sudo ip tuntap add dev $apn mode tun user $USER group $USER
+  sudo ip addr add ${GGSN_NET} dev $apn
+  sudo ip link set $apn up
+fi
+
+if [ -z "$(ip addr show dev $dev | grep "$ip2")" ]; then
+  sudo ip addr add ${PUBLIC_IP2}/32 dev $dev
+fi
+
+logdir="current_log"
+mkdir -p "$logdir"
+
+term() {
+  title="$2"
+  if [ -z "$title" ]; then
+    title="$(basename $@)"
+  fi
+  terminal="$(which urxvt || which xterm)"
+  if ! which $terminal; then
+    echo "CANNOT FIND XTERM PROGRAM"
+  fi
+  exec $terminal -title "CN:$title" -e sh -c "export LD_LIBRARY_PATH='/usr/local/lib'; $1; echo; while true; do echo 'q Enter to close'; read q_to_close; if [ \"x\$q_to_close\" = xq ]; then break; fi; done"
+}
+
+sudo tcpdump -i $dev -n -w current_log/$dev.single.pcap -U not port 22 &
+sudo tcpdump -i lo -n -w current_log/lo.single.pcap -U not port 22 &
+
+hnbgw="osmo-hnbgw"
+msc="gdb -ex run --args $(which osmo-msc)"
+gbproxy="osmo-gbproxy"
+sgsn="osmo-sgsn"
+ggsn="osmo-ggsn"
+mgw4msc="osmo-mgw -c osmo-mgw-for-msc.cfg"
+#mgw4bsc="gdb -ex run --args osmo-mgw -c osmo-mgw-for-bsc.cfg"
+#mgw4bsc="strace osmo-mgw -c osmo-mgw-for-bsc.cfg"
+mgw4bsc="osmo-mgw -c osmo-mgw-for-bsc.cfg"
+hlr="LD_LIBRARY_PATH=/usr/local/lib gdb -ex run --args osmo-hlr"
+stp="osmo-stp"
+bsc="LD_LIBRARY_PATH=/usr/local/lib gdb -ex run --args osmo-bsc -c osmo-bsc.cfg"
+
+term "$ggsn" GGSN &
+sleep .2
+term "$stp" STP &
+sleep .2
+term "$hlr" HLR &
+sleep .2
+term "$sgsn" SGSN &
+sleep .2
+term "$gbproxy" GBPROXY &
+sleep .2
+term "$mgw4msc" MGW4MSC &
+sleep .2
+term "$mgw4bsc" MGW4BSC &
+sleep .2
+term "$msc" MSC &
+sleep 2
+term "$hnbgw" HNBGW &
+sleep .2
+term "$bsc" BSC &
+
+#ssh bts rm /tmp/bts.log /tmp/pcu.log
+#ssh bts neels/run_remote.sh &
+
+echo enter to close
+read enter_to_close
+echo Closing...
+
+#ssh bts neels/stop_remote.sh
+
+kill %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12
+killall osmo-msc
+killall osmo-bsc
+killall osmo-gbproxy
+killall osmo-sgsn
+#killall osmo-hnbgw
+killall osmo-mgw
+killall osmo-hlr
+killall -9 osmo-stp
+sudo killall tcpdump
+killall osmo-ggsn
+
+set +e
+cp *.cfg "$logdir"/
+
+echo
+echo enter name to save log
+read log_name
+if [ -n "$log_name" ]; then
+  newlogdir="log/$log_name"
+  #scp "bts:/tmp/{bts,pcu}.log" "bts:neels/osmo-{bts,pcu}.cfg" "$logdir"
+else
+  newlogdir="autolog/log_$(date +%Y-%m-%d_%H-%M-%S)"
+fi
+mkdir -p "$(dirname "$newlogdir")"
+
+mergecap -w "$logdir/trace.pcap" "$logdir/"*.single.pcap && rm -f "$logdir/"*.single.pcap
+
+if [ -x "$newlogdir" ]; then
+  echo "already exists, move it manually: $newlogdir"
+else
+  echo mv "$logdir" "$newlogdir"
+  mv "$logdir" "$newlogdir"
+  mkdir -p "$logdir"
+  logdir="$newlogdir"
+fi
+rm lastlog
+ln -s "$logdir" lastlog