putIPv4Pkt :: IPv4 a => a -> PutM ()
putIPv4Pkt x = do
  start <- marker
  putWord8 lenIhl
  putWord8 tos
  totLen <- delayedWord16be
  putWord16be ipId
  putWord16be flagsOff
  putWord8    ttl
  putWord8    proto
  acrc <- delayedWord16be
  putIP ipS
  putIP ipD
  hlen <- distance start
  ipPutPayload x
  undelay totLen . Word16be . fromIntegral =<< distance start
  undelay acrc (Word16be $ csum16' 
                  (unsafeDupablePerformIO
                      $ BS.unsafePackAddressLen  hlen (toAddr start)))
  where
    lenIhl = (ihl .&. 0xF) .|. (ver `shiftL` 4 .&. 0xF0)
    ihl    = ipHeaderLen x
    ver    = ipVersion x
    tos    = ipTOS x
    ipId   = ipID x
    flagsOff = (off .&. 0x1FFF) .|. ((fromIntegral flags) `shiftL` 13)
    flags  = ipFlags x
    -- totLen = fromIntegral $ 4*(ipHeaderLen x) + fromIntegral (BS.length body)
    off    = ipFragOffset x
    ttl    = ipTTL x
    proto  = ipProto x
    ipS    = ipSrc x
    ipD    = ipDst x
putIPv4Pkt :: IPv4 a => a -> PutM ()
putIPv4Pkt x = do
  start <- marker
  putWord8 lenIhl
  putWord8 tos
  totLen <- delayedWord16be
  putWord16be ipId
  putWord16be flagsOff
  putWord8    ttl
  putWord8    proto
  acrc <- delayedWord16be
  putIP ipS
  putIP ipD
  hlen <- distance start
  ipPutPayload x
  undelay totLen . Word16be . fromIntegral =<< distance start
  undelay acrc (Word16be $ csum16' 
                  (unsafeDupablePerformIO
                      $ BS.unsafePackAddressLen  hlen (toAddr start)))
  where
    lenIhl = (ihl .&. 0xF) .|. (ver `shiftL` 4 .&. 0xF0)
    ihl    = ipHeaderLen x
    ver    = ipVersion x
    tos    = ipTOS x
    ipId   = ipID x
    flagsOff = (off .&. 0x1FFF) .|. ((fromIntegral flags) `shiftL` 13)
    flags  = ipFlags x
    -- totLen = fromIntegral $ 4*(ipHeaderLen x) + fromIntegral (BS.length body)
    off    = ipFragOffset x
    ttl    = ipTTL x
    proto  = ipProto x
    ipS    = ipSrc x
    ipD    = ipDst x
putIPv4Pkt x = do
  start <- marker
  putWord8 lenIhl
  putWord8 tos
  totLen <- delayedWord16be
  putWord16be ipId
  putWord16be flagsOff
  putWord8    ttl
  putWord8    proto
  acrc <- delayedWord16be
  putIP ipS
  putIP ipD
  hlen <- distance start
  ipPutPayload x
  undelay totLen . Word16be . fromIntegral =<< distance start
  undelay acrc (Word16be $ csum16' 
                  (unsafeDupablePerformIO
                      $ BS.unsafePackAddressLen  hlen (toAddr start)))
  where
    lenIhl = (ihl .&. 0xF) .|. (ver `shiftL` 4 .&. 0xF0)
    ihl    = ipHeaderLen x
    ver    = ipVersion x
    tos    = ipTOS x
    ipId   = ipID x
    flagsOff = (off .&. 0x1FFF) .|. ((fromIntegral flags) `shiftL` 13)
    flags  = ipFlags x
    -- totLen = fromIntegral $ 4*(ipHeaderLen x) + fromIntegral (BS.length body)
    off    = ipFragOffset x
    ttl    = ipTTL x
    proto  = ipProto x
    ipS    = ipSrc x
    ipD    = ipDst x