SS/USSD: implement basic USSE routing configuration for VTY

This change introduces basic Unstructured Supplementary Services
processing Entity (USSE) configuration for VTY by analogy with
ESME and SMPP.

The configuration is done by allocating USSE nodes, so each one
is bound to a particular GSUP-connection, and represents a single
processing entity. Then, one or more USSD-code matching patterns
(e.g. code, prefix, regexp) can be assigned to a particular USSE
node, so all matched USSD-requests will be handled by this node.

Among all other USSE nodes, which are basically External USSEs,
there is a special one called IUSSE - internal USSD handler.
It can be optionally configured to handle and answer simple
requests, like *#100#.

Also, it's possible to set the default USSE, which will handle
all USSD-requests unmatched by other USSEs. Otherwise,
unmatched requests are being rejected.

Change-Id: I3cfd7cd401ea32b7e92f1124d129099d9f7dc6e6
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 58679ed..c931efa 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -31,6 +31,7 @@
 	test_subscriber.vty \
 	test_subscriber.sql \
 	test_subscriber.ctrl \
+	test_sse.vty \
 	$(NULL)
 
 TESTSUITE = $(srcdir)/testsuite
diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty
index 21809c8..6969626 100644
--- a/tests/test_nodes.vty
+++ b/tests/test_nodes.vty
@@ -70,6 +70,10 @@
   exit
   end
   gsup
+  usse (internal|NAME)
+  no usse (internal|NAME)
+  usse-default (internal|NAME)
+  no usse-default
 
 OsmoHLR(config-hlr)# gsup
 OsmoHLR(config-hlr-gsup)# list
@@ -85,6 +89,39 @@
   bind ip A.B.C.D
 
 OsmoHLR(config-hlr-gsup)# exit
+OsmoHLR(config-hlr)# usse test
+OsmoHLR(config-hlr-eusse)# list
+  help
+  list
+  write terminal
+  write file
+  write memory
+  write
+  show running-config
+  exit
+  end
+  pattern (code|regexp|prefix) PATTERN
+  no pattern (code|regexp|prefix) PATTERN
+
+OsmoHLR(config-hlr-eusse)# exit
+OsmoHLR(config-hlr)# usse internal
+OsmoHLR(config-hlr-iusse)# list
+  help
+  list
+  write terminal
+  write file
+  write memory
+  write
+  show running-config
+  exit
+  end
+  pattern (code|regexp|prefix) PATTERN response .RESPONSE
+  no pattern (code|regexp|prefix) PATTERN
+
+OsmoHLR(config-hlr-iusse)# exit
+OsmoHLR(config-hlr)# no usse test
+OsmoHLR(config-hlr)# no usse internal
+
 OsmoHLR(config-hlr)# exit
 OsmoHLR(config)# exit
 OsmoHLR# configure terminal
@@ -119,4 +156,5 @@
 hlr
  gsup
   bind ip 127.0.0.1
+ no usse-default
 end
diff --git a/tests/test_usse.vty b/tests/test_usse.vty
new file mode 100644
index 0000000..498e8d5
--- /dev/null
+++ b/tests/test_usse.vty
@@ -0,0 +1,246 @@
+OsmoHLR> enable
+OsmoHLR# configure terminal
+OsmoHLR(config)# show running-config
+
+Current configuration:
+!
+!
+log stderr
+  logging filter all 1
+  logging color 1
+  logging print category 1
+  logging print extended-timestamp 1
+  logging print file 1
+  logging level all debug
+  logging level main notice
+  logging level db notice
+  logging level auc notice
+...
+!
+line vty
+ no login
+!
+ctrl
+ bind 127.0.0.1
+hlr
+ gsup
+  bind ip 127.0.0.1
+ no usse-default
+end
+
+OsmoHLR(config)# hlr
+OsmoHLR(config-hlr)# no usse test
+% Cannot remove non-existent USSE 'test'
+
+OsmoHLR(config-hlr)# usse gw1
+OsmoHLR(config-hlr-eusse)# no pattern prefix *111*
+% Cannot remove non-existent pattern '*111*' of type 'prefix'
+
+OsmoHLR(config-hlr-eusse)# pattern prefix *110*
+OsmoHLR(config-hlr-eusse)# pattern prefix *181*
+OsmoHLR(config-hlr-eusse)# pattern prefix *110*
+% Pattern already exists!
+
+OsmoHLR(config-hlr-eusse)# pattern code *110*
+OsmoHLR(config-hlr-eusse)# pattern code *888#
+OsmoHLR(config-hlr-eusse)# pattern code *110*
+% Pattern already exists!
+
+OsmoHLR(config-hlr-eusse)# pattern regexp ^*[1-3]{3}*[0-9]+#$
+OsmoHLR(config-hlr-eusse)# pattern regexp ^*[5-7]{3}*[0-9]+#$
+OsmoHLR(config-hlr-eusse)# pattern regexp ^*[1-3]{3}*[0-9]+#$
+% Pattern already exists!
+
+OsmoHLR(config-hlr-eusse)# show running-config
+
+Current configuration:
+!
+!
+log stderr
+  logging filter all 1
+  logging color 1
+  logging print category 1
+  logging print extended-timestamp 1
+  logging print file 1
+  logging level all debug
+  logging level main notice
+  logging level db notice
+  logging level auc notice
+...
+!
+line vty
+ no login
+!
+ctrl
+ bind 127.0.0.1
+hlr
+ gsup
+  bind ip 127.0.0.1
+ no usse-default
+ usse gw1
+  pattern prefix *110*
+  pattern prefix *181*
+  pattern code *110*
+  pattern code *888#
+  pattern regexp ^*[1-3]{3}*[0-9]+#$
+  pattern regexp ^*[5-7]{3}*[0-9]+#$
+end
+
+OsmoHLR(config-hlr-eusse)# no pattern prefix *181*
+OsmoHLR(config-hlr-eusse)# no pattern code *110*
+OsmoHLR(config-hlr-eusse)# no pattern regexp ^*[1-3]{3}*[0-9]+#$
+OsmoHLR(config-hlr-eusse)# show running-config
+
+Current configuration:
+!
+!
+log stderr
+  logging filter all 1
+  logging color 1
+  logging print category 1
+  logging print extended-timestamp 1
+  logging print file 1
+  logging level all debug
+  logging level main notice
+  logging level db notice
+  logging level auc notice
+...
+!
+line vty
+ no login
+!
+ctrl
+ bind 127.0.0.1
+hlr
+ gsup
+  bind ip 127.0.0.1
+ no usse-default
+ usse gw1
+  pattern prefix *110*
+  pattern code *888#
+  pattern regexp ^*[5-7]{3}*[0-9]+#$
+end
+
+OsmoHLR(config-hlr-eusse)# exit
+OsmoHLR(config-hlr)# usse internal
+
+OsmoHLR(config-hlr-iusse)# pattern code *#100#
+% Command incomplete.
+
+OsmoHLR(config-hlr-iusse)# pattern code *#100# response Your extension is %m
+OsmoHLR(config-hlr-iusse)# pattern regexp ^*999*[0-3]+#$ response Mahlzeit!
+
+OsmoHLR(config-hlr-iusse)# no pattern code *888#
+% Cannot remove non-existent pattern '*888#' of type 'code'
+
+OsmoHLR(config-hlr-iusse)# show running-config
+
+Current configuration:
+!
+!
+log stderr
+  logging filter all 1
+  logging color 1
+  logging print category 1
+  logging print extended-timestamp 1
+  logging print file 1
+  logging level all debug
+  logging level main notice
+  logging level db notice
+  logging level auc notice
+...
+!
+line vty
+ no login
+!
+ctrl
+ bind 127.0.0.1
+hlr
+ gsup
+  bind ip 127.0.0.1
+ no usse-default
+ usse gw1
+  pattern prefix *110*
+  pattern code *888#
+  pattern regexp ^*[5-7]{3}*[0-9]+#$
+ usse internal
+  pattern code *#100# response Your extension is %m
+  pattern regexp ^*999*[0-3]+#$ response Mahlzeit!
+end
+
+OsmoHLR(config-hlr-iusse)# exit
+OsmoHLR(config-hlr)# usse-default test
+% Cannot find USSE 'test'
+
+OsmoHLR(config-hlr)# usse-default internal
+OsmoHLR(config-hlr)# usse-default gw1
+OsmoHLR(config-hlr)# show running-config
+
+Current configuration:
+!
+!
+log stderr
+  logging filter all 1
+  logging color 1
+  logging print category 1
+  logging print extended-timestamp 1
+  logging print file 1
+  logging level all debug
+  logging level main notice
+  logging level db notice
+  logging level auc notice
+...
+!
+line vty
+ no login
+!
+ctrl
+ bind 127.0.0.1
+hlr
+ gsup
+  bind ip 127.0.0.1
+ usse-default gw1
+ usse gw1
+  pattern prefix *110*
+  pattern code *888#
+  pattern regexp ^*[5-7]{3}*[0-9]+#$
+ usse internal
+  pattern code *#100# response Your extension is %m
+  pattern regexp ^*999*[0-3]+#$ response Mahlzeit!
+end
+
+OsmoHLR(config-hlr)# no usse gw1
+% Cannot remove USSE 'gw1', it is the default route
+
+OsmoHLR(config-hlr)# no usse-default
+OsmoHLR(config-hlr)# no usse gw1
+OsmoHLR(config-hlr)# show running-config
+
+Current configuration:
+!
+!
+log stderr
+  logging filter all 1
+  logging color 1
+  logging print category 1
+  logging print extended-timestamp 1
+  logging print file 1
+  logging level all debug
+  logging level main notice
+  logging level db notice
+  logging level auc notice
+...
+!
+line vty
+ no login
+!
+ctrl
+ bind 127.0.0.1
+hlr
+ gsup
+  bind ip 127.0.0.1
+ no usse-default
+ usse internal
+  pattern code *#100# response Your extension is %m
+  pattern regexp ^*999*[0-3]+#$ response Mahlzeit!
+end