BNetworkDevice: Implement Scan().
This depends on the previous commit to return the correct error code from ioctl(). If there are no VAPs running (which is the case after a forced disconnect from an access point), scans will fail. In that case, we call IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP, which will restart a VAP, and then initiate the scan. Change-Id: I732aefe67e386dbb0ed3d232ed9deda678132601 Reviewed-on: https://review.haiku-os.org/551 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
e9073260a7
commit
4e5aaaa700
@@ -13,9 +13,11 @@
|
|||||||
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
||||||
|
|
||||||
#include <Messenger.h>
|
#include <Messenger.h>
|
||||||
|
#include <Looper.h>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
#include <NetServer.h>
|
#include <NetServer.h>
|
||||||
|
#include <NetworkNotifications.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
# include <compat/sys/cdefs.h>
|
# include <compat/sys/cdefs.h>
|
||||||
@@ -42,6 +44,9 @@ struct ie_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private functions (code shared with net_server)
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
get_80211(const char* name, int32 type, void* data, int32& length)
|
get_80211(const char* name, int32 type, void* data, int32& length)
|
||||||
{
|
{
|
||||||
@@ -66,6 +71,30 @@ get_80211(const char* name, int32 type, void* data, int32& length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
set_80211(const char* name, int32 type, void* data,
|
||||||
|
int32 length = 0, int32 value = 0)
|
||||||
|
{
|
||||||
|
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (socket < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
FileDescriptorCloser closer(socket);
|
||||||
|
|
||||||
|
struct ieee80211req ireq;
|
||||||
|
strlcpy(ireq.i_name, name, IF_NAMESIZE);
|
||||||
|
ireq.i_type = type;
|
||||||
|
ireq.i_val = value;
|
||||||
|
ireq.i_len = length;
|
||||||
|
ireq.i_data = data;
|
||||||
|
|
||||||
|
if (ioctl(socket, SIOCS80211, &ireq, sizeof(struct ieee80211req)) < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T> status_t
|
template<typename T> status_t
|
||||||
do_request(T& request, const char* name, int option)
|
do_request(T& request, const char* name, int option)
|
||||||
{
|
{
|
||||||
@@ -687,17 +716,87 @@ BNetworkDevice::Control(int option, void* request)
|
|||||||
status_t
|
status_t
|
||||||
BNetworkDevice::Scan(bool wait, bool forceRescan)
|
BNetworkDevice::Scan(bool wait, bool forceRescan)
|
||||||
{
|
{
|
||||||
#if 0
|
// Network status listener for change notifications
|
||||||
if (index == 0) {
|
class ScanListener : public BLooper {
|
||||||
struct ieee80211_scan_req request;
|
public:
|
||||||
memset(&request, 0, sizeof(request));
|
ScanListener(BString iface)
|
||||||
request.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE
|
:
|
||||||
| IEEE80211_IOC_SCAN_NOJOIN;
|
fInterface(iface)
|
||||||
request.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
|
{
|
||||||
set_80211(Name(), IEEE80211_IOC_SCAN_REQ, NULL);
|
start_watching_network(B_WATCH_NETWORK_WLAN_CHANGES, this);
|
||||||
|
}
|
||||||
|
virtual ~ScanListener()
|
||||||
|
{
|
||||||
|
stop_watching_network(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void MessageReceived(BMessage *message)
|
||||||
|
{
|
||||||
|
if (message->what != B_NETWORK_MONITOR) {
|
||||||
|
BLooper::MessageReceived(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BString interfaceName;
|
||||||
|
if (message->FindString("interface", &interfaceName) != B_OK)
|
||||||
|
return;
|
||||||
|
if (fInterface.FindFirst(interfaceName) < 0)
|
||||||
|
return;
|
||||||
|
if (message->FindInt32("opcode") != B_NETWORK_WLAN_SCANNED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Lock();
|
||||||
|
Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fInterface;
|
||||||
|
};
|
||||||
|
|
||||||
|
ScanListener* listener = NULL;
|
||||||
|
if (wait)
|
||||||
|
listener = new ScanListener(Name());
|
||||||
|
|
||||||
|
// Trigger the scan
|
||||||
|
struct ieee80211_scan_req request;
|
||||||
|
memset(&request, 0, sizeof(request));
|
||||||
|
request.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
|
||||||
|
| IEEE80211_IOC_SCAN_BGSCAN
|
||||||
|
| IEEE80211_IOC_SCAN_NOPICK
|
||||||
|
| IEEE80211_IOC_SCAN_ONCE
|
||||||
|
| (forceRescan ? IEEE80211_IOC_SCAN_FLUSH : 0);
|
||||||
|
request.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
|
||||||
|
request.sr_nssid = 0;
|
||||||
|
|
||||||
|
status_t status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request,
|
||||||
|
sizeof(request));
|
||||||
|
|
||||||
|
// If there are no VAPs running, the net80211 layer will return ENXIO.
|
||||||
|
// Try to bring up the interface (which should start a VAP) and try again.
|
||||||
|
if (status == ENXIO) {
|
||||||
|
struct ieee80211req dummy;
|
||||||
|
status = set_80211(Name(), IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP, &dummy,
|
||||||
|
sizeof(dummy));
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = set_80211(Name(), IEEE80211_IOC_SCAN_REQ, &request,
|
||||||
|
sizeof(request));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return B_ERROR;
|
// If there is already a scan currently running, it's probably an "infinite"
|
||||||
|
// one, which we of course don't want to wait for. So just return immediately
|
||||||
|
// if that's the case.
|
||||||
|
if (status == EINPROGRESS)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
if (!wait || status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
while (wait_for_thread(listener->Run(), NULL) == B_INTERRUPTED)
|
||||||
|
;
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user