diff --git a/scapy/fields.py b/scapy/fields.py
index 0dbe6910eba412c44c8f5ead1712f173fc499e3b..53f84727ca737ee33fc52d11438303d2aefc7554 100644
--- a/scapy/fields.py
+++ b/scapy/fields.py
@@ -798,32 +798,68 @@ class XBitField(BitField):
 
 class _EnumField(Field):
     def __init__(self, name, default, enum, fmt = "H"):
-        i2s = self.i2s = {}
-        s2i = self.s2i = {}
-        if type(enum) is list:
-            keys = range(len(enum))
+        """ Initializes enum fields.
+
+        @param name:    name of this field
+        @param default: default value of this field
+        @param enum:    either a dict or a tuple of two callables. Dict keys are
+                        the internal values, while the dict values are the
+                        user-friendly representations. If the tuple is provided,
+                        the first callable receives the internal value as
+                        parameter and returns the user-friendly representation
+                        and the second callable does the converse. The first
+                        callable may return None to default to a literal string
+                        (repr()) representation.
+        @param fmt:     struct.pack format used to parse and serialize the 
+			internal value from and to machine representation.
+        """
+        if isinstance(enum, tuple):
+            self.i2s_cb = enum[0]
+            self.s2i_cb = enum[1]
+            self.i2s = None
+            self.s2i = None
         else:
-            keys = enum.keys()
-        if any(type(x) is str for x in keys):
-            i2s, s2i = s2i, i2s
-        for k in keys:
-            i2s[k] = enum[k]
-            s2i[enum[k]] = k
+            i2s = self.i2s = {}
+            s2i = self.s2i = {}
+            self.i2s_cb = None
+            self.s2i_cb = None
+            if type(enum) is list:
+                keys = range(len(enum))
+            else:
+                keys = enum.keys()
+            if any(type(x) is str for x in keys):
+                i2s, s2i = s2i, i2s
+            for k in keys:
+                i2s[k] = enum[k]
+                s2i[enum[k]] = k
         Field.__init__(self, name, default, fmt)
+
     def any2i_one(self, pkt, x):
         if type(x) is str:
-            x = self.s2i[x]
+            try:
+                x = self.s2i[x]
+            except TypeError:
+                x = self.s2i_cb(x)
         return x
+
     def i2repr_one(self, pkt, x):
-        if self not in conf.noenum and not isinstance(x,VolatileValue) and x in self.i2s:
-            return self.i2s[x]
+        if self not in conf.noenum and not isinstance(x,VolatileValue):
+            try:
+                return self.i2s[x]
+            except KeyError:
+                pass
+            except TypeError:
+                ret = self.i2s_cb(x)
+                if ret is not None:
+                    return ret
         return repr(x)
     
     def any2i(self, pkt, x):
         if type(x) is list:
             return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x)
         else:
-            return self.any2i_one(pkt,x)        
+            return self.any2i_one(pkt,x)
+
     def i2repr(self, pkt, x):
         if type(x) is list:
             return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x)
@@ -831,17 +867,21 @@ class _EnumField(Field):
             return self.i2repr_one(pkt,x)
 
 class EnumField(_EnumField):
-    __slots__ = ["i2s", "s2i"]
+    __slots__ = ["i2s", "s2i", "s2i_cb", "i2s_cb"]
 
 class CharEnumField(EnumField):
     def __init__(self, name, default, enum, fmt = "1s"):
         EnumField.__init__(self, name, default, enum, fmt)
-        k = self.i2s.keys()
-        if k and len(k[0]) != 1:
-            self.i2s,self.s2i = self.s2i,self.i2s
+        if self.i2s is not None:
+            k = self.i2s.keys()
+            if k and len(k[0]) != 1:
+                self.i2s,self.s2i = self.s2i,self.i2s
     def any2i_one(self, pkt, x):
         if len(x) != 1:
-            x = self.s2i[x]
+            if self.s2i is None:
+                x = self.s2i_cb(x)
+            else:
+                x = self.s2i[x]
         return x
 
 class BitEnumField(BitField, _EnumField):
@@ -856,6 +896,7 @@ class BitEnumField(BitField, _EnumField):
         return _EnumField.i2repr(self, pkt, x)
 
 class ShortEnumField(EnumField):
+    __slots__ = EnumField.__slots__
     def __init__(self, name, default, enum):
         EnumField.__init__(self, name, default, enum, "H")
 
@@ -883,10 +924,18 @@ class LEIntEnumField(EnumField):
 
 class XShortEnumField(ShortEnumField):
     def i2repr_one(self, pkt, x):
-        if self not in conf.noenum and not isinstance(x,VolatileValue) and x in self.i2s:
-            return self.i2s[x]
+        if self not in conf.noenum and not isinstance(x,VolatileValue):
+            try:
+                return self.i2s[x]
+            except KeyError:
+                pass
+            except TypeError:
+                ret = self.i2s_cb(x)
+                if ret is not None:
+                    return ret
         return lhex(x)
 
+
 class _MultiEnumField(_EnumField):
     def __init__(self, name, default, enum, depends_on, fmt = "H"):
         
diff --git a/test/fields.uts b/test/fields.uts
index 653bf60d3e00a6c62c040a88be9c3833e6f07fb3..2c683f85cad881cbdd10dfd44b371ade811ccb2c 100644
--- a/test/fields.uts
+++ b/test/fields.uts
@@ -507,4 +507,265 @@ assert(re.match(r'^.*Star \(\*\).*$', x) is not None)
 assert(re.match(r'^.*Plus \(\+\).*$', x) is not None)
 assert(re.match(r'^.*bit 2.*$', x) is not None)
 
+############
+############
++ EnumField tests
+
+= EnumField tests initialization
+
+# Basic EnumField
+f = EnumField('test', 0, {0: 'Foo', 1: 'Bar'})
+# Reverse i2s/s2i
+rf = EnumField('test', 0, {'Foo': 0, 'Bar': 1})
+# EnumField initialized with a list
+lf = EnumField('test', 0, ['Foo', 'Bar'])
+# EnumField with i2s_cb/s2i_cb
+fcb = EnumField('test', 0, (
+        lambda x: 'Foo' if x == 0 else 'Bar' if 1 <= x <= 10 else repr(x),
+        lambda x: 0 if x == 'Foo' else 1 if x == 'Bar' else int(x),
+    )
+)
+
+def expect_exception(e, c):
+    try:
+        eval(c)
+        return False
+    except e:
+        return True
+
+
+= EnumField.any2i_one
+~ field enumfield
+
+assert(f.any2i_one(None, 'Foo') == 0)
+assert(f.any2i_one(None, 'Bar') == 1)
+assert(f.any2i_one(None, 2) == 2)
+expect_exception(KeyError, 'f.any2i_one(None, "Baz")')
+
+assert(rf.any2i_one(None, 'Foo') == 0)
+assert(rf.any2i_one(None, 'Bar') == 1)
+assert(rf.any2i_one(None, 2) == 2)
+expect_exception(KeyError, 'rf.any2i_one(None, "Baz")')
+
+assert(lf.any2i_one(None, 'Foo') == 0)
+assert(lf.any2i_one(None, 'Bar') == 1)
+assert(lf.any2i_one(None, 2) == 2)
+expect_exception(KeyError, 'lf.any2i_one(None, "Baz")')
+
+assert(fcb.any2i_one(None, 'Foo') == 0)
+assert(fcb.any2i_one(None, 'Bar') == 1)
+assert(fcb.any2i_one(None, 5) == 5)
+expect_exception(ValueError, 'fcb.any2i_one(None, "Baz")')
+
+True
+
+= EnumField.any2i
+~ field enumfield
+
+assert(f.any2i(None, 'Foo') == 0)
+assert(f.any2i(None, 'Bar') == 1)
+assert(f.any2i(None, 2) == 2)
+expect_exception(KeyError, 'f.any2i(None, "Baz")')
+assert(f.any2i(None, ['Foo', 'Bar', 2]) == [0, 1, 2])
+
+assert(rf.any2i(None, 'Foo') == 0)
+assert(rf.any2i(None, 'Bar') == 1)
+assert(rf.any2i(None, 2) == 2)
+expect_exception(KeyError, 'rf.any2i(None, "Baz")')
+assert(rf.any2i(None, ['Foo', 'Bar', 2]) == [0, 1, 2])
+
+assert(lf.any2i(None, 'Foo') == 0)
+assert(lf.any2i(None, 'Bar') == 1)
+assert(lf.any2i(None, 2) == 2)
+expect_exception(KeyError, 'lf.any2i(None, "Baz")')
+assert(lf.any2i(None, ['Foo', 'Bar', 2]) == [0, 1, 2])
+
+assert(fcb.any2i(None, 'Foo') == 0)
+assert(fcb.any2i(None, 'Bar') == 1)
+assert(fcb.any2i(None, 5) == 5)
+expect_exception(ValueError, 'fcb.any2i(None, "Baz")')
+assert(f.any2i(None, ['Foo', 'Bar', 5]) == [0, 1, 5])
+
+True
+
+= EnumField.i2repr_one
+~ field enumfield
+
+assert(f.i2repr_one(None, 0) == 'Foo')
+assert(f.i2repr_one(None, 1) == 'Bar')
+expect_exception(KeyError, 'f.i2repr_one(None, 2)')
+
+assert(rf.i2repr_one(None, 0) == 'Foo')
+assert(rf.i2repr_one(None, 1) == 'Bar')
+expect_exception(KeyError, 'rf.i2repr_one(None, 2)')
+
+assert(lf.i2repr_one(None, 0) == 'Foo')
+assert(lf.i2repr_one(None, 1) == 'Bar')
+expect_exception(KeyError, 'lf.i2repr_one(None, 2)')
+
+assert(fcb.i2repr_one(None, 0) == 'Foo')
+assert(fcb.i2repr_one(None, 1) == 'Bar')
+assert(fcb.i2repr_one(None, 5) == 'Bar')
+assert(fcb.i2repr_one(None, 11) == repr(11))
+
+conf.noenum.add(f, rf, lf, fcb)
+
+assert(f.i2repr_one(None, 0) == repr(0))
+assert(f.i2repr_one(None, 1) == repr(1))
+assert(f.i2repr_one(None, 2) == repr(2))
+
+assert(rf.i2repr_one(None, 0) == repr(0))
+assert(rf.i2repr_one(None, 1) == repr(1))
+assert(rf.i2repr_one(None, 2) == repr(2))
+
+assert(lf.i2repr_one(None, 0) == repr(0))
+assert(lf.i2repr_one(None, 1) == repr(1))
+assert(lf.i2repr_one(None, 2) == repr(2))
+
+assert(fcb.i2repr_one(None, 0) == repr(0))
+assert(fcb.i2repr_one(None, 1) == repr(1))
+assert(fcb.i2repr_one(None, 5) == repr(5))
+assert(fcb.i2repr_one(None, 11) == repr(11))
+
+conf.noenum.remove(f, rf, lf, fcb)
+
+assert(f.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
+assert(rf.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
+assert(lf.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
+assert(fcb.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
+
+True
+
+= EnumField.i2repr
+~ field enumfield
+
+assert(f.i2repr(None, 0) == 'Foo')
+assert(f.i2repr(None, 1) == 'Bar')
+expect_exception(KeyError, 'f.i2repr(None, 2)')
+assert(f.i2repr(None, [0, 1]) == ['Foo', 'Bar'])
+
+assert(rf.i2repr(None, 0) == 'Foo')
+assert(rf.i2repr(None, 1) == 'Bar')
+expect_exception(KeyError, 'rf.i2repr(None, 2)')
+assert(rf.i2repr(None, [0, 1]) == ['Foo', 'Bar'])
+
+assert(lf.i2repr(None, 0) == 'Foo')
+assert(lf.i2repr(None, 1) == 'Bar')
+expect_exception(KeyError, 'lf.i2repr(None, 2)')
+assert(lf.i2repr(None, [0, 1]) == ['Foo', 'Bar'])
+
+assert(fcb.i2repr(None, 0) == 'Foo')
+assert(fcb.i2repr(None, 1) == 'Bar')
+assert(fcb.i2repr(None, 5) == 'Bar')
+assert(fcb.i2repr(None, 11) == repr(11))
+assert(fcb.i2repr(None, [0, 1, 5, 11]) == ['Foo', 'Bar', 'Bar', repr(11)])
+
+conf.noenum.add(f, rf, lf, fcb)
+
+assert(f.i2repr(None, 0) == repr(0))
+assert(f.i2repr(None, 1) == repr(1))
+assert(f.i2repr(None, 2) == repr(2))
+assert(f.i2repr(None, [0, 1, 2]) == [repr(0), repr(1), repr(2)])
+
+assert(rf.i2repr(None, 0) == repr(0))
+assert(rf.i2repr(None, 1) == repr(1))
+assert(rf.i2repr(None, 2) == repr(2))
+assert(rf.i2repr(None, [0, 1, 2]) == [repr(0), repr(1), repr(2)])
+
+assert(lf.i2repr(None, 0) == repr(0))
+assert(lf.i2repr(None, 1) == repr(1))
+assert(lf.i2repr(None, 2) == repr(2))
+assert(lf.i2repr(None, [0, 1, 2]) == [repr(0), repr(1), repr(2)])
+
+assert(fcb.i2repr(None, 0) == repr(0))
+assert(fcb.i2repr(None, 1) == repr(1))
+assert(fcb.i2repr(None, 5) == repr(5))
+assert(fcb.i2repr(None, 11) == repr(11))
+assert(fcb.i2repr(None, [0, 1, 5, 11]) == [repr(0), repr(1), repr(5), repr(11)])
+
+conf.noenum.remove(f, rf, lf, fcb)
+
+assert(f.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
+assert(rf.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
+assert(lf.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
+assert(fcb.i2repr_one(None, RandNum(0, 10)) == '<RandNum>')
+
+True
+
+############
+############
++ CharEnumField tests
+
+= Building expect_exception handler
+~ field charenumfield
+
+def expect_exception(e, c):
+    try:
+        eval(c)
+        return False
+    except e:
+        return True
+
+
+= CharEnumField tests initialization
+~ field charenumfield
+
+fc = CharEnumField('test', 'f', {'f': 'Foo', 'b': 'Bar'})
+fcb = CharEnumField('test', 'a', (
+    lambda x: 'Foo' if x == 'a' else 'Bar' if x == 'b' else 'Baz',
+    lambda x: 'a' if x == 'Foo' else 'b' if x == 'Bar' else ''
+))
+
+True
+
+= CharEnumField.any2i_one
+~ field charenumfield
+
+assert(fc.any2i_one(None, 'Foo') == 'f')
+assert(fc.any2i_one(None, 'Bar') == 'b')
+expect_exception(KeyError, 'fc.any2i_one(None, "Baz")')
+
+assert(fcb.any2i_one(None, 'Foo') == 'a')
+assert(fcb.any2i_one(None, 'Bar') == 'b')
+assert(fcb.any2i_one(None, 'Baz') == '')
+
+True
+
+############
+############
++ XShortEnumField tests
+
+= Building expect_exception handler
+~ field xshortenumfield
+
+def expect_exception(e, c):
+    try:
+        eval(c)
+        return False
+    except e:
+        return True
+
+
+= XShortEnumField tests initialization
+~ field xshortenumfield
+
+f = XShortEnumField('test', 0, {0: 'Foo', 1: 'Bar'})
+fcb = XShortEnumField('test', 0, (
+    lambda x: 'Foo' if x == 0 else 'Bar' if x == 1 else lhex(x),
+    lambda x: x
+))
+
+True
+
+= XShortEnumField.i2repr_one
+~ field xshortenumfield
+
+assert(f.i2repr_one(None, 0) == 'Foo')
+assert(f.i2repr_one(None, 1) == 'Bar')
+assert(f.i2repr_one(None, 0xff) == '0xff')
+
+assert(f.i2repr_one(None, 0) == 'Foo')
+assert(f.i2repr_one(None, 1) == 'Bar')
+assert(f.i2repr_one(None, 0xff) == '0xff')
 
+True