diff --git a/scapy/arch/bpf/supersocket.py b/scapy/arch/bpf/supersocket.py
index e3a6b6d003662f94adb6b59269469bcced12031d..3903fa4574ea2e5c64382bc6a39cf8133e100c8a 100644
--- a/scapy/arch/bpf/supersocket.py
+++ b/scapy/arch/bpf/supersocket.py
@@ -4,25 +4,28 @@
 Scapy *BSD native support - BPF sockets
 """
 
+import errno
+import fcntl
+import os
+from select import select
+import struct
+import time
+
+from scapy.arch.bpf.core import get_dev_bpf, attach_filter
+from scapy.arch.bpf.consts import BIOCGBLEN, BIOCGDLT, BIOCGSTATS, \
+    BIOCIMMEDIATE, BIOCPROMISC, BIOCSBLEN, BIOCSETIF, BIOCSHDRCMPLT, \
+    BPF_BUFFER_LENGTH
 from scapy.config import conf
+from scapy.consts import FREEBSD, NETBSD
+from scapy.data import ETH_P_ALL
 from scapy.error import Scapy_Exception, warning
 from scapy.supersocket import SuperSocket
-from scapy.layers.l2 import Ether
-from scapy.layers.inet import IP
-from scapy.layers.inet6 import IPv6
-from scapy.packet import Raw
-from scapy.data import ETH_P_ALL
-from scapy.consts import FREEBSD, OPENBSD, NETBSD
 
-from scapy.arch.bpf.core import get_dev_bpf, attach_filter
-from scapy.arch.bpf.consts import *
 
-import struct
-import fcntl
-import os
-import time
-import errno
-from select import select
+if FREEBSD or NETBSD:
+    BPF_ALIGNMENT = 8  # sizeof(long)
+else:
+    BPF_ALIGNMENT = 4  # sizeof(int32_t)
 
 
 # SuperSockets definitions
@@ -56,16 +59,15 @@ class _L2bpfSocket(SuperSocket):
         # Set the BPF buffer length
         try:
             fcntl.ioctl(self.ins, BIOCSBLEN, struct.pack('I', BPF_BUFFER_LENGTH))
-        except IOError as err:
-            msg = "BIOCSBLEN failed on /dev/bpf%i" % self.dev_bpf
-            raise Scapy_Exception(msg)
+        except IOError:
+            raise Scapy_Exception("BIOCSBLEN failed on /dev/bpf%i" %
+                                  self.dev_bpf)
 
         # Assign the network interface to the BPF handle
         try:
             fcntl.ioctl(self.ins, BIOCSETIF, struct.pack("16s16x", self.iface))
-        except IOError as err:
-            msg = "BIOCSETIF failed on %s" % self.iface
-            raise Scapy_Exception(msg)
+        except IOError:
+            raise Scapy_Exception("BIOCSETIF failed on %s" % self.iface)
         self.assigned_interface = self.iface
 
         # Set the interface into promiscuous
@@ -75,17 +77,17 @@ class _L2bpfSocket(SuperSocket):
         # Don't block on read
         try:
             fcntl.ioctl(self.ins, BIOCIMMEDIATE, struct.pack('I', 1))
-        except IOError as err:
-            msg = "BIOCIMMEDIATE failed on /dev/bpf%i" % self.dev_bpf
-            raise Scapy_Exception(msg)
+        except IOError:
+            raise Scapy_Exception("BIOCIMMEDIATE failed on /dev/bpf%i" %
+                                  self.dev_bpf)
 
         # Scapy will provide the link layer source address
         # Otherwise, it is written by the kernel
         try:
             fcntl.ioctl(self.ins, BIOCSHDRCMPLT, struct.pack('i', 1))
-        except IOError as err:
-            msg = "BIOCSHDRCMPLT failed on /dev/bpf%i" % self.dev_bpf
-            raise Scapy_Exception(msg)
+        except IOError:
+            raise Scapy_Exception("BIOCSHDRCMPLT failed on /dev/bpf%i" %
+                                  self.dev_bpf)
 
         # Configure the BPF filter
         if not nofilter:
@@ -105,13 +107,16 @@ class _L2bpfSocket(SuperSocket):
 
         try:
             fcntl.ioctl(self.ins, BIOCPROMISC, struct.pack('i', value))
-        except IOError as err:
-            msg = "Can't put your interface (%s) into promiscuous mode !" % self.iface
-            raise Scapy_Exception(msg)
+        except IOError:
+            raise Scapy_Exception("Cannot set promiscuous mode on interface "
+                                  "(%s)!" % self.iface)
 
     def __del__(self):
         """Close the file descriptor on delete"""
-        self.close()
+        # When the socket is deleted on Scapy exits, __del__ is
+        # sometimes called "too late", and self is None
+        if self is not None:
+            self.close()
 
     def guess_cls(self):
         """Guess the packet class that must be used on the interface"""
@@ -120,21 +125,18 @@ class _L2bpfSocket(SuperSocket):
         try:
             ret = fcntl.ioctl(self.ins, BIOCGDLT, struct.pack('I', 0))
             ret = struct.unpack('I', ret)[0]
-        except IOError as err:
-            warning("BIOCGDLT failed: unable to guess type. Using Ethernet !")
-            return Ether
-
-        # *BSD loopback interface
-        if OPENBSD and ret == 12:  # DTL_NULL on OpenBSD
-            return Loopback
+        except IOError:
+            cls = conf.default_l2
+            warning("BIOCGDLT failed: unable to guess type. Using %s !",
+                    cls.name)
+            return cls
 
         # Retrieve the corresponding class
-        cls = conf.l2types.get(ret, None)
-        if cls is None:
-            cls = Ether
-            warning("Unable to guess type. Using Ethernet !")
-
-        return cls
+        try:
+            return conf.l2types[ret]
+        except KeyError:
+            cls = conf.default_l2
+            warning("Unable to guess type (type %i). Using %s", ret, cls.name)
 
     def set_nonblock(self, set_flag=True):
         """Set the non blocking flag on the socket"""
@@ -143,8 +145,8 @@ class _L2bpfSocket(SuperSocket):
         if self.fd_flags is None:
             try:
                 self.fd_flags = fcntl.fcntl(self.ins, fcntl.F_GETFL)
-            except IOError as err:
-                warning("Can't get flags on this file descriptor !")
+            except IOError:
+                warning("Cannot get flags on this file descriptor !")
                 return
 
         # Set the non blocking flag
@@ -165,7 +167,7 @@ class _L2bpfSocket(SuperSocket):
         try:
             ret = fcntl.ioctl(self.ins, BIOCGSTATS, struct.pack("2I", 0, 0))
             return struct.unpack("2I", ret)
-        except IOError as err:
+        except IOError:
             warning("Unable to get stats from BPF !")
             return (None, None)
 
@@ -175,7 +177,7 @@ class _L2bpfSocket(SuperSocket):
         try:
             ret = fcntl.ioctl(self.ins, BIOCGBLEN, struct.pack("I", 0))
             return struct.unpack("I", ret)[0]
-        except IOError as err:
+        except IOError:
             warning("Unable to get the BPF buffer length")
             return
 
@@ -211,25 +213,15 @@ class L2bpfListenSocket(_L2bpfSocket):
 
     def get_frame(self):
         """Get a frame or packet from the received list"""
-
         if self.received_frames:
-            pkt = self.received_frames.pop(0)
-            if isinstance(self, L3bpfSocket):
-                pkt = pkt.payload
-            return pkt
+            return self.received_frames.pop(0)
 
-        return None
-
-    def bpf_align(self, bh_h, bh_c):
+    @staticmethod
+    def bpf_align(bh_h, bh_c):
         """Return the index to the end of the current packet"""
 
-        if FREEBSD or NETBSD:
-            BPF_ALIGNMENT = 8  # sizeof(long)
-        else:
-            BPF_ALIGNMENT = 4  # sizeof(int32_t)
-
-        x = bh_h + bh_c
-        return ((x)+(BPF_ALIGNMENT-1)) & ~(BPF_ALIGNMENT-1)  # from <net/bpf.h>
+        # from <net/bpf.h>
+        return ((bh_h + bh_c)+(BPF_ALIGNMENT-1)) & ~(BPF_ALIGNMENT-1)
 
     def extract_frames(self, bpf_buffer):
         """Extract all frames from the buffer and stored them in the received list."""
@@ -263,7 +255,7 @@ class L2bpfListenSocket(_L2bpfSocket):
         except:
             if conf.debug_dissector:
                 raise
-            pkt = Raw(frame_str)
+            pkt = conf.raw_layer(frame_str)
         self.received_frames.append(pkt)
 
         # Extract the next frame
@@ -278,20 +270,17 @@ class L2bpfListenSocket(_L2bpfSocket):
             # Get a frame from the buffer
             return self.get_frame()
 
-        else:
-            # Get data from BPF
-            try:
-                bpf_buffer = os.read(self.ins, x)
-            except EnvironmentError as e:
-                if e.errno == errno.EAGAIN:
-                    return
-                else:
-                    warning("BPF recv(): %s" % e)
-                    return
+        # Get data from BPF
+        try:
+            bpf_buffer = os.read(self.ins, x)
+        except EnvironmentError as exc:
+            if exc.errno != errno.EAGAIN:
+                warning("BPF recv()", exc_info=True)
+            return
 
-            # Extract all frames from the BPF buffer
-            self.extract_frames(bpf_buffer)
-            return self.get_frame()
+        # Extract all frames from the BPF buffer
+        self.extract_frames(bpf_buffer)
+        return self.get_frame()
 
 
 class L2bpfSocket(L2bpfListenSocket):
@@ -308,34 +297,35 @@ class L2bpfSocket(L2bpfListenSocket):
             # Get a frame from the buffer
             return self.get_frame()
 
-        else:
-            # Set the non blocking flag, read from the socket, and unset the flag
-            self.set_nonblock(True)
-            pkt = L2bpfListenSocket.recv(self)
-            self.set_nonblock(False)
-            return pkt
+        # Set the non blocking flag, read from the socket, and unset the flag
+        self.set_nonblock(True)
+        pkt = L2bpfListenSocket.recv(self)
+        self.set_nonblock(False)
+        return pkt
 
 
 class L3bpfSocket(L2bpfSocket):
 
+    def get_frame(self):
+        """Get a frame or packet from the received list"""
+        pkt = super(L3bpfSocket, self).get_frame()
+        if pkt is not None:
+            return pkt.payload
+
     def send(self, pkt):
         """Send a packet"""
 
         # Use the routing table to find the output interface
-        if isinstance(pkt, IPv6):
-            iff, a, gw = conf.route6.route(pkt.dst)
-        if isinstance(pkt, IP):
-            iff, a, gw = conf.route.route(pkt.dst)
-        else:
+        iff = pkt.route()[0]
+        if iff is None:
             iff = conf.iface
 
         # Assign the network interface to the BPF handle
         if self.assigned_interface != iff:
             try:
                 fcntl.ioctl(self.outs, BIOCSETIF, struct.pack("16s16x", iff))
-            except IOError as err:
-                msg = "BIOCSETIF failed on %s" % iff
-                raise Scapy_Exception(msg)
+            except IOError:
+                raise Scapy_Exception("BIOCSETIF failed on %s" % iff)
             self.assigned_interface = iff
 
         # Build the frame
diff --git a/scapy/error.py b/scapy/error.py
index 793e220bb8a8acab44356881c68b7f96fc094696..d7273447d018e12e15534362ebf43fd3ffdfccf8 100644
--- a/scapy/error.py
+++ b/scapy/error.py
@@ -64,14 +64,13 @@ log_interactive = logging.getLogger("scapy.interactive")  # logs in interactive
 log_loading = logging.getLogger("scapy.loading")          # logs when loading Scapy
 
 
-def warning(x, onlyOnce=None):
+def warning(x, *args, **kargs):
     """
     Prints a warning during runtime.
 
     onlyOnce - if True, the warning will never be printed again.
     """ 
-    if onlyOnce:
+    if kargs.pop("onlyOnce", False):
         from scapy.config import conf
         conf.warning_next_only_once = True
-    log_runtime.warning(x)
-
+    log_runtime.warning(x, *args, **kargs)
diff --git a/scapy/layers/all.py b/scapy/layers/all.py
index 18e8e2a1508db0f63122f2461d7413e9736e4f9c..20a991d0778577a117fd26b3dd838c4c7cb4b141 100644
--- a/scapy/layers/all.py
+++ b/scapy/layers/all.py
@@ -10,6 +10,7 @@ All layers. Configurable with conf.load_layers.
 from __future__ import absolute_import
 from scapy.config import conf
 from scapy.error import log_loading
+from scapy.main import load_layer
 import logging, importlib
 import scapy.modules.six as six
 ignored = list(six.moves.builtins.__dict__.keys()) + ["sys"]
@@ -17,36 +18,11 @@ log = logging.getLogger("scapy.loading")
 
 __all__ = []
 
-
-def _validate_local(x):
-    """Returns whether or not a variable should be imported.
-    Will return False for any default modules (sys), or if
-    they are detected as private vars (starting with a _)"""
-    global ignored
-    return x[0] != "_" and not x in ignored
-
-def _import_star(m):
-    mod = importlib.import_module("." + m, "scapy.layers")
-    if '__all__' in mod.__dict__:
-        # only import the exported symbols in __all__
-        for name in mod.__dict__['__all__']:
-            __all__.append(name)
-            globals()[name] = mod.__dict__[name]
-    else:
-        # import all the non-private symbols
-        for name, sym in six.iteritems(mod.__dict__):
-            if _validate_local(name):
-                __all__.append(name)
-                globals()[name] = sym
-
-LAYER_ALIASES = {
-    "tls": "tls.all",
-}
-
 for _l in conf.load_layers:
     log_loading.debug("Loading layer %s" % _l)
     try:
-        _import_star(LAYER_ALIASES.get(_l, _l))
+        load_layer(_l, globals_dict=globals(), symb_list=__all__)
     except Exception as e:
         log.warning("can't import layer %s: %s" % (_l,e))
 
+del _l
diff --git a/scapy/layers/dhcp6.py b/scapy/layers/dhcp6.py
index 616048600ec93903164fd14121663e29ece11fdd..e87eba4a2bcedec8a49a5c7c653054997eafbbe6 100644
--- a/scapy/layers/dhcp6.py
+++ b/scapy/layers/dhcp6.py
@@ -12,16 +12,25 @@ DHCPv6: Dynamic Host Configuration Protocol for IPv6. [RFC 3315]
 
 from __future__ import print_function
 import socket
+import struct
+import time
 
-from scapy.packet import *
-from scapy.fields import *
-from scapy.data import *
-from scapy.utils6 import *
-from scapy.themes import Color
-from scapy.layers.inet6 import *
 from scapy.ansmachine import AnsweringMachine
-from scapy.sendrecv import *
+from scapy.arch import get_if_raw_hwaddr, in6_getifaddr
+from scapy.config import conf
+from scapy.data import EPOCH, ETHER_ANY
 from scapy.error import warning
+from scapy.fields import BitField, ByteEnumField, ByteField, FieldLenField, \
+    FlagsField, IntEnumField, IntField, MACField, PacketField, \
+    PacketListField, ShortEnumField, ShortField, StrField, StrFixedLenField, \
+    StrLenField, UTCTimeField, X3BytesField, XIntField, XShortEnumField
+from scapy.layers.inet import UDP
+from scapy.layers.inet6 import DomainNameListField, IP6Field, IP6ListField, IPv6
+from scapy.packet import Packet, bind_bottom_up
+from scapy.pton_ntop import inet_pton
+from scapy.sendrecv import send
+from scapy.themes import Color
+from scapy.utils6 import in6_addrtovendor, in6_islladdr
 
 #############################################################################
 # Helpers                                                                  ##
@@ -1330,9 +1339,8 @@ DHCPv6_am.parse_options( dns="2001:500::1035", domain="localdomain, local",
             self.duid = duid
         else:
             # Timeval
-            from time import gmtime, strftime, mktime
             epoch = (2000, 1, 1, 0, 0, 0, 5, 1, 0)
-            delta = mktime(epoch) - EPOCH
+            delta = time.mktime(epoch) - EPOCH
             timeval = time.time() - delta
 
             # Mac Address
@@ -1368,7 +1376,6 @@ DHCPv6_am.parse_options( dns="2001:500::1035", domain="localdomain, local",
             return False
 
         src = p[IPv6].src
-        dst = p[IPv6].dst
 
         p = p[IPv6].payload 
         if not isinstance(p, UDP) or p.sport != 546 or p.dport != 547 :
@@ -1451,7 +1458,7 @@ DHCPv6_am.parse_options( dns="2001:500::1035", domain="localdomain, local",
                 it = it.payload
                     
             addrs = [bo + x + n for x in addrs]
-            if debug:
+            if self.debug:
                 msg = r + "[DEBUG]" + n + " Received " + g + "Decline" + n 
                 msg += " from " + bo + src + vendor + " for "
                 msg += ", ".join(addrs)+ n
@@ -1515,12 +1522,8 @@ DHCPv6_am.parse_options( dns="2001:500::1035", domain="localdomain, local",
         print("Sent %s answering to %s from %s%s" % (reptype, reqtype, reqsrc, vendor))
 
     def make_reply(self, req):
-        req_mac_src = req.src
-        req_mac_dst = req.dst
-
         p = req[IPv6]
         req_src = p.src
-        req_dst = p.dst
 
         p = p.payload.payload
 
diff --git a/scapy/layers/inet.py b/scapy/layers/inet.py
index 6c469416003fd4a38ecbb9ab0c3f870c4a9419ea..be474e653b4279436ecdf3b2abb2e15a3e740f11 100644
--- a/scapy/layers/inet.py
+++ b/scapy/layers/inet.py
@@ -18,7 +18,7 @@ from scapy.base_classes import Gen
 from scapy.data import *
 from scapy.layers.l2 import *
 from scapy.config import conf
-from scapy.consts import WINDOWS
+from scapy.consts import OPENBSD, WINDOWS
 from scapy.fields import *
 from scapy.packet import *
 from scapy.volatile import *
@@ -796,6 +796,7 @@ bind_layers( Ether,         IP,            type=2048)
 bind_layers( CookedLinux,   IP,            proto=2048)
 bind_layers( GRE,           IP,            proto=2048)
 bind_layers( SNAP,          IP,            code=2048)
+bind_layers( Loopback,      IP,            type=0)
 bind_layers( Loopback,      IP,            type=2)
 bind_layers( IPerror,       IPerror,       frag=0, proto=4)
 bind_layers( IPerror,       ICMPerror,     frag=0, proto=1)
@@ -808,7 +809,9 @@ bind_layers( IP,            UDP,           frag=0, proto=17)
 bind_layers( IP,            GRE,           frag=0, proto=47)
 
 conf.l2types.register(101, IP)
-conf.l2types.register_num2layer(12, IP)
+if not OPENBSD:
+    # see scapy.layers.l2.py
+    conf.l2types.register_num2layer(12, IP)
 conf.l2types.register(DLT_IPV4, IP)
 
 conf.l3types.register(ETH_P_IP, IP)
diff --git a/scapy/layers/l2.py b/scapy/layers/l2.py
index ae6dc5c0b8db7b12cc4e507b2c968bf221891fc3..d8f540d77bcb1e49499510a7763c0d4067337131 100644
--- a/scapy/layers/l2.py
+++ b/scapy/layers/l2.py
@@ -13,6 +13,7 @@ import os, struct, time, socket
 
 from scapy.base_classes import Net
 from scapy.config import conf
+from scapy.consts import OPENBSD
 from scapy.data import *
 from scapy.packet import *
 from scapy.ansmachine import *
@@ -447,6 +448,9 @@ conf.l2types.register_layer2num(ARPHDR_ETHER, Dot3)
 conf.l2types.register(144, CookedLinux)  # called LINUX_IRDA, similar to CookedLinux
 conf.l2types.register(113, CookedLinux)
 conf.l2types.register(DLT_NULL, Loopback)
+# Under OpenBSD, for some reason, DLT_NULL == 12
+if OPENBSD:
+    conf.l2types.register(12, Loopback)
 
 conf.l3types.register(ETH_P_ARP, ARP)
 
diff --git a/scapy/main.py b/scapy/main.py
index 287bcd7d3857169aa135ffe4e68c935b9807485c..fda7e96847502566b18efe5305f88289dac5e16e 100644
--- a/scapy/main.py
+++ b/scapy/main.py
@@ -18,7 +18,10 @@ import importlib
 ignored = list(six.moves.builtins.__dict__.keys())
 
 from scapy.error import *
-from scapy.layers.all import LAYER_ALIASES
+
+LAYER_ALIASES = {
+    "tls": "tls.all"
+}
 
 def _probe_config_file(cf):
     cf_path = os.path.join(os.path.expanduser("~"), cf)
@@ -65,28 +68,57 @@ from scapy.themes import DefaultTheme
 ######################
 
 
-def _load(module):
+def _load(module, globals_dict=None, symb_list=None):
+    """Loads a Python module to make variables, objects and functions
+available globally.
+
+    The idea is to load the module using importlib, then copy the
+symbols to the global symbol table.
+
+    """
+    if globals_dict is None:
+        globals_dict = six.moves.builtins.__dict__
     try:
         mod = importlib.import_module(module)
         if '__all__' in mod.__dict__:
             # import listed symbols
             for name in mod.__dict__['__all__']:
-                six.moves.builtins.__dict__[name] = mod.__dict__[name]
+                if symb_list is not None:
+                    symb_list.append(name)
+                globals_dict[name] = mod.__dict__[name]
         else:
             # only import non-private symbols
             for name, sym in six.iteritems(mod.__dict__):
                 if _validate_local(name):
-                    six.moves.builtins.__dict__[name] = sym
-    except Exception as e:
-        log_interactive.error(e)
+                    if symb_list is not None:
+                        symb_list.append(name)
+                    globals_dict[name] = sym
+    except Exception:
+        log_interactive.error("Loading module %s", module, exc_info=True)
 
 def load_module(name):
+    """Loads a Scapy module to make variables, objects and functions
+    available globally.
+
+    """
     _load("scapy.modules."+name)
 
-def load_layer(name):
-    _load("scapy.layers." + LAYER_ALIASES.get(name, name))
+def load_layer(name, globals_dict=None, symb_list=None):
+    """Loads a Scapy layer module to make variables, objects and functions
+    available globally.
+
+    """
+    _load("scapy.layers." + LAYER_ALIASES.get(name, name),
+          globals_dict=globals_dict, symb_list=symb_list)
 
 def load_contrib(name):
+    """Loads a Scapy contrib module to make variables, objects and
+    functions available globally.
+
+    If no contrib module can be found with the given name, try to find
+    a layer module, since a contrib module may become a layer module.
+
+    """
     try:
         importlib.import_module("scapy.contrib." + name)
         _load("scapy.contrib." + name)
diff --git a/scapy/route.py b/scapy/route.py
index c8b8fa4e67d9859e49b84486d056165a20d5ad42..c6a973de5b60688d3e79c46203ef483913fa6b69 100644
--- a/scapy/route.py
+++ b/scapy/route.py
@@ -8,7 +8,6 @@ Routing and handling of network interfaces.
 """
 
 from __future__ import absolute_import
-import socket
 from scapy.consts import LOOPBACK_NAME, LOOPBACK_INTERFACE
 from scapy.utils import atol, ltoa, itom, pretty_routes
 from scapy.config import conf