module Hans.IP4.State (
IP4State(..),
SendSource(..),
ResponderRequest(..),
newIP4State,
HasIP4State(..),
addRoute,
lookupRoute4,
isLocalAddr,
nextIdent,
routesForDev,
) where
import Hans.Config (Config(..))
import Hans.Device.Types (Device(..))
import Hans.Ethernet (Mac)
import Hans.IP4.ArpTable (ArpTable,newArpTable)
import Hans.IP4.Fragments (FragTable,newFragTable)
import Hans.IP4.Packet (IP4,IP4Ident)
import qualified Hans.IP4.RoutingTable as RT
import Hans.Lens
import Hans.Network.Types (NetworkProtocol)
import qualified Control.Concurrent.BoundedChan as BC
import qualified Data.ByteString.Lazy as L
import Data.IORef (IORef,newIORef,atomicModifyIORef',readIORef)
import System.Random (StdGen,newStdGen,Random(random))
data SendSource = SourceAny
| SourceIP4 !IP4
| SourceDev !Device !IP4
data ResponderRequest = Finish !Device !Mac [L.ByteString]
| Send !SendSource !IP4 !Bool !NetworkProtocol L.ByteString
data IP4State = IP4State { ip4Routes :: !(IORef RT.RoutingTable)
, ip4ArpTable :: !ArpTable
, ip4Fragments :: !FragTable
, ip4ArpRetry :: !Int
, ip4ArpRetryDelay :: !Int
, ip4ResponderQueue :: !(BC.BoundedChan ResponderRequest)
, ip4RandomSeed :: !(IORef StdGen)
}
newIP4State :: Config -> IO IP4State
newIP4State cfg =
do ip4Routes <- newIORef RT.empty
ip4ArpTable <- newArpTable cfg
ip4Fragments <- newFragTable cfg
ip4ResponderQueue <- BC.newBoundedChan 32
ip4RandomSeed <- newIORef =<< newStdGen
return IP4State { ip4ArpRetry = cfgArpRetry cfg
, ip4ArpRetryDelay = cfgArpRetryDelay cfg * 1000
, .. }
class HasIP4State state where
ip4State :: Getting r state IP4State
instance HasIP4State IP4State where
ip4State = id
addRoute :: HasIP4State state => state -> Bool -> RT.Route -> IO ()
addRoute state = \ defRoute route ->
atomicModifyIORef' ip4Routes (\ table -> (RT.addRule defRoute route table, ()))
where
IP4State { .. } = view ip4State state
lookupRoute4 :: HasIP4State state => state -> IP4 -> IO (Maybe (IP4,IP4,Device))
lookupRoute4 state = \ dest ->
do routes <- readIORef ip4Routes
case RT.lookupRoute dest routes of
Just route -> return (Just ( RT.routeSource route
, RT.routeNextHop dest route
, RT.routeDevice route))
Nothing -> return Nothing
where
IP4State { .. } = view ip4State state
isLocalAddr :: HasIP4State state => state -> IP4 -> IO (Maybe RT.Route)
isLocalAddr state = \ dst ->
do rt <- readIORef ip4Routes
return $! RT.isLocal dst rt
where
IP4State { .. } = view ip4State state
nextIdent :: HasIP4State state => state -> IO IP4Ident
nextIdent state =
atomicModifyIORef' ip4RandomSeed (\g -> case random g of (a,g') -> (g',a) )
where
IP4State { .. } = view ip4State state
routesForDev :: HasIP4State state => state -> Device -> IO [RT.Route]
routesForDev state dev =
do routes <- readIORef (ip4Routes (view ip4State state))
return $! RT.routesForDev dev routes