packages feed

hans-2.1.0.0: src/Hans/Address/Mac.hs

module Hans.Address.Mac (
    Mac(..)
  , showsMac
  , macMask
  ) where

import Hans.Address
import Hans.Utils (showPaddedHex)

import Data.Serialize (Serialize(..))
import Data.Serialize.Get (getWord16be,getWord32be)
import Data.Serialize.Put (putByteString)
import Data.Bits (Bits(shiftR,testBit,complement))
import Data.List (intersperse)
import Data.Word (Word8)
import Numeric (readHex)
import qualified Data.ByteString as S


-- | Mac addresses.
data Mac = Mac
  {-# UNPACK #-} !Word8
  {-# UNPACK #-} !Word8
  {-# UNPACK #-} !Word8
  {-# UNPACK #-} !Word8
  {-# UNPACK #-} !Word8
  {-# UNPACK #-} !Word8
  deriving ( Eq, Ord )


-- | Show a Mac address.
showsMac :: Mac -> ShowS
showsMac (Mac a b c d e f) = foldl1 (.)
                           $ intersperse (showChar ':')
                           $ map showPaddedHex [a,b,c,d,e,f]

-- | Generates a mask tailored to the given MAC address.
macMask :: Mac -> Mac
macMask (Mac a b c d e f) =
  Mac (complement a)
      (complement b)
      (complement c)
      (complement d)
      (complement e)
      (complement f)

instance Show Mac where
  showsPrec _ = showsMac

instance Read Mac where
  readsPrec _ = loop 6 []
    where
    loop :: Int -> [Word8] -> String -> [(Mac,String)]
    loop 0 [f,e,d,c,b,a] str = [(Mac a b c d e f,str)]
    loop 0 _             _   = []
    loop n acc           str = case readHex str of
      [(a,':':rest)] -> loop (n-1) (a:acc) rest
      [(a,    rest)] -> loop 0     (a:acc) rest
      _              -> []


instance Address Mac where
  addrSize _ = 6

  toBits (Mac a b c d e f) = concatMap k [a,b,c,d,e,f]
    where k i = map (testBit i) [0 .. 7]

instance Serialize Mac where
  get = do
    n <- getWord32be
    m <- getWord16be
    let f x d = fromIntegral (x `shiftR` d)
    return $! Mac (f n 24) (f n 16) (f n 8) (fromIntegral n)
                  (f m 8)  (fromIntegral m)

  put (Mac a b c d e f) = putByteString (S.pack [a,b,c,d,e,f])