diff --git a/.travis/test.sh b/.travis/test.sh
index 32da0f375b248aebf71d7cc44e49b7bd7a29fa51..ebb75eeccd1edf117958cdfdd2e0355ab3efb7a8 100644
--- a/.travis/test.sh
+++ b/.travis/test.sh
@@ -63,18 +63,8 @@ then
   fi
 fi
 
-for f in *.uts
-do
-  if [ "$f" = "bpf.uts" ] || [ "$f" = "mock_windows.uts" ] ; then
-    continue
-  fi
-  $SCAPY_SUDO ./run_tests -q -F -t $f $UT_FLAGS || exit $?
-done
-
-for f in ../scapy/contrib/*.uts
-do
-  $SCAPY_SUDO ./run_tests -f text -t $f $UT_FLAGS -P "load_contrib('$(basename ${f/.uts})')" || exit $?
-done
+# Run all normal and contrib tests
+$SCAPY_SUDO ./run_tests -c ./configs/travis.utsc -T "bpf.uts" -T "mock_windows.uts" $UT_FLAGS || exit $?
 
 # Run unit tests with openssl if we have root privileges
 if [ "$TRAVIS_OS_NAME" = "linux" ] && [ ! -z $SCAPY_USE_PCAPDNET ] && [ ! -z $SCAPY_SUDO ]
diff --git a/appveyor.yml b/appveyor.yml
index 64525c4b9c173481bd0d8c11f329482792dd7b28..a0a4393520f8f13133099c1130a995ade7b96ed2 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -27,12 +27,9 @@ test_script:
   - "%PYTHON%\\python -m coverage run -a bin\\UTscapy -f text -t test\\regression.uts -F -K mock_read_routes6_bsd || exit /b 42"
   - 'del test\regression.uts'
 
-  # Secondary unit tests
+  # Secondary and contrib unit tests
   - 'del test\bpf.uts' # Don't bother with BPF regression tests
-  - "for %%t in (test\\*.uts) do (%PYTHON%\\python -m coverage run -a bin\\UTscapy -f text -t %%t -F -K combined_modes_ccm || exit /b 42)"
-  
-  # Contrib unit tests
-  - "for %%t in (scapy\\contrib\\*.uts) do (%PYTHON%\\python -m coverage run -a bin\\UTscapy -f text -t %%t -F -P \"load_contrib(\'%%~nt\')\"  || exit /b 42)"
+  - "%PYTHON%\\python -m coverage run -a bin\\UTscapy -c test\\configs\\windows.utsc || exit /b 42"
 
 after_test:
   # Install & run codecov
diff --git a/scapy/dadict.py b/scapy/dadict.py
index 96c8faab35a6cbbef49131f2089a1433c84e64ec..c799b87c967d46d3f55062ac8a7d14a4af9354e7 100644
--- a/scapy/dadict.py
+++ b/scapy/dadict.py
@@ -25,7 +25,7 @@ class DADict_Exception(Scapy_Exception):
 class DADict:
     def __init__(self, _name="DADict", **kargs):
         self._name=_name
-        self.__dict__.update(kargs)
+        self.update(kargs)
     def fixname(self,val):
         return fixname(val)
     def __contains__(self, val):
@@ -55,6 +55,10 @@ class DADict:
             if k not in self or self[k] != kargs[k]:
                 return False
         return True
+
+    def update(self, *args, **kwargs):
+        for k, v in dict(*args, **kwargs).iteritems():
+            self[k] = v
     
     def _find(self, *args, **kargs):
          return self._recurs_find((), *args, **kargs)
diff --git a/scapy/modules/voip.py b/scapy/modules/voip.py
index 53036a7899b7782e9c1fceee47377da6b652aeed..de1ce5f25b3dbeac55e7944932b3d4e7daf46950 100644
--- a/scapy/modules/voip.py
+++ b/scapy/modules/voip.py
@@ -24,9 +24,6 @@ sox_base = "sox -t .ul %s - -t ossdsp /dev/dsp"
 if WINDOWS:
     if conf.prog.sox is None:
         raise OSError("Sox must be installed to play VoIP packets")
-    finally:
-        if p_test:
-            p_test.terminate()
     sox_base = "\"" + conf.prog.sox + "\" -t .ul %s - -t waveaudio"
 
 def _merge_sound_bytes(x,y,sample_size=2):
diff --git a/scapy/tools/UTscapy.py b/scapy/tools/UTscapy.py
index 515e0ededcde73194494eef26fe06f14356257b4..28b12461450189b24937f666f120143a01e8c314 100755
--- a/scapy/tools/UTscapy.py
+++ b/scapy/tools/UTscapy.py
@@ -7,11 +7,16 @@
 Unit testing infrastructure for Scapy
 """
 
-import sys,getopt,imp
+import sys, getopt, imp, glob
 import bz2, base64, os.path, time, traceback, zlib, sha
 from scapy.consts import WINDOWS
 
 
+### Util class ###
+
+class Bunch:
+    __init__ = lambda self, **kw: setattr(self, '__dict__', kw)
+
 #### Import tool ####
 
 def import_module(name):
@@ -135,9 +140,16 @@ class TestCampaign(TestClass):
         self.sha = None
         self.preexec = None
         self.preexec_output = None
+        self.end_pos = 0
     def add_testset(self, testset):
         self.campaign.append(testset)
         testset.keywords.update(self.keywords)
+    def startNum(self, beginpos):
+        for ts in self:
+            for t in ts:
+                t.num = beginpos
+                beginpos += 1
+        self.end_pos = beginpos
     def __iter__(self):
         return self.campaign.__iter__()
     def all_tests(self):
@@ -171,10 +183,58 @@ class UnitTest(TestClass):
         self.keywords = set()
         self.crc = None
         self.expand = 1
+    def decode(self):
+        self.test = self.test.decode("utf8")
+        self.output = self.output.decode("utf8")
+        self.comments = self.comments.decode("utf8")
+        self.result = self.result.decode("utf8")
+    def encode(self):
+        self.test = self.test.encode("utf8")
+        self.output = self.output.encode("utf8")
+        self.comments = self.comments.encode("utf8")
+        self.result = self.result.encode("utf8")
     def __nonzero__(self):
         return self.res
 
 
+# Careful note: all data not included will be set by default.
+# Use -c as first argument !!
+def parse_config_file(config_path, verb=3):
+    """Parse provided json to get configuration
+    Empty default json:
+    {
+      "testfiles": [],
+      "onlyfailed": false,
+      "verb": 2,
+      "dump": 0,
+      "crc": true,
+      "scapy": "scapy",
+      "preexec": {},
+      "global_preexec": "",
+      "outputfile": null,
+      "local": true,
+      "format": "ansi",
+      "num": null,
+      "modules": [],
+      "kw_ok": [],
+      "kw_ko": []
+    }
+
+    """
+    import json, unicodedata
+    with open(config_path) as config_file:
+        data = json.load(config_file, encoding="utf8")
+        if verb > 2:
+            print >>sys.stderr, "### Loaded config file", config_path
+    def get_if_exist(key, default):
+        return data[key] if key in data else default
+    return Bunch(testfiles=get_if_exist("testfiles", []), onlyfailed=get_if_exist("onlyfailed", False),
+                 verb=get_if_exist("verb", 3), dump=get_if_exist("dump", 0), crc=get_if_exist("crc", 1),
+                 scapy=get_if_exist("scapy", "scapy"), preexec=get_if_exist("preexec", {}),
+                 global_preexec=get_if_exist("global_preexec", ""), outfile=get_if_exist("outputfile", sys.stdout),
+                 local=get_if_exist("local", 0), num=get_if_exist("num", None), modules=get_if_exist("modules", []),
+                 kw_ok=get_if_exist("kw_ok", []), kw_ko=get_if_exist("kw_ko", []), format=get_if_exist("format", "ansi"))
+
 #### PARSE CAMPAIGN ####
 
 def parse_campaign_file(campaign_file):
@@ -202,7 +262,6 @@ def parse_campaign_file(campaign_file):
             testset.add_test(test)
         elif l[0] == "*":
             if test is not None:
-                
                 test.comments += l[1:]
             elif testset is not None:
                 testset.comments += l[1:]
@@ -286,9 +345,9 @@ def filter_tests_keep_on_keywords(test_campaign, kw):
 def filter_tests_remove_on_keywords(test_campaign, kw):
     def kw_match(lst, kw):
         for k in kw:
-            if k not in lst:
-                return False
-        return True
+            if k in lst:
+                return True
+        return False
     
     if kw:
         for ts in test_campaign:
@@ -301,7 +360,7 @@ def remove_empty_testsets(test_campaign):
 
 #### RUN CAMPAIGN #####
 
-def run_campaign(test_campaign, get_interactive_session, verb=2):
+def run_campaign(test_campaign, get_interactive_session, verb=3):
     if WINDOWS:
         # Add a route to 127.0.0.1
         from scapy.arch.windows import route_add_loopback
@@ -328,6 +387,7 @@ def run_campaign(test_campaign, get_interactive_session, verb=2):
                 res = "failed"
                 failed += 1
             t.result = res
+            t.decode()
             if verb > 1:
                 print >>sys.stderr,"%(result)6s %(crc)s %(name)s" % t
     test_campaign.passed = passed
@@ -399,40 +459,18 @@ def campaign_to_xUNIT(test_campaign):
     return output
 
 
-def campaign_to_HTML(test_campaign, local=0):
-    output = """<html>
-<head>
-<title>%(title)s</title>
-<link rel="stylesheet" href="%%(UTscapy_css)s" type="text/css">
-<script language="JavaScript" src="%%(UTscapy_js)s" type="text/javascript"></script>
-</head>
-<body>
-
+def campaign_to_HTML(test_campaign):
+    output = """
 <h1>%(title)s</h1>
 
-<span class=button onClick="hide_all('tst')">Shrink All</span>
-<span class=button onClick="show_all('tst')">Expand All</span>
-<span class=button onClick="show_passed('tst')">Expand Passed</span>
-<span class=button onClick="show_failed('tst')">Expand Failed</span>
 <p>
 """ % test_campaign
 
-    if local:
-        External_Files.UTscapy_js.write(os.path.dirname(test_campaign.output_file.name))
-        External_Files.UTscapy_css.write(os.path.dirname(test_campaign.output_file.name))
-        output %= External_Files.get_local_dict()
-    else:
-        output %= External_Files.get_URL_dict()
-
     if test_campaign.crc is not None and test_campaign.sha is not None:
         output += "CRC=<span class=crc>%(crc)s</span> SHA=<span class=crc>%(sha)s</span><br>" % test_campaign
     output += "<small><em>"+html_info_line(test_campaign)+"</em></small>"
     output += test_campaign.headcomments +  "\n<p>PASSED=%(passed)i FAILED=%(failed)i<p>\n\n" % test_campaign
-    for ts in test_campaign:
-        for t in ts:
-            output += """<span class=button%(result)s onClick="goto_id('tst%(num)il')">%(num)03i</span>\n""" % t
-    output += "\n\n"
-    
+
     for testset in test_campaign:
         output += "<h2>" % testset
         if testset.crc is not None:
@@ -460,8 +498,44 @@ def campaign_to_HTML(test_campaign, local=0):
 %(output)s</pre></span>
 """ % t
         output += "\n</ul>\n\n"
+    return output
+
+def pack_html_campaigns(runned_campaigns, data, local=0, title=None):
+    output = """
+<html>
+<head>
+<title>%(title)s</title>
+<h1>UTScapy tests</h1>
+
+<span class=button onClick="hide_all('tst')">Shrink All</span>
+<span class=button onClick="show_all('tst')">Expand All</span>
+<span class=button onClick="show_passed('tst')">Expand Passed</span>
+<span class=button onClick="show_failed('tst')">Expand Failed</span>
+
+<p>
+"""
+    for test_campaign in runned_campaigns:
+        for ts in test_campaign:
+            for t in ts:
+                output += """<span class=button%(result)s onClick="goto_id('tst%(num)il')">%(num)03i</span>\n""" % t
+        
+    output += """</p>\n\n
+<link rel="stylesheet" href="%(UTscapy_css)s" type="text/css">
+<script language="JavaScript" src="%(UTscapy_js)s" type="text/javascript"></script>
+</head>
+<body>
+%(data)s
+</body></html>
+"""
+    out_dict = {'data': data, 'title': title if title else "UTScapy tests"}
+    if local:
+        External_Files.UTscapy_js.write(os.path.dirname(test_campaign.output_file.name))
+        External_Files.UTscapy_css.write(os.path.dirname(test_campaign.output_file.name))
+        out_dict.update(External_Files.get_local_dict())
+    else:
+        out_dict.update(External_Files.get_URL_dict())
 
-    output += "</body></html>"
+    output %= out_dict
     return output
 
 def campaign_to_LATEX(test_campaign):
@@ -512,15 +586,18 @@ def campaign_to_LATEX(test_campaign):
                       
 def usage():
     print >>sys.stderr,"""Usage: UTscapy [-m module] [-f {text|ansi|HTML|LaTeX}] [-o output_file] 
-               [-t testfile] [-k keywords [-k ...]] [-K keywords [-K ...]]
+               [-t testfile] [-T testfile] [-k keywords [-k ...]] [-K keywords [-K ...]]
                [-l] [-d|-D] [-F] [-q[q]] [-P preexecute_python_code]
-               [-s /path/to/scapy]
+               [-s /path/to/scapy] [-c configfile]
+-t\t\t: provide test files (can be used many times)
+-T\t\t: if -t is used with *, remove a specific file (can be used many times)
 -l\t\t: generate local files
 -F\t\t: expand only failed tests
 -d\t\t: dump campaign
 -D\t\t: dump campaign and stop
 -C\t\t: don't calculate CRC and SHA
 -s\t\t: path to scapy.py
+-c\t\t: load a .utsc config file
 -q\t\t: quiet mode
 -qq\t\t: [silent mode]
 -n <testnum>\t: only tests whose numbers are given (eg. 1,3-7,12)
@@ -534,6 +611,70 @@ def usage():
 
 #### MAIN ####
 
+def execute_campaign(TESTFILE, OUTPUTFILE, PREEXEC, NUM, KW_OK, KW_KO, DUMP,
+                     FORMAT, VERB, ONLYFAILED, CRC, autorun_func, pos_begin=0):
+    # Parse test file
+    test_campaign = parse_campaign_file(TESTFILE)
+
+    # Report parameters
+    if PREEXEC:
+        test_campaign.preexec = PREEXEC
+    
+    # Compute campaign CRC and SHA
+    if CRC:
+        compute_campaign_digests(test_campaign)
+
+    # Filter out unwanted tests
+    filter_tests_on_numbers(test_campaign, NUM)
+    for k in KW_OK:
+        filter_tests_keep_on_keywords(test_campaign, k)
+    for k in KW_KO:
+        filter_tests_remove_on_keywords(test_campaign, k)
+
+    remove_empty_testsets(test_campaign)
+
+
+    # Dump campaign
+    if DUMP:
+        dump_campaign(test_campaign)
+        if DUMP > 1:
+            sys.exit()
+
+    # Run tests
+    test_campaign.output_file = OUTPUTFILE
+    result = run_campaign(test_campaign, autorun_func[FORMAT], verb=VERB)
+
+    # Shrink passed
+    if ONLYFAILED:
+        for t in test_campaign.all_tests():
+            if t:
+                t.expand = 0
+            else:
+                t.expand = 2
+
+    pos_end = 0
+    # Generate report
+    if FORMAT == Format.TEXT:
+        output = campaign_to_TEXT(test_campaign)
+    elif FORMAT == Format.ANSI:
+        output = campaign_to_ANSI(test_campaign)
+    elif FORMAT == Format.HTML:
+        test_campaign.startNum(pos_begin)
+        output = campaign_to_HTML(test_campaign)
+    elif FORMAT == Format.LATEX:
+        output = campaign_to_LATEX(test_campaign)
+    elif FORMAT == Format.XUNIT:
+        output = campaign_to_xUNIT(test_campaign)
+
+    return output, (result == 0), test_campaign
+
+def resolve_testfiles(TESTFILES):
+    for tfile in TESTFILES[:]:
+        if "*" in tfile:
+            TESTFILES.remove(tfile)
+            TESTFILES.extend(glob.glob(tfile))
+    return TESTFILES
+
 def main(argv):
     import __builtin__
 
@@ -543,23 +684,25 @@ def main(argv):
     TESTFILE = sys.stdin
     OUTPUTFILE = sys.stdout
     LOCAL = 0
-    NUM=None
+    NUM = None
     KW_OK = []
     KW_KO = []
     DUMP = 0
-    CRC = 1
-    ONLYFAILED = 0
-    VERB=2
-    PREEXEC=""
-    SCAPY="scapy"
+    CRC = True
+    ONLYFAILED = False
+    VERB = 3
+    GLOB_PREEXEC = ""
+    PREEXEC_DICT = {}
+    SCAPY = "scapy"
     MODULES = []
+    TESTFILES = []
     try:
-        opts = getopt.getopt(argv, "o:t:f:hln:m:k:K:DdCFqP:s:")
+        opts = getopt.getopt(argv, "o:t:T:c:f:hln:m:k:K:DdCFqP:s:")
         for opt,optarg in opts[0]:
             if opt == "-h":
                 usage()
             elif opt == "-F":
-                ONLYFAILED = 1
+                ONLYFAILED = True
             elif opt == "-q":
                 VERB -= 1
             elif opt == "-D":
@@ -567,18 +710,42 @@ def main(argv):
             elif opt == "-d":
                 DUMP = 1
             elif opt == "-C":
-                CRC = 0
+                CRC = False
             elif opt == "-s":
                 SCAPY = optarg
             elif opt == "-P":
-                PREEXEC += "\n"+optarg
+                GLOB_PREEXEC += "\n"+optarg
             elif opt == "-f":
                 try:
                     FORMAT = Format.from_string(optarg)
                 except KeyError,msg:
                     raise getopt.GetoptError("Unknown output format %s" % msg)
             elif opt == "-t":
-                TESTFILE = open(optarg)
+                TESTFILES.append(optarg)
+                TESTFILES = resolve_testfiles(TESTFILES)
+            elif opt == "-T":
+                TESTFILES.remove(optarg)
+            elif opt == "-c":
+                data = parse_config_file(optarg, VERB)
+                ONLYFAILED = data.onlyfailed
+                VERB = data.verb
+                DUMP = data.dump
+                CRC = data.crc
+                SCAPY = data.scapy
+                PREEXEC_DICT = data.preexec
+                GLOB_PREEXEC = data.global_preexec
+                OUTPUTFILE = data.outfile
+                TESTFILES = data.testfiles
+                LOCAL = 1 if data.local else 0
+                NUM = data.num
+                MODULES = data.modules
+                KW_OK = [data.kw_ok]
+                KW_KO = [data.kw_ko]
+                try:
+                    FORMAT = Format.from_string(data.format)
+                except KeyError,msg:
+                    raise getopt.GetoptError("Unknown output format %s" % msg)
+                TESTFILES = resolve_testfiles(TESTFILES)
             elif opt == "-o":
                 OUTPUTFILE = open(optarg, "w")
             elif opt == "-l":
@@ -598,7 +765,8 @@ def main(argv):
             elif opt == "-K":
                 KW_KO.append(optarg.split(","))
 
-        
+        if VERB > 2:
+            print >>sys.stderr, "### Booting scapy..."
         try:
             from scapy import all as scapy
         except ImportError,e:
@@ -623,61 +791,56 @@ def main(argv):
         Format.XUNIT: scapy.autorun_get_text_interactive_session,
         }
 
-    # Parse test file
-    test_campaign = parse_campaign_file(TESTFILE)
-
-    # Report parameters
-    if PREEXEC:
-        test_campaign.preexec = PREEXEC
+    if VERB > 2:
+        print >>sys.stderr,"### Starting tests..."
+
+    glob_output = ""
+    glob_result = 0
+    glob_title = None
+
+    UNIQUE = len(TESTFILES) == 1
+
+    # Resolve tags and asterix
+    for prex in PREEXEC_DICT.keys():
+        if "*" in prex:
+            pycode = PREEXEC_DICT[prex]
+            del PREEXEC_DICT[prex]
+            for gl in glob.iglob(prex):
+                _pycode = pycode.replace("%name%", os.path.splitext(os.path.split(gl)[1])[0])
+                PREEXEC_DICT[gl] = _pycode
+
+    pos_begin = 0
+
+    runned_campaigns = []
+    # Execute all files
+    for TESTFILE in TESTFILES:
+        if VERB > 2:
+            print >>sys.stderr,"### Loading:", TESTFILE
+        PREEXEC = PREEXEC_DICT[TESTFILE] if TESTFILE in PREEXEC_DICT else GLOB_PREEXEC
+        output, result, campaign = execute_campaign(open(TESTFILE), OUTPUTFILE,
+                                          PREEXEC, NUM, KW_OK, KW_KO,
+                                          DUMP, FORMAT, VERB, ONLYFAILED,
+                                          CRC, autorun_func, pos_begin)
+        runned_campaigns.append(campaign)
+        pos_begin = campaign.end_pos
+        if UNIQUE:
+            glob_title = campaign.title
+        glob_output += output
+        if not result:
+            glob_result = 1
+            break
+
+    if VERB > 2:
+            print >>sys.stderr,"### Writing output..."
+    # Concenate outputs
+    if FORMAT == Format.HTML:
+        glob_output = pack_html_campaigns(runned_campaigns, glob_output, LOCAL, glob_title)
     
-
-    # Compute campaign CRC and SHA
-    if CRC:
-        compute_campaign_digests(test_campaign)
-
-    # Filter out unwanted tests
-    filter_tests_on_numbers(test_campaign, NUM)
-    for k in KW_OK:
-        filter_tests_keep_on_keywords(test_campaign, k)
-    for k in KW_KO:
-        filter_tests_remove_on_keywords(test_campaign, k)
-
-    remove_empty_testsets(test_campaign)
-
-
-    # Dump campaign
-    if DUMP:
-        dump_campaign(test_campaign)
-        if DUMP > 1:
-            sys.exit()
-
-    # Run tests
-    test_campaign.output_file = OUTPUTFILE
-    result = run_campaign(test_campaign, autorun_func[FORMAT], verb=VERB)
-
-    # Shrink passed
-    if ONLYFAILED:
-        for t in test_campaign.all_tests():
-            if t:
-                t.expand = 0
-            else:
-                t.expand = 2
-
-    # Generate report
-    if FORMAT == Format.TEXT:
-        output = campaign_to_TEXT(test_campaign)
-    elif FORMAT == Format.ANSI:
-        output = campaign_to_ANSI(test_campaign)
-    elif FORMAT == Format.HTML:
-        output = campaign_to_HTML(test_campaign, local=LOCAL)
-    elif FORMAT == Format.LATEX:
-        output = campaign_to_LATEX(test_campaign)
-    elif FORMAT == Format.XUNIT:
-        output = campaign_to_xUNIT(test_campaign)
-
-    OUTPUTFILE.write(output)
+    OUTPUTFILE.write(glob_output.encode("utf8"))
     OUTPUTFILE.close()
-    return result
+
+    # Return state
+    return glob_result
 
 if __name__ == "__main__":
     exit(main(sys.argv[1:]))
diff --git a/test/cert.uts b/test/cert.uts
index c43652cd7ae12251078acb7f0264584189f8df7c..af3f041ce92ec3c5a9b0fcd8a14c9afaf28df6c7 100644
--- a/test/cert.uts
+++ b/test/cert.uts
@@ -193,7 +193,7 @@ x.version == 3
 x.serial == 0xB45E7043E7090B71
 
 = Cert class : Checking signature algorithm
-x.sigAlg == 'sha1-with-rsa-signature' 
+x.sigAlg == 'sha1_with_rsa_signature' 
 
 = Cert class : Checking issuer extraction in basic format (/C=FR ...)
 x.issuer_str == '/C=FR/ST=Paris/L=Paris/O=Mushroom Corp./OU=Mushroom VPN Services/CN=IKEv2 X.509 Test certificate/emailAddress=ikev2-test@mushroom.corp'
diff --git a/test/configs/travis.utsc b/test/configs/travis.utsc
new file mode 100644
index 0000000000000000000000000000000000000000..c8dd3cf7b3c67cdf95af5d2c83e704d8f2eddbba
--- /dev/null
+++ b/test/configs/travis.utsc
@@ -0,0 +1,11 @@
+{
+  "testfiles": [
+    "*.uts",
+    "../scapy/contrib/*.uts"
+  ],
+  "onlyfailed": true,
+  "preexec": {
+    "../scapy/contrib/*.uts": "load_contrib(\"%name%\")"
+  },
+  "format": "text"
+}
diff --git a/test/configs/windows.utsc b/test/configs/windows.utsc
new file mode 100644
index 0000000000000000000000000000000000000000..253ddebd0a016691b50033dae67785680e46edf2
--- /dev/null
+++ b/test/configs/windows.utsc
@@ -0,0 +1,14 @@
+{
+  "testfiles": [
+    "test\\*.uts",
+    "scapy\\contrib\\*.uts"
+  ],
+  "onlyfailed": true,
+  "preexec": {
+    "scapy\\contrib\\*.uts": "load_contrib(\"%name%\")"
+  },
+  "format": "text",
+  "kw_ko": [
+    "combined_modes_ccm"
+  ]
+}
diff --git a/test/configs/windows2.utsc b/test/configs/windows2.utsc
new file mode 100644
index 0000000000000000000000000000000000000000..445817e2ce41734bc0ec532871217b83b68fdae7
--- /dev/null
+++ b/test/configs/windows2.utsc
@@ -0,0 +1,15 @@
+{
+  "testfiles": [
+    "*.uts",
+    "..\\scapy\\contrib\\*.uts"
+  ],
+  "onlyfailed": true,
+  "preexec": {
+    "..\\scapy\\contrib\\*.uts": "load_contrib(\"%name%\")"
+  },
+  "format": "html",
+  "kw_ko": [
+    "combined_modes_ccm",
+    "mock_read_routes6_bsd"
+  ]
+}
diff --git a/test/regression.uts b/test/regression.uts
index e8d8b17b7d5aadf47d9db4f156e373def7915edc..6c8d0635b01df07fdbe7b36b4f31b90866fc1264 100644
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -1244,7 +1244,7 @@ in6_addrtomac("FE80::" + in6_mactoifaceid("FF:00:00:00:00:00", ulbit=0)) == 'ff:
 import socket
 
 res=True
-for _ in xrange(10):
+for a in xrange(10):
     s1,s2 = in6_getRandomizedIfaceId('20b:93ff:feeb:2d3')
     inet_pton(socket.AF_INET6, '::'+s1)
     tmp2 = inet_pton(socket.AF_INET6, '::'+s2)
@@ -7473,10 +7473,11 @@ def test_show():
         result_show += s
     mock_stdout = mock.Mock()
     mock_stdout.write = write
+    saved_stdout = sys.stdout
     sys.stdout = mock_stdout
     tr = TracerouteResult(tr_packets)
     tr.show()
-    sys.stdout = sys.__stdout__
+    sys.stdout = saved_stdout
     expected = "  192.168.0.1:tcp80  \n"
     expected += "1 192.168.0.1     11 \n"
     expected += "2 192.168.0.2     11 \n"
@@ -7525,10 +7526,11 @@ def test_IPID_count():
         result_IPID_count += s
     mock_stdout = mock.Mock()
     mock_stdout.write = write
+    saved_stdout = sys.stdout
     sys.stdout = mock_stdout
     random.seed(0x2807)
     IPID_count([(IP()/UDP(), IP(id=random.randint(0, 65535))/UDP()) for i in range(3)])
-    sys.stdout = sys.__stdout__
+    sys.stdout = saved_stdout
     lines = result_IPID_count.split("\n")
     print len(lines) == 5
     print lines[0] == "Probably 3 classes: [4613, 53881, 58437]"
diff --git a/test/run_tests.bat b/test/run_tests.bat
index 1ddef95a9076d15c11148f5e9e95ceedb3e33e22..8c4200d867fe76d9df2814d942cdb145b18fee85 100644
--- a/test/run_tests.bat
+++ b/test/run_tests.bat
@@ -1,8 +1,9 @@
 @echo off
+title UTscapy - All tests
 set MYDIR=%cd%\..
 set PYTHONPATH=%MYDIR%
 if [%1]==[] (
-  python "%MYDIR%\scapy\tools\UTscapy.py" -t regression.uts -K mock_read_routes6_bsd -f html -o scapy_regression_test_%date:~6,4%_%date:~3,2%_%date:~0,2%.html
+  python "%MYDIR%\scapy\tools\UTscapy.py" -c configs\\windows2.utsc -T bpf.uts -o scapy_regression_test_%date:~6,4%_%date:~3,2%_%date:~0,2%.html
 ) else (
   python "%MYDIR%\scapy\tools\UTscapy.py" %@
 )
diff --git a/test/run_tls_test.bat b/test/run_tls_test.bat
deleted file mode 100644
index 66379c3e291e1a79737382c817440ecb4918a919..0000000000000000000000000000000000000000
--- a/test/run_tls_test.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-@echo off
-set MYDIR=%cd%\..
-set PYTHONPATH=%MYDIR%
-python "%MYDIR%\scapy\tools\UTscapy.py" -t tls/tests_tls_netaccess.uts -f html -o scapy_tls_test_%date:~6,4%_%date:~3,2%_%date:~0,2%.html
-PAUSE
diff --git a/test/x509.uts b/test/x509.uts
index e481e0ea06bc2eb355691d642d52ef6bad01da22..d910c3e003fbbc759330ce6c5f82cb38ad147fd8 100644
--- a/test/x509.uts
+++ b/test/x509.uts
@@ -65,7 +65,7 @@ tbs.serialNumber == ASN1_INTEGER(0xb45e7043e7090b71)
 
 = Cert class : Signature algorithm (as advertised by TBSCertificate)
 assert(type(tbs.signature) is X509_AlgorithmIdentifier)
-tbs.signature.algorithm == ASN1_OID("sha1-with-rsa-signature")
+tbs.signature.algorithm == ASN1_OID("sha1_with_rsa_signature")
 
 = Cert class : Issuer structure
 assert(type(tbs.issuer) is list)
@@ -121,7 +121,7 @@ ext[0].extnValue.keyIdentifier == ASN1_STRING('\xf3\xd8N\xde\x90\xf7\xe6]\xd2\xc
 
 = Cert class : Signature algorithm
 assert(type(x.signatureAlgorithm) is X509_AlgorithmIdentifier)
-x.signatureAlgorithm.algorithm == ASN1_OID("sha1-with-rsa-signature")
+x.signatureAlgorithm.algorithm == ASN1_OID("sha1_with_rsa_signature")
 
 = Cert class : Signature value
 x.signatureValue == ASN1_BIT_STRING("6\xce\xdd\x01\xbdz\x1f\x89[\xc71i_\xb5\x90\xac\xb5\x06\x9a\xc1\xe8\xf5Jlk\x01\xf0\xc1\xe0\xd5\x0c\xdb\x83l\x1b\xe5\x19#\xcf\x17\x03\x95\xcc\xe9\n%\x99\xfc\x8a\x9c\xda\xe8\x98\xc2\xc2\xd7\xee\x82h\\c\xabx\xc2\xfe\xa7R\xee'\xda\x94R\xd0V\x8e\xe2\x93\xfb^\xd3>\x8e\x96\x8d\x11\x90\x13`\xc9\xa8\x16=}\x8bG\x99\x07{\xd4oH;\xa8<\x8b\x1bHs&$\x0f|\x01\x9c\x1a\xb5\xbb\xc4\x86l\xcc \xd2MR\x81\xd5\xce\x13\xde\x1d\x99\xc8h\x18\x14\x06\r6]B\xe4\xfcIbt\xeeuE\xfd\xe0\x87\xc7Q\xfeH\x05A$\x13\xeb\xce\xef\xb3\\}M`\xf4\xd3=\x10\xd9\xbb6P]\xceo\x7f\x8dbA\x06\x12\x8eE\xf5\x17\x8fBm&c\xde\x02Oll\xe9jG\xa3N\xb4\x16\x8e\xdfV\x90\x05\x92\xd3\x16\xc7[\xe9\xbb\xec,\x11\xb4\x00\x86\x01\xaaWG\xc2Gd0(2\x1bN\xb3\xd6\xfe\x9fG&\xd2CaX\xd8t\x01q\xaf{;W\xbe\xf2", readable=True)
@@ -146,7 +146,7 @@ tbs.version == None
 
 = CRL class : Signature algorithm (as advertised by TBSCertList)
 assert(type(tbs.signature) is X509_AlgorithmIdentifier)
-tbs.signature.algorithm == ASN1_OID("sha1-with-rsa-signature")
+tbs.signature.algorithm == ASN1_OID("sha1_with_rsa_signature")
 
 = CRL class : Issuer structure
 assert(type(tbs.issuer) is list)
@@ -180,7 +180,7 @@ tbs.crlExtensions == None
 
 = CRL class : Signature algorithm
 assert(type(x.signatureAlgorithm) is X509_AlgorithmIdentifier)
-x.signatureAlgorithm.algorithm == ASN1_OID("sha1-with-rsa-signature")
+x.signatureAlgorithm.algorithm == ASN1_OID("sha1_with_rsa_signature")
 
 = CRL class : Signature value
 x.signatureValue == ASN1_BIT_STRING('"\xc9\xf6\xbb\x1d\xa1\xa5=$\xc7\xff\xb0"\x11\xb3p\x06[\xc5U\xdd3v\xa0\x98"\x08cDi\xcfOG%w\x99\x12\x84\xd2\x19\xae \x94\xca,T\x9ak\x81\xd2\x038\xa6Z\x95\x8d*\xe2a\xce\xdb\x19\xcdu\'Y&|V\xe1\xe4\x80q\x1aI\xb2\xaa\xcdI[\xda\x0f\xa8\xff\xce<\n\xfc\xc9\xad\xc6\xde\xc8@d\x0c&\t#\x90\xb7\x9c\xb9P\x03\x8fK\x18\x9f\xb0\xe0e\x0f`\x1c\x1ag\xe5\x85\xc4%\xf5\x0b\xc93\x82R\xe6', readable=True)
@@ -215,7 +215,7 @@ response = OCSP_Response(s)
 assert(response.responseStatus.val == 0)
 assert(isinstance(response.responseBytes, OCSP_ResponseBytes))
 responseBytes = response.responseBytes
-assert(responseBytes.responseType == ASN1_OID("basic-response"))
+assert(responseBytes.responseType == ASN1_OID("basic_response"))
 assert(responseBytes.signatureAlgorithm.algorithm == ASN1_OID("sha256WithRSAEncryption"))
 assert(responseBytes.signatureAlgorithm.parameters == ASN1_NULL(0))
 assert(responseBytes.signature.val_readable[:3] == "\x90\xef\xf9" and responseBytes.signature.val_readable[-3:] == "\x8bb\xfc")