module Network.Etherbunny.Ethernet (
MACAddr,
EthType,
EtherPkt,
getEtherPacket
) where
import Network.Etherbunny.Ip
import Network.Etherbunny.Packet
import Data.Word
import qualified Data.ByteString as B
import Data.Binary.Get
import Numeric
import Bits
newtype MACAddr = MACAddr Word64
deriving (Eq, Ord, Bits, Num, Integral, Enum, Real)
instance Show MACAddr where
showsPrec _ (MACAddr m) =
foldr (\i a -> showsHexByte (getWord m i) ":" . a) (showsHexByte (getWord m 0) "") $ [5,4..1]
where
getWord x i = (x `shiftR` (i*8)) .&. 0xff
showsHexByte x a = showString $ tail $ showHex (16^(2 :: Int)+x) a
macFromList :: [Word8] -> MACAddr
macFromList = wordsToInt 6
newtype EthType = EthType Word16
deriving (Num, Eq)
instance Show EthType where
showsPrec _ (EthType e) =
showString $ tail $ showHex ((16 :: Int)^(4 :: Int)+ 0x0800) $ " " ++ etherTypeName e
etherTypeName :: (Num a) => a -> [Char]
etherTypeName e
| e == 0x0800 = "IP"
| otherwise = "Unknown"
data EtherPayload = IPPkt IPPkt
deriving (Show)
data EtherPkt = EtherPkt {
ethDestination :: !MACAddr,
ethSource :: !MACAddr,
ethType :: !EthType,
ethPayload :: !(Maybe EtherPayload),
ethRemainder :: !([Word8])
}
instance Show EtherPkt where
showsPrec p pkt =
showString "Ethernet II dest: " . showsPrec p (ethDestination pkt)
. showString " src: " . showsPrec p (ethSource pkt)
. showString " type: " . showsPrec p (ethType pkt)
. showsPrec p (ethPayload pkt)
. showsPrec p (ethRemainder pkt)
getMacAddress :: Get MACAddr
getMacAddress = do
mac <- getByteString 6
return $ macFromList $ B.unpack mac
getEtherPacket :: Get EtherPkt
getEtherPacket = do
dst <- getMacAddress
src <- getMacAddress
typ <- getWord16be
payload <- do
case typ of
0x0800 -> do
payload <- getIPPacket
return $ Just $ IPPkt payload
_ -> return Nothing
numRemain <- remaining
remain <- getByteString $ fromIntegral numRemain
return $ EtherPkt dst src (EthType typ) payload (B.unpack remain)