A service for Scanning and Connecting to WiFi Networks from the CF

I’m going through the Smart Device Framework‘s WZC code doing testing and hardening (yes, I realize it’s long overdue) and I realize that it’s not all that clear how to add a preferred network to a wireless adapter.  I’ve created the beginnings of a new Service class for the OpenNETCF IoC framework (though it’s not required that you use IoC to use the service) that will help applications manage things.  I’ll come back and update this code as I expand the service due to dogfooding it, but here’s the start:


 

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;

namespace OpenNETCF.Net.NetworkInformation
{
public delegate void ScanCompleteDelegate(AccessPoint[] newNetworks, AccessPoint[] lostNetworks, AccessPoint[] stillAvailableNetworks);

public class WiFiService
{
private List m_knownAPs = new List();
private object m_syncRoot = new object();
private AutoResetEvent m_stopScanEvent = new AutoResetEvent(false);
private WirelessZeroConfigNetworkInterface m_wzc;

public event ScanCompleteDelegate ScanComplete;

public int ScanPeriod { get; set; }
public bool Scanning { get; private set; }

public WiFiService(WirelessZeroConfigNetworkInterface netInterface)
{
m_wzc = netInterface;

// default to a 2 second network scan period
ScanPeriod = 2000;
}

~WiFiService()
{
StopScanning();
m_knownAPs.Clear();
}

public void StartScanning()
{
if (Scanning) return;

new Thread(ScanThreadProc) { IsBackground = true }
.Start();
}

public void StopScanning()
{
if (!Scanning) return;

m_stopScanEvent.Set();
m_knownAPs.Clear();
}

public bool ConnectToOpenNetwork(string ssid)
{
return ConnectToNetwork(ssid, null, false, AuthenticationMode.Open, WEPStatus.WEPDisabled);
}

public bool ConnectToOpenNetwork(AccessPoint accessPoint)
{
return m_wzc.AddPreferredNetwork(accessPoint);
}

public bool ConnectToWEPNetwork(string ssid, string wepKey)
{
return ConnectToNetwork(ssid, wepKey, false, AuthenticationMode.Open, WEPStatus.WEPEnabled);
}

public bool ConnectToWEPNetwork(AccessPoint accessPoint, string wepKey)
{
return ConnectToWEPNetwork(accessPoint.Name, wepKey);
}

///


/// This connects to a WPA network using TKIP encryption.
///

///
///
///
public bool ConnectToWPANetwork(string ssid, string passphrase)
{
return ConnectToNetwork(ssid, passphrase, false, AuthenticationMode.WPAPSK, WEPStatus.TKIPEnabled);
}

///


/// This method will only connect to a WPA2 network using AES.
/// If you need fallback to WPA (using TKIP), use the overload that takes in an AccessPoint
///

///
///
///
public bool ConnectToWPA2Network(string ssid, string passphrase)
{
return ConnectToNetwork(ssid, passphrase, false, AuthenticationMode.WPA2PSK, WEPStatus.AESEnabled);
}

///


/// Connects to a WPA or WPA2 (AES or TKIP)
///

///
///
///
public bool ConnectToWPANetwork(AccessPoint accessPoint, string passphrase)
{
// quick validation
var valid = accessPoint.AuthenticationMode == AuthenticationMode.WPA
|| accessPoint.AuthenticationMode == AuthenticationMode.WPAPSK
|| accessPoint.AuthenticationMode == AuthenticationMode.WPA2
|| accessPoint.AuthenticationMode == AuthenticationMode.WPA2PSK;

if (!valid)
{
throw new InvalidOperationException(“The provided AP is not set up for WPA”);
}

return ConnectToNetwork(accessPoint.Name, passphrase, false, accessPoint.AuthenticationMode, accessPoint.Privacy);
}

private void ScanThreadProc()
{
lock (m_syncRoot)
{
Scanning = true;

do
{
var et = Environment.TickCount;

var current = m_wzc.NearbyAccessPoints;

var added = current.Except(m_knownAPs);
var lost = m_knownAPs.Except(current);
var updated = m_knownAPs.Intersect(current);

m_knownAPs = current.ToList();

var handler = ScanComplete;

et = Environment.TickCount – et;
Debug.WriteLine(string.Format(“Network scan took {0}ms”, et));

if (handler != null)
{
handler(added.ToArray(), lost.ToArray(), updated.ToArray());
}
} while (!m_stopScanEvent.WaitOne(ScanPeriod, false));

Scanning = false;
}
}

private bool ConnectToNetwork(string ssid, string passphrase, bool adhoc, AuthenticationMode mode, WEPStatus encryption)
{
EAPParameters eap = null;

switch (mode)
{
case AuthenticationMode.WPA:
case AuthenticationMode.WPAPSK:
case AuthenticationMode.WPA2:
case AuthenticationMode.WPA2PSK:
eap = new EAPParameters()
{
Enable8021x = true,
EapType = EAPType.Default,
EapFlags = EAPFlags.Enabled,
};
break;
}

// stop scanning while connecting
var wasScanning = Scanning;
StopScanning();

try
{
lock (m_syncRoot)
{
return m_wzc.AddPreferredNetwork(ssid,
!adhoc,
passphrase,
1,
mode,
encryption,
eap);
}
}
finally
{
if (wasScanning) StartScanning();
}
}
}
}

One thought on “A service for Scanning and Connecting to WiFi Networks from the CF”

  1. Should your delegate declaration contain interfaces for its parameters perhaps? Something like:

    public delegate void ScanCompleteDelegate(IAccessPoint[] newNetworks, IAccessPoint[] lostNetworks, IAccessPoint[] stillAvailableNetworks);

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s