summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--changelog.md2
-rw-r--r--readme.md31
-rw-r--r--src/Xmobar/Plugins/Monitors.hs8
-rw-r--r--src/Xmobar/Plugins/Monitors/Wireless.hs73
-rw-r--r--xmobar.cabal14
5 files changed, 106 insertions, 22 deletions
diff --git a/changelog.md b/changelog.md
index a52fce3..93fa31e 100644
--- a/changelog.md
+++ b/changelog.md
@@ -20,6 +20,8 @@ _New features_
- New more efficient time coalescing strategy for monitor updates,
available with the threaded runtime: use the `with_threaded` flag
to enable it (see #410; thanks to Tomáš Janoušek).
+ - `Wireless` supports current nl80211 API on Linux now, old Wext ioctls still
+ available as compile-time option (thanks to Paul Fertser).
## Version 0.32 (December, 2019)
diff --git a/readme.md b/readme.md
index eb14023..7afac44 100644
--- a/readme.md
+++ b/readme.md
@@ -117,11 +117,15 @@ Otherwise, you'll need to install them yourself.
option is needed for the MBox and Mail plugins to work. Requires the
[hinotify] package.
-- `with_iwlib` Support for wireless cards. Enables the Wireless
- plugin. No Haskell library is required, but you will need the
- [iwlib] C library and headers in your system (e.g., install
- `libiw-dev` in Debian-based systems or `wireless_tools` on Arch
- Linux).
+- `with_nl80211` Support for wireless cards on Linux via nl80211 (all
+ upstream drivers). Enables the Wireless plugin. Requires [netlink]
+ and [cereal] packages.
+
+- `with_iwlib` Support for wireless cards via Wext ioctls
+ (deprecated). Enables the Wireless plugin. No Haskell library is
+ required, but you will need the [iwlib] C library and headers in your
+ system (e.g., install `libiw-dev` in Debian-based systems or
+ `wireless_tools` on Arch Linux). Conflicts with `with_nl80211`.
- `with_alsa` Support for ALSA sound cards. Enables the Volume
plugin. Requires the [alsa-mixer] package. To install the latter,
@@ -820,18 +824,21 @@ specification, such as `("clear", "<icon=weather-clear.xbm/>")`.
### `Wireless Interface Args RefreshRate`
-- If set to "", the interface is looked up in /proc/net/wireless.
+- If set to "", first suitable wireless interface is used.
- Aliases to the interface name with the suffix "wi": thus, `Wireless
"wlan0" []` can be used as `%wlan0wi%`, and `Wireless "" []` as `%wi%`.
- Args: default monitor arguments, plus:
- `--quality-icon-pattern`: dynamic string for connection quality in `qualityipat`.
- Variables that can be used with the `-t`/`--template` argument:
- `essid`, `quality`, `qualitybar`, `qualityvbar`, `qualityipat`
-- Thresholds refer to link quality in a `[0, 100]` scale
-- Default template: `<essid> <quality>`
-- Requires the C library [iwlib] (part of the wireless tools suite)
- installed in your system. In addition, to activate this plugin you
- must pass `--flags="with_iwlib"` during compilation
+ `ssid`, `signal`, `quality`, `qualitybar`, `qualityvbar`, `qualityipat`
+- Thresholds refer to link quality on a `[0, 100]` scale. Note that
+ `quality` is calculated from `signal` (in dBm) by a possibly lossy
+ conversion. It is also not taking into account many factors such as
+ noise level, air busy time, transcievers' capabilities and the
+ others which can have drastic impact on the link performance.
+- Default template: `<ssid> <quality>`
+- To activate this plugin you must pass `--flags="with_nl80211"` or
+ `--flags="with_iwlib"` during compilation
### `Memory Args RefreshRate`
diff --git a/src/Xmobar/Plugins/Monitors.hs b/src/Xmobar/Plugins/Monitors.hs
index d6fc0a0..322d401 100644
--- a/src/Xmobar/Plugins/Monitors.hs
+++ b/src/Xmobar/Plugins/Monitors.hs
@@ -42,7 +42,7 @@ import Xmobar.Plugins.Monitors.CatInt
#ifdef UVMETER
import Xmobar.Plugins.Monitors.UVMeter
#endif
-#ifdef IWLIB
+#if defined IWLIB || defined USE_NL80211
import Xmobar.Plugins.Monitors.Wireless
#endif
#ifdef LIBMPD
@@ -85,7 +85,7 @@ data Monitors = Network Interface Args Rate
#ifdef UVMETER
| UVMeter Station Args Rate
#endif
-#ifdef IWLIB
+#if defined IWLIB || defined USE_NL80211
| Wireless Interface Args Rate
#endif
#ifdef LIBMPD
@@ -142,7 +142,7 @@ instance Exec Monitors where
#ifdef UVMETER
alias (UVMeter s _ _) = "uv " ++ s
#endif
-#ifdef IWLIB
+#if defined IWLIB || defined USE_NL80211
alias (Wireless i _ _) = i ++ "wi"
#endif
#ifdef LIBMPD
@@ -186,7 +186,7 @@ instance Exec Monitors where
#ifdef UVMETER
start (UVMeter s a r) = startUVMeter s a r
#endif
-#ifdef IWLIB
+#if defined IWLIB || defined USE_NL80211
start (Wireless i a r) = runM a wirelessConfig (runWireless i) r
#endif
#ifdef LIBMPD
diff --git a/src/Xmobar/Plugins/Monitors/Wireless.hs b/src/Xmobar/Plugins/Monitors/Wireless.hs
index f2b1e6a..28aba50 100644
--- a/src/Xmobar/Plugins/Monitors/Wireless.hs
+++ b/src/Xmobar/Plugins/Monitors/Wireless.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE TypeApplications, CPP #-}
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.Monitors.Wireless
@@ -8,16 +9,68 @@
-- Stability : unstable
-- Portability : unportable
--
--- A monitor reporting ESSID and link quality for wireless interfaces
+-- A monitor reporting SSID and signal level for wireless interfaces
--
-----------------------------------------------------------------------------
module Xmobar.Plugins.Monitors.Wireless (wirelessConfig, runWireless) where
import System.Console.GetOpt
+import Data.Maybe (fromMaybe)
import Xmobar.Plugins.Monitors.Common
+
+#ifdef IWLIB
import Network.IWlib
+#elif defined USE_NL80211
+import Control.Exception (bracket)
+import qualified Data.Map as M
+import GHC.Int (Int8)
+import Data.Maybe (listToMaybe)
+import Control.Monad.IO.Class (liftIO)
+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
+import Data.ByteString.Char8 (unpack)
+import Data.Serialize.Put (runPut, putWord32host, putByteString)
+import Data.Serialize.Get (runGet)
+
+import System.Linux.Netlink hiding (query)
+import System.Linux.Netlink.GeNetlink.NL80211
+import System.Linux.Netlink.GeNetlink.NL80211.StaInfo
+import System.Linux.Netlink.GeNetlink.NL80211.Constants
+import System.Posix.IO (closeFd)
+
+data IwData = IwData { wiEssid :: String, wiSignal :: Maybe Int, wiQuality :: Int }
+
+getWirelessInfo :: String -> IO IwData
+getWirelessInfo ifname = do
+ bracket makeNL80211Socket (closeFd . getFd) (\s -> do
+ iflist <- getInterfaceList s
+ iwdata <- runMaybeT $ do
+ ifidx <- MaybeT . return $ foldr (\(n, i) z ->
+ if (ifname == "" || ifname == n) then Just i else z)
+ Nothing
+ iflist
+ scanp <- liftIO (getConnectedWifi s ifidx) >>=
+ MaybeT . return . listToMaybe
+ bssid <- MaybeT . return $ M.lookup eNL80211_ATTR_BSS (packetAttributes scanp) >>=
+ rightToMaybe . runGet getAttributes >>=
+ M.lookup eNL80211_BSS_BSSID
+ stap <- liftIO (query s eNL80211_CMD_GET_STATION True $ M.fromList
+ [(eNL80211_ATTR_IFINDEX, runPut $ putWord32host ifidx),
+ (eNL80211_ATTR_MAC, runPut $ putByteString bssid)]) >>=
+ MaybeT . return . listToMaybe
+ let ssid = fromMaybe "" $ getWifiAttributes scanp >>= M.lookup eWLAN_EID_SSID >>=
+ return . unpack
+ signal = staInfoFromPacket stap >>= staSignalMBM >>=
+ return . fromIntegral @Int8 . fromIntegral
+ qlty = fromMaybe (-1) (round @Float . (/ 0.7) . (+ 110) .
+ clamp (-110) (-40) . fromIntegral <$> signal)
+ MaybeT . return $ Just $ IwData ssid signal qlty
+ return $ fromMaybe (IwData "" Nothing (-1)) iwdata)
+ where
+ rightToMaybe = either (const Nothing) Just
+ clamp lb up v = if v < lb then lb else if v > up then up else v
+#endif
newtype WirelessOpts = WirelessOpts
{ qualityIconPattern :: Maybe IconPattern
@@ -36,29 +89,41 @@ options =
wirelessConfig :: IO MConfig
wirelessConfig =
- mkMConfig "<essid> <quality>"
- ["essid", "quality", "qualitybar", "qualityvbar", "qualityipat"]
+ mkMConfig "<ssid> <quality>"
+ ["ssid", "essid", "signal", "quality", "qualitybar", "qualityvbar", "qualityipat"]
runWireless :: String -> [String] -> Monitor String
runWireless iface args = do
opts <- io $ parseOptsWith options defaultOpts args
+#ifdef IWLIB
iface' <- if "" == iface then io findInterface else return iface
+#else
+ let iface' = iface
+#endif
wi <- io $ getWirelessInfo iface'
na <- getConfigValue naString
let essid = wiEssid wi
qlty = fromIntegral $ wiQuality wi
e = if essid == "" then na else essid
ep <- showWithPadding e
+#ifdef USE_NL80211
+ let s = wiSignal wi
+#else
+ let s = if qlty >= 0 then Just (qlty * 0.7 - 110) else Nothing
+#endif
+ sp <- showWithPadding $ fromMaybe "" (show <$> s)
q <- if qlty >= 0
then showPercentWithColors (qlty / 100)
else showWithPadding ""
qb <- showPercentBar qlty (qlty / 100)
qvb <- showVerticalBar qlty (qlty / 100)
qipat <- showIconPattern (qualityIconPattern opts) (qlty / 100)
- parseTemplate [ep, q, qb, qvb, qipat]
+ parseTemplate [ep, ep, sp, q, qb, qvb, qipat]
+#ifdef IWLIB
findInterface :: IO String
findInterface = do
c <- readFile "/proc/net/wireless"
let nds = lines c
return $ if length nds > 2 then takeWhile (/= 'c') (nds!!2) else []
+#endif
diff --git a/xmobar.cabal b/xmobar.cabal
index f23275f..b29b987 100644
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -40,7 +40,11 @@ flag with_inotify
default: False
flag with_iwlib
- description: Wireless info support. Required for the Wireless plugin, needs iwlib installed.
+ description: Wireless info support via Wext ioctls (deprecated). Required for the Wireless plugin, needs iwlib installed.
+ default: False
+
+flag with_nl80211
+ description: Wireless info support via nl80211. Required for the Wireless plugin on systems running Linux, the kernel.
default: False
flag with_mpd
@@ -209,12 +213,18 @@ library
exposed-modules: Xmobar.Plugins.Mail, Xmobar.Plugins.MBox
cpp-options: -DINOTIFY
- if flag(with_iwlib) || flag(all_extensions)
+ if flag(with_iwlib)
extra-libraries: iw
build-depends: iwlib >= 0.1.0 && < 0.2
exposed-modules: Xmobar.Plugins.Monitors.Wireless
cpp-options: -DIWLIB
+ if flag(with_nl80211) || flag(all_extensions)
+ build-depends: netlink >= 1.1.1.0,
+ cereal >= 0.5.8.1
+ exposed-modules: Xmobar.Plugins.Monitors.Wireless
+ cpp-options: -DUSE_NL80211
+
if flag(with_mpd) || flag(all_extensions)
build-depends: libmpd >= 0.9.0.10
exposed-modules: Xmobar.Plugins.Monitors.MPD