module Nettle.Ethernet.AddressResolutionProtocol (
ARPPacket (..)
, ARPQueryPacket(..)
, ARPReplyPacket(..)
, getARPPacket
, getARPPacket2
, putARPPacket
) where
import Nettle.Ethernet.EthernetAddress
import Nettle.IPv4.IPAddress
import Data.Binary
import Data.Binary.Put
import Data.Word
import Control.Monad
import Control.Monad.Error
import Data.HList
import qualified Data.Binary.Strict.Get as Strict
import qualified Nettle.OpenFlow.StrictPut as Strict
import qualified Data.Binary.Get as Binary
data ARPPacket = ARPQuery ARPQueryPacket
| ARPReply ARPReplyPacket
deriving (Show, Eq)
data ARPQueryPacket =
ARPQueryPacket { querySenderEthernetAddress :: EthernetAddress
, querySenderIPAddress :: IPAddress
, queryTargetIPAddress :: IPAddress
} deriving (Show,Eq)
data ARPReplyPacket =
ARPReplyPacket { replySenderEthernetAddress :: EthernetAddress
, replySenderIPAddress :: IPAddress
, replyTargetEthernetAddress :: EthernetAddress
, replyTargetIPAddress :: IPAddress
}
deriving (Show, Eq)
queryOpCode, replyOpCode :: Word16
queryOpCode = 1
replyOpCode = 2
getARPPacket :: Strict.Get (Maybe ARPPacket)
getARPPacket = do
htype <- Strict.getWord16be
ptype <- Strict.getWord16be
hlen <- Strict.getWord8
plen <- Strict.getWord8
opCode <- Strict.getWord16be
sha <- getEthernetAddress
spa <- getIPAddress
tha <- getEthernetAddress
tpa <- getIPAddress
body <- if opCode == queryOpCode
then return ( Just (ARPQuery (ARPQueryPacket { querySenderEthernetAddress = sha
, querySenderIPAddress = spa
, queryTargetIPAddress = tpa
}
)
)
)
else if opCode == replyOpCode
then return (Just (ARPReply (ARPReplyPacket { replySenderEthernetAddress = sha
, replySenderIPAddress = spa
, replyTargetEthernetAddress = tha
, replyTargetIPAddress = tpa
}
)
)
)
else return Nothing
return body
getARPPacket2 :: Binary.Get (Maybe ARPPacket)
getARPPacket2 = do
htype <- Binary.getWord16be
ptype <- Binary.getWord16be
hlen <- Binary.getWord8
plen <- Binary.getWord8
opCode <- Binary.getWord16be
sha <- getEthernetAddress2
spa <- getIPAddress2
tha <- getEthernetAddress2
tpa <- getIPAddress2
body <- if opCode == queryOpCode
then return ( Just (ARPQuery (ARPQueryPacket { querySenderEthernetAddress = sha
, querySenderIPAddress = spa
, queryTargetIPAddress = tpa
}
)
)
)
else if opCode == replyOpCode
then return (Just (ARPReply (ARPReplyPacket { replySenderEthernetAddress = sha
, replySenderIPAddress = spa
, replyTargetEthernetAddress = tha
, replyTargetIPAddress = tpa
}
)
)
)
else return Nothing
return body
putARPPacket :: ARPPacket -> Strict.Put
putARPPacket body =
case body of
(ARPQuery (ARPQueryPacket {..})) ->
do
Strict.putWord16be ethernetHardwareType
Strict.putWord16be ipProtocolType
Strict.putWord8 numberOctetsInEthernetAddress
Strict.putWord8 numberOctetsInIPAddress
Strict.putWord16be queryOpCode
putEthernetAddress querySenderEthernetAddress
putIPAddress querySenderIPAddress
putEthernetAddress (ethernetAddress 0 0 0 0 0 0)
putIPAddress queryTargetIPAddress
(ARPReply (ARPReplyPacket {..})) ->
do
Strict.putWord16be ethernetHardwareType
Strict.putWord16be ipProtocolType
Strict.putWord8 numberOctetsInEthernetAddress
Strict.putWord8 numberOctetsInIPAddress
Strict.putWord16be replyOpCode
putEthernetAddress replySenderEthernetAddress
putIPAddress replySenderIPAddress
putEthernetAddress replyTargetEthernetAddress
putIPAddress replyTargetIPAddress
ethernetHardwareType = 1
ipProtocolType = 0x0800
numberOctetsInEthernetAddress = 6
numberOctetsInIPAddress = 4