diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Erick Gonzalez (c) 2017
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# Remote Authentication Dial In User Service (RADIUS)
+
+This module compiles RADIUS packet definitions and different attributes as specified in RFC 2865, as well as de/coding functions to serialize and deserialize RADIUS packets to/from binary data. 
+
+RADIUS extensions in RFC 2869 are also supported, as well as RFC 3162 for IPv6 related attributes
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/radius.cabal b/radius.cabal
new file mode 100644
--- /dev/null
+++ b/radius.cabal
@@ -0,0 +1,30 @@
+name:                radius
+version:             0.1.0.0
+synopsis:            Remote Authentication Dial In User Service (RADIUS)
+description:         This module provides types and on the wire de/coding of RADIUS packets as per RFC2865
+homepage:            https://github.com/erickg/radius#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Erick Gonzalez
+maintainer:          erick@codemonkeylabs.de
+copyright:           2017 Erick Gonzalez
+category:            Network
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Network.RADIUS.Encoding
+                     , Network.RADIUS.Types
+  build-depends:       base >= 4.7 && < 5
+                     , binary
+                     , bytestring
+                     , iproute
+                     , pretty-hex
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+
+source-repository head
+  type:     git
+  location: https://github.com/erickg/radius
diff --git a/src/Network/RADIUS/Encoding.hs b/src/Network/RADIUS/Encoding.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/RADIUS/Encoding.hs
@@ -0,0 +1,339 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-|
+Module      : Network.RADIUS.Encoding
+Description : Provides on the wire de/coding of RADIUS packets as per RFC 3748
+Copyright   : (c) Erick Gonzalez, 2017
+License     : BSD3
+Maintainer  : erick@codemonkeylabs.de
+Stability   : experimental
+Portability : POSIX
+
+This module provides Binary instances for the RADIUS Packet type and attributes. So you basically decode a (lazy) ByteString and get a RADIUS Packet back or you can encode a RADIUS Packet to a ByteString, which you can then send on the wire as is, etc. Simple as that.
+
+-}
+
+module Network.RADIUS.Encoding where
+
+import Control.Monad               (when)
+import Data.Binary                 (Binary(..), encode)
+import Data.Binary.Put             (Put, putLazyByteString, putWord8, putWord16be, putWord32be)
+import Data.Binary.Get             (Get, getLazyByteString, getWord8, getWord16be, isEmpty)
+import Data.ByteString.Lazy.Char8  (ByteString)
+import Data.IP                     (IPv4, IPv6)
+import Data.Int                    (Int64)
+import Data.Word                   (Word8, Word16, Word32)
+import Network.RADIUS.Types
+import Debug.Trace
+
+import qualified Data.ByteString.Lazy.Char8 as B
+
+-- | Self explanatory. It can be useful when reading a RADIUS packet from a socket for example,
+-- so one can retrieve the packet header (containing the packet length) first and then use that
+-- to figure out how much data is left to read
+radiusHeaderSize :: Word16
+radiusHeaderSize = 20
+
+-- | Fixed authenticator length as per RFC 2865
+authenticatorLength :: Int64
+authenticatorLength = 16
+
+instance Binary Packet where
+    put Packet{ getHeader = Header{..} , .. } = do
+      let iD         = fromIntegral $ getPacketId
+          authLen    = B.length getPacketAuthenticator
+          attributes = encodeAttributes getPacketAttributes
+          attrsLen   = fromIntegral . B.length $ attributes
+      when (authLen /= authenticatorLength) $
+           fail $ "RADIUS.Encoding: Invalid Authenticator length " ++ show authLen
+      put getPacketType
+      putWord8 iD
+      putWord16be $ attrsLen + radiusHeaderSize
+      putLazyByteString getPacketAuthenticator
+      putLazyByteString attributes
+    get = do
+      header <- decodeHeader
+      decodePacket header
+
+-- | Allows decoding of a RADIUS header in the Get Monad
+decodeHeader :: Get Header
+decodeHeader = do
+  packetType    <- get
+  iD            <- getWord8
+  packetLength  <- getWord16be
+  authenticator <- getLazyByteString authenticatorLength
+  return Header { getPacketType          = packetType,
+                  getPacketId            = iD,
+                  getPacketLength        = packetLength,
+                  getPacketAuthenticator = authenticator }
+
+-- | Given an already decoded header, this function can be used to decode the complete packet
+-- from the available data
+decodePacket :: Header -> Get Packet
+decodePacket header@Header{..} = do
+  attributes <- decodeAttributes []
+  return Packet { getHeader           = header,
+                  getPacketAttributes = attributes }
+
+instance Binary PacketType where
+    put = putEnum
+    get = getEnum
+
+-- | Used internally to encode a list of RADIUS attributes. You probably don't need this.
+encodeAttributes :: [PacketAttribute] -> ByteString
+encodeAttributes = B.concat . fmap encode
+
+-- | Used internally to decode a list of RADIUS attributes. You probably don't need this.
+decodeAttributes :: [PacketAttribute] -> Get [PacketAttribute]
+decodeAttributes acc = do
+  done <- isEmpty
+  if done
+    then return . reverse $ acc
+    else do
+      attribute <- get
+      decodeAttributes $ attribute : acc
+
+instance Binary IPv4
+instance Binary IPv6
+
+instance Binary PacketAttribute where
+    put (UserNameAttribute str)                 = putAttributeStr   1 str
+    put (UserPasswordAttribute str)             = putAttributeStr   2 str
+    put (FramedIPv6Route str)                   = putAttributeStr  99 str
+    put (FramedIPv6Pool str)                    = putAttributeStr 100 str
+    put (FilterIdAttribute str)                 = putAttributeStr  11 str
+    put (ReplyMessageAttribute str)             = putAttributeStr  18 str
+    put (CallbackNumberAttribute str)           = putAttributeStr  19 str
+    put (CallbackIdAttribute str)               = putAttributeStr  20 str
+    put (FramedRouteAttribute str)              = putAttributeStr  22 str
+    put (StateAttribute str)                    = putAttributeStr  24 str
+    put (ClassAttribute str)                    = putAttributeStr  25 str
+    put (CalledStationIdAttribute str)          = putAttributeStr  30 str
+    put (CallingStationIdAttribute str)         = putAttributeStr  31 str
+    put (NASIdentifierAttribute str)            = putAttributeStr  32 str
+    put (ProxyStateAttribute str)               = putAttributeStr  33 str
+    put (LoginLATServiceAttribute str)          = putAttributeStr  34 str
+    put (LoginLATNodeAttribute str)             = putAttributeStr  35 str
+    put (LoginLATGroupAttribute str)            = putAttributeStr  36 str
+    put (FramedAppleTalkZoneAttribute str)      = putAttributeStr  39 str
+    put (CHAPChallengeAttribute str)            = putAttributeStr  60 str
+    put (LoginLATPortAttribute str)             = putAttributeStr  63 str
+    put (ARAPPasswordAttribute str)             = putAttributeStr  70 str
+    put (ARAPFeaturesAttribute str)             = putAttributeStr  71 str
+    put (ARAPSecurityDataAttribute str)         = putAttributeStr  74 str
+    put (ConnectInfoAttribute str)              = putAttributeStr  77 str
+    put (ConfigurationTokenAttribute str)       = putAttributeStr  78 str
+    put (EAPMessageAttribute str)               = putAttributeStr  79 str
+    put (MessageAuthenticatorAttribute str)     = putAttributeStr  80 str
+    put (ARAPChallengeResponseAttribute str)    = putAttributeStr  84 str
+    put (NASPortIdAttribute str)                = putAttributeStr  87 str
+    put (FramedPoolAttribute str)               = putAttributeStr  88 str
+    put (NASPortAttribute value)                = putAttribute      5 value
+    put (FramedMTUAttribute value)              = putAttribute     12 value
+    put (LoginTCPPortAttribute value)           = putAttribute     16 value
+    put (FramedIPXNetworkAttribute value)       = putAttribute     23 value
+    put (SessionTimeoutAttribute value)         = putAttribute     27 value
+    put (IdleTimeoutAttribute value)            = putAttribute     28 value
+    put (FramedAppleTalkLinkAttribute value)    = putAttribute     37 value
+    put (FramedAppleTalkNetworkAttribute value) = putAttribute     38 value
+    put (PortLimitAttribute value)              = putAttribute     62 value
+    put (NASIPAddress value)                    = putAttribute      4 value
+    put (NASIPv6Address value)                  = putAttribute     95 value
+    put (ServiceTypeAttribute value)            = putAttribute      6 value
+    put (FramedProtocolAttribute value)         = putAttribute      7 value
+    put (FramedIPAddressAttribute value)        = putAttribute      8 value
+    put (FramedIPNetmaskAttribute value)        = putAttribute      9 value
+    put (FramedRoutingAttribute value)          = putAttribute     10 value
+    put (FramedCompressionAttribute value)      = putAttribute     13 value
+    put (FramedInterfaceIdAttribute value)      = putAttribute     96 value
+    put (LoginIPHostAttribute value)            = putAttribute     14 value
+    put (LoginIPv6HostAttribute value)          = putAttribute     98 value
+    put (LoginServiceAttribute value)           = putAttribute     15 value
+    put (TerminationActionAttribute value)      = putAttribute     29 value
+    put (NASPortTypeAttribute value)            = putAttribute     61 value
+    put (AccountInputGigawordsAttribute value)  = putAttribute     52 value
+    put (AccountOutputGigawordsAttribute value) = putAttribute     53 value
+    put (EventTimeStampAttribute value)         = putAttribute     55 value
+    put (ARAPZoneAccessAttribute value)         = putAttribute     72 value
+    put (ARAPSecurityAttribute value)           = putAttribute     73 value
+    put (PasswordRetryAttribute value)          = putAttribute     75 value
+    put (PromptAttribute value)                 = putAttribute     76 value
+    put (AcctInterimIntervalAttribute value)    = putAttribute     85 value
+    put (FramedIPv6Prefix prefixLength prefix) = do
+      let attr    = encode prefix
+          attrLen = 4 + (fromIntegral . B.length $ attr)
+      putWord8 97 -- Attribute type
+      putWord8 attrLen
+      putWord8 0  -- reserved
+      putWord8 $ fromIntegral prefixLength
+      putLazyByteString attr
+    put (VendorSpecificAttribute iD str) = do
+      let attrLen = (fromIntegral . B.length $ str) + 6 -- Attribute header length + string
+      putWord8 26 -- Attribute Type
+      putWord8 attrLen
+      put iD
+      putLazyByteString str
+    put (CHAPPassword identity str)           = do
+      let attrLen = (fromIntegral . B.length $ str) + 3 -- Attribute header plus string
+      when (attrLen /= 19) $ fail $ "Invalid RADIUS CHAP Password length " ++ show attrLen
+      putWord8 3 -- Attribute Type
+      putWord8 attrLen
+      putWord8 identity
+      putLazyByteString str
+
+    get = do
+      code <- getWord8
+      traceM $ "decode attr " ++ show code
+      getAttribute code
+
+-- | For internal use
+putAttributeStr :: Word8 -> ByteString -> Put
+putAttributeStr code str = do
+    putWord8 code
+    putWord8 $ (fromIntegral . B.length $ str) + 2 -- attr length + code + len octets
+    putLazyByteString str
+
+-- | For internal use
+putAttribute :: (Binary a) => Word8 -> a -> Put
+putAttribute code attribute = do
+    let attrData = encode attribute
+        attrLen  = (fromIntegral . B.length $ attrData) + 2 -- attr length + code + len octets
+    putWord8 code
+    putWord8 attrLen
+    putLazyByteString attrData
+
+getAttribute :: Word8 -> Get PacketAttribute
+getAttribute   1 = getAttributeStr >>= return . UserNameAttribute
+getAttribute   2 = getAttributeStr >>= return . UserPasswordAttribute
+getAttribute  99 = getAttributeStr >>= return . FramedIPv6Route
+getAttribute 100 = getAttributeStr >>= return . FramedIPv6Pool
+getAttribute  11 = getAttributeStr >>= return . FilterIdAttribute
+getAttribute  18 = getAttributeStr >>= return . ReplyMessageAttribute
+getAttribute  19 = getAttributeStr >>= return . CallbackNumberAttribute
+getAttribute  20 = getAttributeStr >>= return . CallbackIdAttribute
+getAttribute  22 = getAttributeStr >>= return . FramedRouteAttribute
+getAttribute  24 = getAttributeStr >>= return . StateAttribute
+getAttribute  25 = getAttributeStr >>= return . ClassAttribute
+getAttribute  30 = getAttributeStr >>= return . CalledStationIdAttribute
+getAttribute  31 = getAttributeStr >>= return . CallingStationIdAttribute
+getAttribute  32 = getAttributeStr >>= return . NASIdentifierAttribute
+getAttribute  33 = getAttributeStr >>= return . ProxyStateAttribute
+getAttribute  34 = getAttributeStr >>= return . LoginLATServiceAttribute
+getAttribute  35 = getAttributeStr >>= return . LoginLATNodeAttribute
+getAttribute  36 = getAttributeStr >>= return . LoginLATGroupAttribute
+getAttribute  39 = getAttributeStr >>= return . FramedAppleTalkZoneAttribute
+getAttribute  60 = getAttributeStr >>= return . CHAPChallengeAttribute
+getAttribute  63 = getAttributeStr >>= return . LoginLATPortAttribute
+getAttribute  70 = getAttributeStr >>= return . ARAPPasswordAttribute
+getAttribute  71 = getAttributeStr >>= return . ARAPFeaturesAttribute
+getAttribute  74 = getAttributeStr >>= return . ARAPSecurityDataAttribute
+getAttribute  77 = getAttributeStr >>= return . ConnectInfoAttribute
+getAttribute  78 = getAttributeStr >>= return . ConfigurationTokenAttribute
+getAttribute  79 = getAttributeStr >>= return . EAPMessageAttribute
+getAttribute  80 = getAttributeStr >>= return . MessageAuthenticatorAttribute
+getAttribute  84 = getAttributeStr >>= return . ARAPChallengeResponseAttribute
+getAttribute  87 = getAttributeStr >>= return . NASPortIdAttribute
+getAttribute  88 = getAttributeStr >>= return . FramedPoolAttribute
+getAttribute 5  = getAttributeValue >>= return . NASPortAttribute
+getAttribute 12 = getAttributeValue >>= return . FramedMTUAttribute
+getAttribute 16 = getAttributeValue >>= return . LoginTCPPortAttribute
+getAttribute 23 = getAttributeValue >>= return . FramedIPXNetworkAttribute
+getAttribute 27 = getAttributeValue >>= return . SessionTimeoutAttribute
+getAttribute 28 = getAttributeValue >>= return . IdleTimeoutAttribute
+getAttribute 37 = getAttributeValue >>= return . FramedAppleTalkLinkAttribute
+getAttribute 38 = getAttributeValue >>= return . FramedAppleTalkNetworkAttribute
+getAttribute 62 = getAttributeValue >>= return . PortLimitAttribute
+getAttribute 4  = getAttributeValue >>= return . NASIPAddress
+getAttribute 95 = getAttributeValue >>= return . NASIPv6Address
+getAttribute 6  = getAttributeValue >>= return . ServiceTypeAttribute . fromEnum32
+getAttribute 7  = getAttributeValue >>= return . FramedProtocolAttribute . fromEnum32
+getAttribute 8  = getAttributeValue >>= return . FramedIPAddressAttribute
+getAttribute 9  = getAttributeValue >>= return . FramedIPNetmaskAttribute
+getAttribute 10 = getAttributeValue >>= return . FramedRoutingAttribute . fromEnum32
+getAttribute 13 = getAttributeValue >>= return . FramedCompressionAttribute . fromEnum32
+getAttribute 96 = getAttributeValue >>= return . FramedInterfaceIdAttribute
+getAttribute 14 = getAttributeValue >>= return . LoginIPHostAttribute
+getAttribute 98 = getAttributeValue >>= return . LoginIPv6HostAttribute
+getAttribute 15 = getAttributeValue >>= return . LoginServiceAttribute . fromEnum32
+getAttribute 29 = getAttributeValue >>= return . TerminationActionAttribute . fromEnum32
+getAttribute 61 = getAttributeValue >>= return . NASPortTypeAttribute . fromEnum32
+getAttribute 52 = getAttributeValue >>= return . AccountInputGigawordsAttribute
+getAttribute 53 = getAttributeValue >>= return . AccountOutputGigawordsAttribute
+getAttribute 55 = getAttributeValue >>= return . EventTimeStampAttribute
+getAttribute 72 = getAttributeValue >>= return . ARAPZoneAccessAttribute . fromEnum32
+getAttribute 73 = getAttributeValue >>= return . ARAPSecurityAttribute
+getAttribute 75 = getAttributeValue >>= return . PasswordRetryAttribute
+getAttribute 76 = getAttributeValue >>= return . PromptAttribute
+getAttribute 85 = getAttributeValue >>= return . AcctInterimIntervalAttribute
+getAttribute 97 = do
+  attrLen      <- getWord8
+  _reserved    <- getWord8
+  prefixLength <- getWord8
+  when (attrLen /= 20) $ fail $ "Unsupported RADIUS Framed IPv6 Prefix attribute length "
+           ++ show attrLen
+  prefix <- get
+  return $ FramedIPv6Prefix (fromIntegral prefixLength) prefix
+getAttribute 26 = do
+  attrLen  <- getWord8
+  iD       <- get
+  attrData <- getLazyByteString . fromIntegral $ attrLen - 6
+  return $ VendorSpecificAttribute iD attrData
+getAttribute 3 = do
+  attrLen  <- getWord8
+  when (attrLen /= 19) $ fail $ "Invalid RADIUS CHAP Password length " ++ show attrLen
+  identity <- getWord8
+  attrData <- getLazyByteString 16 -- CHAP response is always 16 octets
+  return $ CHAPPassword identity attrData
+getAttribute n  = fail $ "Unknown RADIUS attribute type " ++ show n
+
+-- | For internal use.
+getAttributeStr :: Get ByteString
+getAttributeStr = getWord8 >>= getLazyByteString . fromIntegral . (subtract 2) -- minus type + len
+
+-- | For internal use.
+getAttributeValue :: (Binary a) => Get a
+getAttributeValue = getWord8 >> get
+
+instance Binary ServiceType where
+    put = putEnum
+    get = getEnum
+
+instance Binary FramedProtocol where
+    put = putEnum
+    get = getEnum
+
+instance Binary FramedRouting where
+    put = putEnum
+    get = getEnum
+
+instance Binary FramedCompression where
+    put = putEnum
+    get = getEnum
+
+instance Binary LoginService where
+    put = putEnum
+    get = getEnum
+
+instance Binary TerminationAction where
+    put = putEnum
+    get = getEnum
+
+instance Binary NASPortType where
+    put = putEnum
+    get = getEnum
+
+instance Binary ARAPZoneAccess where
+    put = putEnum
+    get = getEnum
+
+-- | For internal use.
+putEnum :: (Enum a) => a -> Put
+putEnum = putWord32be . fromIntegral . fromEnum
+
+-- | For internal use.
+getEnum :: (Enum a) => Get a
+getEnum = getWord8 >>= return . toEnum . fromIntegral
+
+-- | For internal use.
+fromEnum32 :: (Enum a) => Word32 -> a
+fromEnum32 = toEnum . fromIntegral
diff --git a/src/Network/RADIUS/Types.hs b/src/Network/RADIUS/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/RADIUS/Types.hs
@@ -0,0 +1,258 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-|
+Module      : Network.RADIUS.Types
+Description : Provides types and definitions for RADIUS as per RFC 2865
+Copyright   : (c) Erick Gonzalez, 2017
+License     : BSD3
+Maintainer  : erick@codemonkeylabs.de
+Stability   : experimental
+Portability : POSIX
+
+This module compiles the RADIUS packet definitions and different attributes as specified in
+RFC 2865. The naming conventions from the RFC have been preserved as much as possible, so
+it should be straightforward to look up a particular element and understand what it means etc.
+
+RADIUS extensions in RFC 2869 are also supported, as well as RFC 3162 for IPv6 related attributes
+
+-}
+module Network.RADIUS.Types where
+
+import Data.ByteString.Lazy.Char8    (ByteString)
+import Data.Data                     (Data)
+import Data.Word                     (Word8, Word16, Word32, Word64)
+import Data.IP                       (IPv4, IPv6)
+import Data.Int                      (Int8)
+
+data Header = Header { getPacketType          :: PacketType,
+                       getPacketId            :: Word8,
+                       getPacketLength        :: Word16,
+                       getPacketAuthenticator :: ByteString }
+              deriving (Show, Eq)
+
+data Packet = Packet { getHeader           :: Header,
+                       getPacketAttributes :: [PacketAttribute] }
+              deriving (Show, Eq)
+
+data PacketType = AccessRequest
+                | AccessAccept
+                | AccessReject
+                | AccountingRequest
+                | AccountingResponse
+                | AccessChallenge
+                | StatusServer
+                | StatusClient
+                  deriving (Show, Eq)
+
+
+instance Enum PacketType where
+    fromEnum AccessRequest      = 1
+    fromEnum AccessAccept       = 2
+    fromEnum AccessReject       = 3
+    fromEnum AccountingRequest  = 4
+    fromEnum AccountingResponse = 5
+    fromEnum AccessChallenge    = 11
+    fromEnum StatusServer       = 12
+    fromEnum StatusClient       = 13
+    toEnum 1  = AccessRequest
+    toEnum 2  = AccessAccept
+    toEnum 3  = AccessReject
+    toEnum 4  = AccountingRequest
+    toEnum 5  = AccountingResponse
+    toEnum 11 = AccessChallenge
+    toEnum 12 = StatusServer
+    toEnum 13 = StatusClient
+    toEnum x  = error $ "Invalid RADIUS packet type " ++ show x
+
+data PacketAttribute =
+    UserNameAttribute               { getUserNameAttribute               :: ByteString        }
+  | UserPasswordAttribute           { getUserPasswordAttribute           :: ByteString        }
+  | CHAPPassword                    { getCHAPIdentity                    :: Word8,
+                                      getCHAPPasswordAttribute           :: ByteString        }
+  | NASIPAddress                    { getNASIPAddress                    :: IPv4              }
+  | NASIPv6Address                  { getNASIPv6Address                  :: IPv6              }
+  | NASPortAttribute                { getNASPortAttribute                :: Word32            }
+  | ServiceTypeAttribute            { getServiceTypeAttribute            :: ServiceType       }
+  | FramedProtocolAttribute         { getFramedProtocolAttribute         :: FramedProtocol    }
+  | FramedIPAddressAttribute        { getFramedIPAddressAttribute        :: IPv4              }
+  | FramedIPNetmaskAttribute        { getFramedIPNetmaskAttribute        :: IPv4              }
+  | FramedRoutingAttribute          { getFramedRoutingAttribute          :: FramedRouting     }
+  | FramedInterfaceIdAttribute      { getFramedInterfaceIdAttribute      :: Word64            }
+  | FramedIPv6Prefix                { getFramedIPv6PrefixLength          :: Int8,
+                                      getFramedIPv6Prefix                :: IPv6              }
+  | FramedIPv6Route                 { getFramedIPv6RouteAttribute        :: ByteString        }
+  | FramedIPv6Pool                  { getFramedIPv6PoolAttribute         :: ByteString        }
+  | FilterIdAttribute               { getFilterIdAttribute               :: ByteString        }
+  | FramedMTUAttribute              { getFramedMTUAttribute              :: Word32            }
+  | FramedCompressionAttribute      { getFramedCompressionAttribute      :: FramedCompression }
+  | LoginIPHostAttribute            { getLoginIPHostAttribute            :: IPv4              }
+  | LoginIPv6HostAttribute          { getLoginIPv6HostAttribute          :: IPv6              }
+  | LoginServiceAttribute           { getLoginServiceAttribute           :: LoginService      }
+  | LoginTCPPortAttribute           { getLoginTCPPortAttribute           :: Word32            }
+  | ReplyMessageAttribute           { getReplyMessageAttribute           :: ByteString        }
+  | CallbackNumberAttribute         { getCallbackNumberAttribute         :: ByteString        }
+  | CallbackIdAttribute             { getCallbackIdAttribute             :: ByteString        }
+  | FramedRouteAttribute            { getFramedRouteAttribute            :: ByteString        }
+  | FramedIPXNetworkAttribute       { getFramedIPXNetworkAttribute       :: Word32            }
+  | StateAttribute                  { getStateAttribute                  :: ByteString        }
+  | ClassAttribute                  { getClassAttribute                  :: ByteString        }
+  | VendorSpecificAttribute         { getVendorSpecificAttributeId       :: Word32,
+                                      getVendorSpecificAttribute         :: ByteString        }
+  | SessionTimeoutAttribute         { getSessionTimeoutAttribute         :: Word32            }
+  | IdleTimeoutAttribute            { getIdleTimeoutAttribute            :: Word32            }
+  | TerminationActionAttribute      { getTerminationActionAttribute      :: TerminationAction }
+  | CalledStationIdAttribute        { getCalledStationIdAttribute        :: ByteString        }
+  | CallingStationIdAttribute       { getCallingStationIdAttribute       :: ByteString        }
+  | NASIdentifierAttribute          { getNASIdentifierAttribute          :: ByteString        }
+  | ProxyStateAttribute             { getProxyStateAttribute             :: ByteString        }
+  | LoginLATServiceAttribute        { getLoginLATServiceAttribute        :: ByteString        }
+  | LoginLATNodeAttribute           { getLoginLATNodeAttribute           :: ByteString        }
+  | LoginLATGroupAttribute          { getLoginLATGroupAttribute          :: ByteString        }
+  | FramedAppleTalkLinkAttribute    { getFramedAppleTalkLinkAttribute    :: Word32            }
+  | FramedAppleTalkNetworkAttribute { getFramedAppleTalkNetworkAttribute :: Word32            }
+  | FramedAppleTalkZoneAttribute    { getFramedAppleTalkZoneAttribute    :: ByteString        }
+  | CHAPChallengeAttribute          { getCHAPChallengeAttribute          :: ByteString        }
+  | NASPortTypeAttribute            { getNASPortTypeAttribute            :: NASPortType       }
+  | PortLimitAttribute              { getPortLimitAttribute              :: Word32            }
+  | LoginLATPortAttribute           { getLoginLATPortAttribute           :: ByteString        }
+  | AccountInputGigawordsAttribute  { getAccountInputGigawordsAttribute  :: Word32            }
+  | AccountOutputGigawordsAttribute { getAccountOutputGigawordsAttribute :: Word32            }
+  | EventTimeStampAttribute         { getEventTimeStampAttribute         :: Word32            }
+  | ARAPPasswordAttribute           { getARAPPasswordAttribute           :: ByteString        }
+  | ARAPFeaturesAttribute           { getARAPFeaturesAttribute           :: ByteString        }
+  | ARAPZoneAccessAttribute         { getARAPZoneAccessAttribute         :: ARAPZoneAccess    }
+  | ARAPSecurityAttribute           { getARAPSecurityAttribute           :: Word32            }
+  | ARAPSecurityDataAttribute       { getARAPSecurityDataAttribute       :: ByteString        }
+  | PasswordRetryAttribute          { getPasswordRetryAttribute          :: Word32            }
+  | PromptAttribute                 { getPromptAttribute                 :: Word32            }
+  | ConnectInfoAttribute            { getConnectInfoAttribute            :: ByteString        }
+  | ConfigurationTokenAttribute     { getConfigurationTokenAttribute     :: ByteString        }
+  | EAPMessageAttribute             { getEAPMessageAttribute             :: ByteString        }
+  | MessageAuthenticatorAttribute   { getMessageAuthenticatorAttribute   :: ByteString        }
+  | ARAPChallengeResponseAttribute  { getARAPChallengeResponseAttribute  :: ByteString        }
+  | AcctInterimIntervalAttribute    { getAcctInterimIntervalAttribute    :: Word32            }
+  | NASPortIdAttribute              { getNASPortIdAttribute              :: ByteString        }
+  | FramedPoolAttribute             { getFramedPoolAttribute             :: ByteString        }
+  deriving (Show, Eq, Data)
+
+
+data ServiceType = LoginService
+                 | FramedService
+                 | CallbackLoginService
+                 | CallbackFramedService
+                 | OutboundService
+                 | AdministrativeService
+                 | NASPromptService
+                 | AuthenticateOnlyService
+                 | CallbackNASPrompt
+                 | CallCheckService
+                 | CallbackAdministrativeService
+                   deriving (Show, Eq, Data)
+
+instance Enum ServiceType where
+    fromEnum LoginService                  = 1
+    fromEnum FramedService                 = 2
+    fromEnum CallbackLoginService          = 3
+    fromEnum CallbackFramedService         = 4
+    fromEnum OutboundService               = 5
+    fromEnum AdministrativeService         = 6
+    fromEnum NASPromptService              = 7
+    fromEnum AuthenticateOnlyService       = 8
+    fromEnum CallbackNASPrompt             = 9
+    fromEnum CallCheckService              = 10
+    fromEnum CallbackAdministrativeService = 11
+    toEnum 1  = LoginService
+    toEnum 2  = FramedService
+    toEnum 3  = CallbackLoginService
+    toEnum 4  = CallbackFramedService
+    toEnum 5  = OutboundService
+    toEnum 6  = AdministrativeService
+    toEnum 7  = NASPromptService
+    toEnum 8  = AuthenticateOnlyService
+    toEnum 9  = CallbackNASPrompt
+    toEnum 10 = CallCheckService
+    toEnum 11 = CallbackAdministrativeService
+    toEnum x  = error $ "Invalid RADIUS service type " ++ show x
+
+data FramedProtocol = PPPFramedProtocol
+                    | SLIPFramedProtocol
+                    | ARAPFramedProtocol
+                    | GandalfFramedProtocol
+                    | XylogicsFramedProtocol
+                    | X75FramedProtocol
+                      deriving (Show, Eq, Data)
+
+instance Enum FramedProtocol where
+    fromEnum PPPFramedProtocol      = 1
+    fromEnum SLIPFramedProtocol     = 2
+    fromEnum ARAPFramedProtocol     = 3
+    fromEnum GandalfFramedProtocol  = 4
+    fromEnum XylogicsFramedProtocol = 5
+    fromEnum X75FramedProtocol      = 6
+    toEnum 1 = PPPFramedProtocol
+    toEnum 2 = SLIPFramedProtocol
+    toEnum 3 = ARAPFramedProtocol
+    toEnum 4 = GandalfFramedProtocol
+    toEnum 5 = XylogicsFramedProtocol
+    toEnum 6 = X75FramedProtocol
+    toEnum x = error $ "Invalid framed protocol " ++ show x
+
+data FramedRouting = NoneFramedRouting
+                   | SendFramedRouting
+                   | ListenFramedRouting
+                   | SendAndListenFramedRouting
+                     deriving (Show, Eq, Enum, Data)
+
+data FramedCompression = NoCompression
+                       | VJTCPIPHeaderCompression
+                       | IPXHeaderCompression
+                       | StacLZSCompression
+                         deriving (Show, Eq, Enum, Data)
+
+data LoginService = TelnetService
+                  | RloginService
+                  | TCPClearService
+                  | PortMasterService
+                  | LATService
+                  | X25PADService
+                  | X25T3POSService
+                  | UnusedService
+                  | TCPClearQuietService
+                    deriving (Show, Eq, Enum, Data)
+
+data TerminationAction = DefaultTerminationAction | RADIUSRequestTerminationAction
+                       deriving (Show, Eq, Enum, Data)
+
+data NASPortType = AsyncNASPort
+                 | SyncNASPort
+                 | ISDNSyncPort
+                 | ISDNAsyncV120Port
+                 | VirtualNASPort
+                 | PIAFSNASPort
+                 | HDLCClearChannelNASPort
+                 | X25NASPort
+                 | X75NASPort
+                 | G3FaxNASPort
+                 | SDSLNASPort
+                 | ADSLCAPNASPort
+                 | ADSLDMTNASPort
+                 | IDSLNASPort
+                 | EthernetNASPort
+                 | XDSLNASPort
+                 | CableNASPort
+                 | WirelessOtherNASPort
+                 | WirelessIEEE80211NASPort
+                   deriving (Show, Eq, Enum, Data)
+
+data ARAPZoneAccess = DefaultZoneOnlyARAPAccess
+                    | UseZoneFilterInclusivelyARAPAccess
+                    | UseZoneFilterExclusivelyARAPAccess
+                    deriving (Show, Eq, Data)
+
+instance Enum ARAPZoneAccess where
+    toEnum 1 = DefaultZoneOnlyARAPAccess
+    toEnum 2 = UseZoneFilterInclusivelyARAPAccess
+    toEnum 4 = UseZoneFilterExclusivelyARAPAccess
+    toEnum n = error $ "Invalid RADIUS ARAP Zone Access " ++ show n
+    fromEnum DefaultZoneOnlyARAPAccess = 1
+    fromEnum UseZoneFilterInclusivelyARAPAccess = 2
+    fromEnum UseZoneFilterExclusivelyARAPAccess = 4
