module Hans.Udp.Input (
processUdp
) where
import Hans.Addr (Addr,toAddr)
import qualified Hans.Buffer.Datagram as DG
import Hans.Checksum (finalizeChecksum,extendChecksum)
import Hans.Device (Device(..),ChecksumOffload(..),rxOffload)
import Hans.IP4.Packet (IP4)
import Hans.Lens (view)
import Hans.Monad (Hans,decode',dropPacket,io)
import Hans.Nat.Forward (tryForwardUdp)
import Hans.Network
import Hans.Udp.Output (queueUdp)
import Hans.Udp.Packet
import Hans.Types
import Control.Monad (unless)
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
processUdp :: Network addr
=> NetworkStack -> Device -> addr -> addr -> S.ByteString -> Hans Bool
processUdp ns dev src dst bytes =
do let checksum = finalizeChecksum $ extendChecksum bytes
$ pseudoHeader src dst PROT_UDP
$ S.length bytes
unless (coUdp (view rxOffload dev) || checksum == 0)
(dropPacket (devStats dev))
((hdr,payloadLen),payload) <- decode' (devStats dev) getUdpHeader bytes
let local = toAddr dst
remote = toAddr src
io (routeMsg ns dev local remote hdr (S.take payloadLen payload))
routeMsg :: NetworkStack -> Device -> Addr -> Addr -> UdpHeader -> S.ByteString -> IO Bool
routeMsg ns dev local remote hdr payload =
do mb <- lookupRecv ns remote (udpDestPort hdr)
case mb of
Just buf ->
do _ <- DG.writeChunk buf (dev,remote,udpSourcePort hdr,local,udpDestPort hdr) payload
return True
Nothing ->
do mbFwd <- tryForwardUdp ns local remote hdr
case mbFwd of
Just (ri,dst',hdr') -> queueUdp ns ri dst' hdr' (L.fromStrict payload)
Nothing -> return False