diff --git a/asn1-codec.cabal b/asn1-codec.cabal
--- a/asn1-codec.cabal
+++ b/asn1-codec.cabal
@@ -1,5 +1,5 @@
 name:                asn1-codec
-version:             0.1.0
+version:             0.2.0
 synopsis:            Encode and decode ASN.1
 description:         Add a better description later
 homepage:            https://github.com/andrewthad/asn1-codec
@@ -26,7 +26,7 @@
     Net.Snmp.Decoding
     Net.Snmp.Client
   build-depends:
-      base >= 4.7 && < 5
+      base >= 4.9 && < 5
     , integer-gmp
     , bytestring
     , contravariant
diff --git a/src/Language/Asn/Types/Internal.hs b/src/Language/Asn/Types/Internal.hs
--- a/src/Language/Asn/Types/Internal.hs
+++ b/src/Language/Asn/Types/Internal.hs
@@ -19,6 +19,7 @@
 import Data.ByteString.Builder (Builder)
 import Data.Text (Text)
 import Data.Monoid
+import Data.Semigroup (Semigroup)
 import Data.Word
 import Data.Int
 import Data.Bits
@@ -69,7 +70,7 @@
     UniversalValueNull -> UniversalValueNull
 
 newtype Subtypes a = Subtypes { getSubtypes :: [Subtype a] }
-  deriving (Monoid)
+  deriving (Semigroup,Monoid)
 
 newtype ObjectIdentifier = ObjectIdentifier { getObjectIdentifier :: Vector Integer }
   deriving (Eq,Ord,Show,Read,Generic)
diff --git a/src/Net/Snmp/Decoding.hs b/src/Net/Snmp/Decoding.hs
--- a/src/Net/Snmp/Decoding.hs
+++ b/src/Net/Snmp/Decoding.hs
@@ -27,6 +27,30 @@
 import qualified Data.ByteString.Lazy as LB
 import qualified Language.Asn.Decoding as AsnDecoding
 
+trapPdu :: AsnDecoding TrapPdu
+trapPdu = sequence $ TrapPdu
+  <$> required "enterprise" objectIdentifier
+  <*> required "agent-addr"
+      ( choice
+        [ option "internet" $ tag Application 0 Implicit octetStringWord32
+        ]
+      )
+  <*> required "generic-trap" genericTrap
+  <*> required "specific-trap" integer
+  <*> required "time-stamp" integer
+  <*> required "variable-bindings" (sequenceOf varBind)
+
+genericTrap :: AsnDecoding GenericTrap
+genericTrap = flip mapFailable integer $ \i -> case i of
+  0 -> Right GenericTrapColdStart
+  1 -> Right GenericTrapWarmStart
+  2 -> Right GenericTrapLinkDown
+  3 -> Right GenericTrapLinkUp
+  4 -> Right GenericTrapAuthenticationFailure
+  5 -> Right GenericTrapEgpNeighborLoss
+  6 -> Right GenericTrapEnterpriseSpecific
+  _ -> Left "unrecognized generic-trap number"
+
 messageV2 :: AsnDecoding MessageV2
 messageV2 = sequence $ MessageV2
   <$  required "version" integer -- make this actually demand that it's 1
diff --git a/src/Net/Snmp/Types.hs b/src/Net/Snmp/Types.hs
--- a/src/Net/Snmp/Types.hs
+++ b/src/Net/Snmp/Types.hs
@@ -165,5 +165,21 @@
   , bulkPduVariableBindings :: !(Vector VarBind)
   } deriving (Eq,Show)
 
+data TrapPdu = TrapPdu
+  { trapPduEnterprise :: !ObjectIdentifier
+  , trapPduAgentAddress :: !Word32
+  , trapPduGenericTrap :: !GenericTrap
+  , trapPduSpecificTrap :: !Integer
+  , trapPduTimeStamp :: !Integer
+  , trapPduVariableBindings :: [VarBind]
+  }
 
+data GenericTrap
+  = GenericTrapColdStart
+  | GenericTrapWarmStart
+  | GenericTrapLinkDown
+  | GenericTrapLinkUp
+  | GenericTrapAuthenticationFailure
+  | GenericTrapEgpNeighborLoss
+  | GenericTrapEnterpriseSpecific
 
