
Hi,
Show below is a short program using the FFI to access libiw and provide,
given an interface name such as "wlan0" the associated ESSID. One uses
iw_get_basic_config to fill a struct wireless_config (dynamically
allocated), and extract from that the desired string, which is a field
of type char[MAX_ESSID_LEN] in said struct type.
When i run this program (or call getWirelessInfo inside ghci) with an
existing network interface, it segfaults (calling it with a non-existent
one returns the expected empty string, so the problem is after the first
'if' in getWirelessInfo): can anybody spot what am i doing wrong? Or
perhaps give me any hint on how to debug the issue?
TIA!
jao
{-# LANGUAGE CPP, ForeignFunctionInterface #-}
module Main (main) where
import System.Environment
import Foreign
import Foreign.C.Types
import Foreign.C.String
#include

Hello Jose Looking at the source for iwlib.h the wireless_config struct doesn't have an essid_len field, at least in this version which seems to be current one: * Version : 22 16.3.07 That said, if you are using this version then hsc2hs (the FFI preprocessor) should be throwing an error along the lines of error: structure has no member named 'essid_len' What command line flags are you using to compile? Best wishes Stephen

Hi Stephen,
Stephen Tetley
Hello Jose
Looking at the source for iwlib.h the wireless_config struct doesn't have an essid_len field, at least in this version which seems to be current one:
* Version : 22 16.3.07
That said, if you are using this version then hsc2hs (the FFI preprocessor) should be throwing an error along the lines of
error: structure has no member named 'essid_len'
I'm using the iwlib.h that comes with debian's libiw-dev package, which claims to be version 30 9.4 of wireless tools (it's not clear to me to what version of libiw that corresponds). At any rate, the iwlib.h in my system defines a wireless_config struct with an essid_len (and hsc2hs is thus not complaining). If i try to read the string from essid using peekCString i also get a segfault.
What command line flags are you using to compile?
i do a plain 'hsc2hs Wireless.hsc' and then either 'ghci -liw Wireless.hs' (to try interactively) or 'ghc -o wire -liw Wireless.hs'. I've also tried adding -O, but the results are the same. Thanks a lot for your help, jao

Hi I think I've found a version 30 from Debian's archive - the essid string is fixed length, rather than sized by essid_len (even though essid_len is now in the struct). Is this the same as the version you have? /* Structure for storing all wireless information for each device * This is a cut down version of the one above, containing only * the things *truly* needed to configure a card. * Don't add other junk, I'll remove it... */ typedef struct wireless_config { char name[IFNAMSIZ + 1]; /* Wireless/protocol name */ int has_nwid; iwparam nwid; /* Network ID */ int has_freq; double freq; /* Frequency/channel */ int freq_flags; int has_key; unsigned char key[IW_ENCODING_TOKEN_MAX]; /* Encoding key used */ int key_size; /* Number of bytes */ int key_flags; /* Various flags */ int has_essid; int essid_on; char essid[IW_ESSID_MAX_SIZE + 2]; /* ESSID (extended network) */ int essid_len; int has_mode; int mode; /* Operation mode */ } wireless_config; Best wishes Stephen

Stephen Tetley
Hi
I think I've found a version 30 from Debian's archive - the essid string is fixed length, rather than sized by essid_len (even though essid_len is now in the struct). Is this the same as the version you have?
Yes, it is. I've tried to read the essid field both using peekCString, as in s <- (#peek struct wireless_info, essid) peekCString s and providing explicitly the maximum length of essid (34) to peekCStringLen. Do you mean that for a struct field that is a of type char[LEN] those peek functions are innappropriate? (I've checked using C that essid_len actually gets the correct value, and that the contents of essid is null-terminated, i.e. wi.essid[wi.essid_len] == '\0' is always true). Thanks, jao
/* Structure for storing all wireless information for each device * This is a cut down version of the one above, containing only * the things *truly* needed to configure a card. * Don't add other junk, I'll remove it... */ typedef struct wireless_config { char name[IFNAMSIZ + 1]; /* Wireless/protocol name */ int has_nwid; iwparam nwid; /* Network ID */ int has_freq; double freq; /* Frequency/channel */ int freq_flags; int has_key; unsigned char key[IW_ENCODING_TOKEN_MAX]; /* Encoding key used */ int key_size; /* Number of bytes */ int key_flags; /* Various flags */ int has_essid; int essid_on; char essid[IW_ESSID_MAX_SIZE + 2]; /* ESSID (extended network) */ int essid_len; int has_mode; int mode; /* Operation mode */ } wireless_config;
Best wishes
Stephen

At 11:15 PM +0100 2/19/10, Jose A. Ortega Ruiz wrote:
Stephen Tetley
writes: Hi
I think I've found a version 30 from Debian's archive - the essid string is fixed length, rather than sized by essid_len (even though essid_len is now in the struct). Is this the same as the version you have?
Yes, it is. I've tried to read the essid field both using peekCString, as in
s <- (#peek struct wireless_info, essid) peekCString s
and providing explicitly the maximum length of essid (34) to peekCStringLen. Do you mean that for a struct field that is a of type char[LEN] those peek functions are innappropriate?
(I've checked using C that essid_len actually gets the correct value, and that the contents of essid is null-terminated, i.e. wi.essid[wi.essid_len] == '\0' is always true).
Thanks, jao
/* Structure for storing all wireless information for each device * This is a cut down version of the one above, containing only * the things *truly* needed to configure a card. * Don't add other junk, I'll remove it... */ typedef struct wireless_config { char name[IFNAMSIZ + 1]; /* Wireless/protocol name */ int has_nwid; iwparam nwid; /* Network ID */ int has_freq; double freq; /* Frequency/channel */ int freq_flags; int has_key; unsigned char key[IW_ENCODING_TOKEN_MAX]; /* Encoding key used */ int key_size; /* Number of bytes */ int key_flags; /* Various flags */ int has_essid; int essid_on; char essid[IW_ESSID_MAX_SIZE + 2]; /* ESSID (extended network) */ int essid_len; int has_mode; int mode; /* Operation mode */ } wireless_config;
Best wishes
Stephen
Though I'm not an FFI expert, I'll take a stab in case it might help you. It seems to me that
s <- (#peek struct wireless_info, essid) peekCString s
would read a pointer from the essid field, which is clearly not what you want. I think you'd want to use #ptr. Maybe something like the following (untested!): l <- (#peek struct wireless_config, essid_len) wc p <- (#ptr struct wireless_info, essid) wc -- wireless_config.essid is a char[MAX_LEN] peekCStringLen (p, fromIntegral (l :: CInt)) Dean

Hi Dean,
Dean Herington
Though I'm not an FFI expert, I'll take a stab in case it might help you.
It seems to me that
s <- (#peek struct wireless_info, essid) peekCString s
would read a pointer from the essid field, which is clearly not what you want. I think you'd want to use #ptr. Maybe something like the following (untested!):
l <- (#peek struct wireless_config, essid_len) wc p <- (#ptr struct wireless_info, essid) wc -- wireless_config.essid is a char[MAX_LEN] peekCStringLen (p, fromIntegral (l :: CInt))
Right, using #ptr works (with the minor modification that it doesn't return its value inside IO, so one must use let p =..., instead of p <- ...). Thanks a lot for your help. Cheers, jao
participants (3)
-
Dean Herington
-
Jose A. Ortega Ruiz
-
Stephen Tetley