diff --git a/scapy/contrib/bgp.py b/scapy/contrib/bgp.py
index a0a5fdadc55a7e1084625a2720eed8a5ae0b9853..87ea38f71e252d8da63cd914e92257cfe00ab293 100644
--- a/scapy/contrib/bgp.py
+++ b/scapy/contrib/bgp.py
@@ -607,28 +607,18 @@ class BGPCapability(six.with_metaclass(_BGPCapability_metaclass, Packet)):
 
     # Every BGP capability object inherits from BGPCapability.
     def haslayer(self, cls):
-        ret = 0
-        if cls == BGPCapability:
-            # If cls is BGPCap (the parent class), check that the object is an
-            # instance of an existing BGP capability class.
-            for cap_class in _capabilities_registry:
-                if isinstance(self, _capabilities_registry[cap_class]):
-                    ret = 1
-                    break
-        elif cls in _capabilities_registry and isinstance(self, cls):
-            ret = 1
-        return ret
-
-    def getlayer(self, cls, nb=1, _track=None):
-        layer = None
-        if cls == BGPCapability:
-            for cap_class in _capabilities_registry:
-                if isinstance(self, _capabilities_registry[cap_class]):
-                    layer = self
-                    break
-        else:
-            layer = Packet.getlayer(self, cls, nb, _track)
-        return layer
+        if cls == "BGPCapability":
+            if isinstance(self, BGPCapability):
+                return True
+        if issubclass(cls, BGPCapability):
+            if isinstance(self, cls):
+                return True
+        return super(BGPCapability, self).haslayer(cls)
+
+    def getlayer(self, cls, nb=1, _track=None, _subclass=True, **flt):
+        return super(BGPCapability, self).getlayer(
+            cls, nb=nb, _track=_track, _subclass=True, **flt
+        )
 
     def post_build(self, p, pay):
         length = 0
diff --git a/scapy/contrib/bgp.uts b/scapy/contrib/bgp.uts
index 521abe07c42f71309d5fe2a4dcead1f7e3ddc905..55eb506ba5e442a44fc82032c2eb980a822f6c8e 100644
--- a/scapy/contrib/bgp.uts
+++ b/scapy/contrib/bgp.uts
@@ -119,10 +119,12 @@ except _BGPInvalidDataException:
   True
 
 = BGPCapability - Test haslayer()
-BGPCapFourBytesASN().haslayer(BGPCapability) == True
+assert BGPCapFourBytesASN().haslayer(BGPCapability)
+assert BGPCapability in BGPCapFourBytesASN()
 
 = BGPCapability - Test getlayer()
-isinstance(BGPCapFourBytesASN().getlayer(BGPCapability), BGPCapFourBytesASN)
+assert isinstance(BGPCapFourBytesASN().getlayer(BGPCapability), BGPCapFourBytesASN)
+assert isinstance(BGPCapFourBytesASN()[BGPCapability], BGPCapFourBytesASN)
 
 
 ############################ BGPCapMultiprotocol ##############################
diff --git a/scapy/layers/eap.py b/scapy/layers/eap.py
index b441ff446d83af59506e04710e10a0df29d76689..f5b49764910528915b4f77a381470f78d517b003 100644
--- a/scapy/layers/eap.py
+++ b/scapy/layers/eap.py
@@ -238,26 +238,17 @@ class EAP(Packet):
         return cls
 
     def haslayer(self, cls):
-        ret = 0
-        if cls == EAP:
-            for eap_class in EAP.registered_methods.values():
-                if isinstance(self, eap_class):
-                    ret = 1
-                    break
-        elif cls in list(EAP.registered_methods.values()) and isinstance(self, cls):
-            ret = 1
-        return ret
-
-    def getlayer(self, cls, nb=1, _track=None):
-        layer = None
-        if cls == EAP:
-            for eap_class in EAP.registered_methods.values():
-                if isinstance(self, eap_class):
-                    layer = self
-                    break
-        else:
-            layer = Packet.getlayer(self, cls, nb, _track)
-        return layer
+        if cls == "EAP":
+            if isinstance(self, EAP):
+                return True
+        elif issubclass(cls, EAP):
+            if isinstance(self, cls):
+                return True
+        return super(EAP, self).haslayer(cls)
+
+    def getlayer(self, cls, nb=1, _track=None, _subclass=True, **flt):
+        return super(EAP, self).getlayer(cls, nb=nb, _track=_track,
+                                         _subclass=True, **flt)
 
     def answers(self, other):
         if isinstance(other, EAP):
diff --git a/scapy/layers/ntp.py b/scapy/layers/ntp.py
index 2e75067e27a55278e5c803d85e9a40a0fd6d6e96..f8dbe16b45c95e9f6fe0c42152bfc2b25489b95e 100644
--- a/scapy/layers/ntp.py
+++ b/scapy/layers/ntp.py
@@ -95,14 +95,6 @@ class TimeStampField(FixedPointField):
         return FixedPointField.i2m(self, pkt, val)
 
 
-def get_cls(name, fallback_cls=conf.raw_layer):
-    """
-    Returns class named "name" if it exists, fallback_cls otherwise.
-    """
-
-    return globals().get(name, fallback_cls)
-
-
 #############################################################################
 ##### NTP
 #############################################################################
@@ -172,42 +164,22 @@ _kiss_codes = {
 
 
 # Used by _ntp_dispatcher to instantiate the appropriate class
-_ntp_cls_by_mode = {
-    0: "NTPHeader",
-    1: "NTPHeader",
-    2: "NTPHeader",
-    3: "NTPHeader",
-    4: "NTPHeader",
-    5: "NTPHeader",
-    6: "NTPControl",
-    7: "NTPPrivate"
-}
-
-
 def _ntp_dispatcher(payload):
     """
     Returns the right class for a given NTP packet.
     """
-
-    cls = conf.raw_layer
-
     # By default, calling NTP() will build a NTP packet as defined in RFC 5905
     # (see the code of NTPHeader). Use NTPHeader for extension fields and MAC.
     if payload is None:
-        cls = get_cls("NTPHeader")
-
+        return NTPHeader
     else:
         length = len(payload)
         if length >= _NTP_PACKET_MIN_SIZE:
             first_byte = orb(payload[0])
-
             # Extract NTP mode
-            mode_mask = 0x07
-            mode = first_byte & mode_mask
-
-            cls = get_cls(_ntp_cls_by_mode.get(mode))
-
-    return cls
+            mode = first_byte & 7
+            return {6: NTPControl, 7: NTPPrivate}.get(mode, NTPHeader)
+    return conf.raw_layer
 
 
 class NTP(Packet):
@@ -238,38 +210,18 @@ class NTP(Packet):
     # NTPHeader, NTPControl and NTPPrivate are NTP packets.
     # This might help, for example when reading a pcap file.
     def haslayer(self, cls):
-        ntp_classes = [
-            get_cls("NTPHeader"),
-            get_cls("NTPControl"),
-            get_cls("NTPPrivate")
-        ]
-        ret = 0
-        if cls == NTP:
-            # If cls is NTP (the parent class), check that the object is an
-            # instance of a NTP packet
-            for ntp_class in ntp_classes:
-                if isinstance(self, ntp_class):
-                    ret = 1
-                    break
-        elif cls in ntp_classes and isinstance(self, cls):
-            ret = 1
-        return ret
-
-    def getlayer(self, cls, nb=1, _track=None):
-        ntp_classes = [
-            get_cls("NTPHeader"),
-            get_cls("NTPControl"),
-            get_cls("NTPPrivate")
-        ]
-        layer = None
-        if cls == NTP:
-            for ntp_class in ntp_classes:
-                if isinstance(self, ntp_class):
-                    layer = self
-                    break
-        else:
-            layer = Packet.getlayer(self, cls, nb, _track)
-        return layer
+        """Specific: NTPHeader().haslayer(NTP) should return True."""
+        if cls == "NTP":
+            if isinstance(self, NTP):
+                return True
+        elif issubclass(cls, NTP):
+            if isinstance(self, cls):
+                return True
+        return super(NTP, self).haslayer(cls)
+
+    def getlayer(self, cls, nb=1, _track=None, _subclass=True, **flt):
+        return super(NTP, self).getlayer(cls, nb=nb, _track=_track,
+                                         _subclass=True, **flt)
 
     def mysummary(self):
         return self.sprintf("NTP v%ir,NTP.version%, %NTP.mode%")
diff --git a/scapy/layers/radius.py b/scapy/layers/radius.py
index 9b7507fbdbf60776032bcedf235a8de8babf926d..ada1cb4243857b5f0d5857e96ac2c3e134beac27 100644
--- a/scapy/layers/radius.py
+++ b/scapy/layers/radius.py
@@ -270,25 +270,17 @@ class RadiusAttribute(Packet):
         return cls
 
     def haslayer(self, cls):
-        if cls == RadiusAttribute:
-            for attr_class in RadiusAttribute.registered_attributes.values():
-                if isinstance(self, attr_class):
-                    return True
-        elif cls in RadiusAttribute.registered_attributes.values() and isinstance(self, cls):
-            return True
-        return False
-
-    def getlayer(self, cls, nb=1, _track=None):
-        layer = None
-        if cls == RadiusAttribute:
-            for attr_class in RadiusAttribute.registered_attributes.values():
-                if isinstance(self, attr_class):
-                    layer = self
-                    break
-        else:
-            layer = Packet.getlayer(self, cls, nb, _track)
-        return layer
-
+        if cls == "RadiusAttribute":
+            if isinstance(self, RadiusAttribute):
+                return True
+        elif issubclass(cls, RadiusAttribute):
+            if isinstance(self, cls):
+                return True
+        return super(RadiusAttribute, self).haslayer(cls)
+
+    def getlayer(self, cls, nb=1, _track=None, _subclass=True, **flt):
+        return super(RadiusAttribute, self).getlayer(cls, nb=nb, _track=_track,
+                                                     _subclass=True, **flt)
 
     def post_build(self, p, pay):
         length = self.len
diff --git a/scapy/packet.py b/scapy/packet.py
index 326f15b1a538bd290fe23eac339f560f72853c32..89184d1724565d819f243f21a0b67b8a89e2f585 100644
--- a/scapy/packet.py
+++ b/scapy/packet.py
@@ -888,8 +888,16 @@ class Packet(six.with_metaclass(Packet_metaclass, BasePacket)):
                     if ret:
                         return ret
         return self.payload.haslayer(cls)
-    def getlayer(self, cls, nb=1, _track=None):
-        """Return the nb^th layer that is an instance of cls."""
+
+    def getlayer(self, cls, nb=1, _track=None, _subclass=False, **flt):
+        """Return the nb^th layer that is an instance of cls, matching flt
+values.
+
+        """
+        if _subclass:
+            match = lambda cls1, cls2: issubclass(cls1, cls2)
+        else:
+            match = lambda cls1, cls2: cls1 == cls2
         if isinstance(cls, int):
             nb = cls+1
             cls = None
@@ -897,14 +905,16 @@ class Packet(six.with_metaclass(Packet_metaclass, BasePacket)):
             ccls,fld = cls.split(".",1)
         else:
             ccls,fld = cls,None
-        if cls is None or self.__class__ == cls or self.__class__.__name__ == ccls:
-            if nb == 1:
-                if fld is None:
-                    return self
+        if cls is None or match(self.__class__, cls) or self.__class__.__name__ == ccls:
+            if all(self.getfieldval(fldname) == fldvalue
+                   for fldname, fldvalue in flt.iteritems()):
+                if nb == 1:
+                    if fld is None:
+                        return self
+                    else:
+                        return self.getfieldval(fld)
                 else:
-                    return self.getfieldval(fld)
-            else:
-                nb -=1
+                    nb -=1
         for f in self.packetfields:
             fvalue_gen = self.getfieldval(f.name)
             if fvalue_gen is None:
@@ -914,11 +924,13 @@ class Packet(six.with_metaclass(Packet_metaclass, BasePacket)):
             for fvalue in fvalue_gen:
                 if isinstance(fvalue, Packet):
                     track=[]
-                    ret = fvalue.getlayer(cls, nb, _track=track)
+                    ret = fvalue.getlayer(cls, nb=nb, _track=track,
+                                          _subclass=_subclass)
                     if ret is not None:
                         return ret
                     nb = track[0]
-        return self.payload.getlayer(cls,nb,_track=_track)
+        return self.payload.getlayer(cls, nb=nb, _track=_track,
+                                     _subclass=_subclass, **flt)
 
     def firstlayer(self):
         q = self
@@ -930,13 +942,11 @@ class Packet(six.with_metaclass(Packet_metaclass, BasePacket)):
         if isinstance(cls, slice):
             lname = cls.start
             if cls.stop:
-                ret = self.getlayer(cls.start, cls.stop)
+                ret = self.getlayer(cls.start, nb=cls.stop, **(cls.step or {}))
             else:
-                ret = self.getlayer(cls.start)
-            if ret is None and cls.step is not None:
-                ret = cls.step
+                ret = self.getlayer(cls.start, **(cls.step or {}))
         else:
-            lname=cls
+            lname = cls
             ret = self.getlayer(cls)
         if ret is None:
             if isinstance(lname, Packet_metaclass):
@@ -1287,7 +1297,7 @@ class NoPayload(Packet):
         return isinstance(other, NoPayload) or isinstance(other, conf.padding_layer)
     def haslayer(self, cls):
         return 0
-    def getlayer(self, cls, nb=1, _track=None):
+    def getlayer(self, cls, nb=1, _track=None, **flt):
         if _track is not None:
             _track.append(nb)
         return None
diff --git a/test/regression.uts b/test/regression.uts
index 43e5543a7b89f3448c4f76dd3131ee2a23a7a345..c706feed4a1583cd0282d953ddee208b6be731af 100644
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -482,6 +482,37 @@ except IndexError:
 else:
     False
 
+= getlayer with a filter
+~ getlayer IP
+pkt = IP() / IP(ttl=3) / IP()
+assert pkt[IP::{"ttl":3}].ttl == 3
+assert pkt.getlayer(IP, ttl=3).ttl == 3
+
+= specific haslayer and getlayer implementations for NTP
+~ haslayer getlayer NTP
+pkt = IP() / UDP() / NTPHeader()
+assert NTP in pkt
+assert pkt.haslayer(NTP)
+assert isinstance(pkt[NTP], NTPHeader)
+assert isinstance(pkt.getlayer(NTP), NTPHeader)
+
+= specific haslayer and getlayer implementations for EAP
+~ haslayer getlayer EAP
+pkt = Ether() / EAPOL() / EAP_MD5()
+assert EAP in pkt
+assert pkt.haslayer(EAP)
+assert isinstance(pkt[EAP], EAP_MD5)
+assert isinstance(pkt.getlayer(EAP), EAP_MD5)
+
+= specific haslayer and getlayer implementations for RadiusAttribute
+~ haslayer getlayer RadiusAttribute
+pkt = RadiusAttr_EAP_Message()
+assert RadiusAttribute in pkt
+assert pkt.haslayer(RadiusAttribute)
+assert isinstance(pkt[RadiusAttribute], RadiusAttr_EAP_Message)
+assert isinstance(pkt.getlayer(RadiusAttribute), RadiusAttr_EAP_Message)
+
+
 = equality
 ~ basic
 w=Ether()/IP()/UDP(dport=53)
@@ -8645,6 +8676,11 @@ Dot11(type=0, subtype=1).answers(query) == True
 assert Dot11Elt(info="scapy").summary() == "SSID='scapy'"
 assert Dot11Elt(ID=1).mysummary() == ""
 
+= Multiple Dot11Elt layers
+pkt = Dot11() / Dot11Beacon() / Dot11Elt(ID="Rates") / Dot11Elt(ID="SSID", info="Scapy")
+assert pkt[Dot11Elt::{"ID": 0}].info == "Scapy"
+assert pkt.getlayer(Dot11Elt, ID=0).info == "Scapy"
+
 = Dot11WEP - build
 ~ crypto
 conf.wepkey = ""