Documentation  |   Table of Contents   |  < Previous   |  Next >   |  Index

16    Introduction to Wireless Networking

Low-Level Communications

Exploring Palm OS®

Overview ^TOP^

Palm OS® provides direct support for WiFi wireless networking through a set of ioctl commands that allow an application to find, connect to, and disconnect from wireless networks. Other commands allow applications to monitor the status of a wireless network, configure wireless security, and perform other standard management tasks necessary when using WiFi networking.

While the operating system includes the necessary user interface to manage WiFi connectivity, these ioctl commands are available for developers to provide custom solutions.

WiFi Concepts ^TOP^

A WiFi network is identified by an SSID. The SSID is an ASCII string of up to 32 characters.

There are two types of WiFi networks. The typical network, operating in infrastructure mode, is formed by devices connecting wirelessly to an access access point, which is a dedicated device. This device is also sometimes referred to as a base station. Each access point is a Basic Service Set (BSS). An Extended Service Set (ESS) is a entwork of one or more access points that is referred to by a single SSID.

The other type of network, called an ad-hoc network, is created when one or more devices are connected together wirelessly without a dedicated access point.

Locating and Opening a WiFi Interface ^TOP^

Before you can manage WiFi, you need to find and open the WiFi interface. This is done using IOSGetDriverNameByIndex() and IOSOpen(). See Listing 16.1 for an example.

Listing 16.1  Finding and opening the WiFi interface


char name[64]; 
uint16_t nameLen sizeof(name); 
status_t err; 
 
IOSGetDriverNameByIndex(iosDriverClassWifi, 0, (char *) name, 
			&nameLen); 
int32 wifiDataFD = IOSOpen(name, 0, &err); 
 
strcat(name, "_mgmt"); 
int32 wifiMgmtFD = IOSOpen(name, 0, &err); 

To send data over WiFi, you simply open the interface using the name returned by IOSGetDriverNameByIndex(). If, however, you want to send ioctl commands to the WiFi interface, you need to append the string "_mgmt" to the returned name to access the management interface.

Getting Information About the WiFi Interface ^TOP^

Before using the WiFi interface, your application may need to obtain information about the device's capabilities or status. For example, you may need to determine what forms of encryption it supports, whether or not it's already connected to a network, or what channels and transmission rates it supports.

Determining Supported Encryption Modes ^TOP^

To determine which encryption modes the interface supports, use the WIOCGETSECCAPS command, as demonstrated in Listing 16.2.

Listing 16.2  Getting supported encryption modes


WifiGetSecCapType modes; 
status_t err; 
 
IOSIoctl(wifiFD, WIOCGETSECCAPS, (int32_t) &modes, &err); 
 
if (modes.capabilities & WifiSecOpen) { 
	/* Open System is supported */ 
} 
 
if (modes.capabilities & WifiSecWEP) { 
	/ * WEP is supported */ 
} 

Getting the Interface Status ^TOP^

You can obtain information about the current status of the WiFi interface using the WIOCGETSTATUS ioctl. This is seen in Listing 16.3.

Listing 16.3  Getting the current status of the WiFi interface


uint32_t status; 
status_t err; 
 
IOSIoctl(wifiFD, WIOCGETSTATUS, (int32_t) &status, &err); 

After IOSIoctl() returns, status contains a value indicating the current state of the WiFi interface:

Identifying the Currently Connected Network ^TOP^

If you wish to determine the SSID or BSSID of the network to which the interface is connected, use the WIOCGETSSID or WIOCGETBSSID command.

Listing 16.4  Getting the name and BSSID of the access point or ad-hoc network


WifiSSIDType ssid; 
WifiBSSIDType bssid; 
status_t err; 
 
IOSIoctl(wifiFD, WIOCGETSSID, (int32_t) &ssid, &err); 
IOSIoctl(wifiFD, WIOCGETBSSID, (int32_t) &bssid, &err); 

Determining Supported Channels and Transmission Rates ^TOP^

To determine which channels the WiFi interface supports, use the WIOCGETCHANNEL command. This also reports the channel the interface is currently using.

Listing 16.5  Determining supported channels


status_t err; 
WifiChannelType channels; 
 
channels.current = 0; 
channels.supportedMask = 0; 
 
IOSIoctl(wifiFD, WIOCGETCHANNEL, (int32_t) &channels, &err); 

After this code executes, channels.current is set to the channel on which the interface is currently communicating, and channels.supportedMask is a bit mask of all the channels the interface supports. See "Channel Constants" for a list of the channel number flags.

The code in Listing 16.6 determines the rates supported by the interface, which rates are preferred, and what rate is currently in use.

Listing 16.6  Determining supported transmission rates


WifiGetRatesType rates; 
status_t err; 
 
rates.preferred_rates = 0; 
rates.supported_rates = 0; 
rates.current_rate = 0; 
 
IOSIoctl(wifiFD, WIOCGETRATES, (int32_t) &rates, &err); 

On return, rates.current_rate indicates the transmission rate currently in effect, rates.supported_rates is a bit mask of all the transmission rates the interface supports, and rates.preferred_rates is a bit mask of the rates the interface is best suited for. See "Transmission Rate Flags" for the possible values.


NOTE: The preferred rates always default to the complete set of supported rates. You may change them if you wish, using the WIOCSETRATES ioctl.

Getting the Signal Strength ^TOP^

There are two ways to keep apprised of the current signal strength. You can manually poll the signal strength using the WIOCGETCURRENTRSSI command, or you can enable automatic signal strength update notification.

Listing 16.7  Getting the current signal strength


WifiGetRSSIType current; 
 
IOSIoctl(wifiFD, WIOCGETCURRENTRSSI, (int32_t) &current,
					&err); 

After the code in Listing 16.7 executes, current.signal contains the current signal strength, as a percentage between 0 and 100.

To receive periodic notification of changes to the signal strength, use the WIOCSETRSSIUPDATE command. With this command, you can choose to receive notification events whenever any change to signal strength occurs, whenever the signal strength changes by a given amount, or at a specific interval.

Listing 16.8  Enabling automatic signal strength notifications


WifiRSSIUpdateType update; 
status_t err; 
 
/* notify me when signal strength changes by +/- 2% */ 
 
update.updateMode = WifiRSSIUpdateOnDelta; 
update.updateValue = 2; 
 
/* notify me every 1000 milliseconds */ 
 
update.updateMode = WifiRSSIUpdatePeriodic; 
update.updateValue = 1000; 
 
/* notify me every time the signal strength changes */ 
 
update.updateMode = WifiRSSIUpdateAlways; 
update.updateValue = 0; 
 
/* never notify me of signal strength changes */ 
 
update.updateMode = WifiRSSIUpdateNever; 
update.updateValue = 0; 
 
IOSIoctl(wifiFD, WIOCSETRSSIUPDATE, (int32_t) &update, &err); 

The example in Listing 16.8 shows how to set up the WifiRSSIUpdateType structure for each of the four notification modes. Once the structure is prepared, call IOSIoctl() to issue the request.

Finding an Access Point or Ad-hoc Network ^TOP^

To locate an access point or ad-hoc network to which you can connect, you need to use the WIOCSCAN or WIOCPASSIVESCAN command.

Active Scanning ^TOP^

If you want to simply perform a one-time scan of the airwaves for available ad-hoc networks and access points, use WIOCSCAN. See Listing 16.9.

Listing 16.9  Performing a one-shot scan for access points and ad-hoc networks


WifiScanRequestType cmd; 
status_t err; 
 
memset(&cmd, 0, sizeof(WifiScanRequestType)); 
 
cmd.channels = WifiChannel_All; 
cmd.rates = WifiRate_All; 
cmd.timeout = 2000; 
cmd.blockTillCompletion = 0; 
IOSIoctl(wifiFD, WIOCSCAN, (int32_t) &cmd, &err); 

The scan is performed asynchronously; the IOSIoctl() will return immediately. Your application's event loop will receive WiFi events with the scan results. See "Obtaining Scan Results" for details on how to parse the results.

The blockTillCompletion flag indicates whether or not you want the ioctl to block until the first scan result arrives. This example sets it to 0, indicating that we want to return immediately.

Passive Scanning ^TOP^

If you would prefer to constantly be kept informed of the available access points and ad-hoc networks, as they move in and out of range, or are turned on and off, you can enable passive scanning mode. While in passive scanning mode, your application's event loop will receive scan result events when appropriate. See Listing 16.10 for an example of how to enable passive scanning.

Listing 16.10  Enabling passive scanning


WifiPassiveScanType scan; 
status_t err; 
 
memset(&scan, 0, sizeof(WifiPassiveScanType)); 
 
scan.enableScanning = true; 
scan.channelMask = WifiChannel_All; 
scan.rateMask = WifiRate_All; 
scan.interval = 1000; 
 
IOSIoctl(wifiFD, WIOCPASSIVESCAN, (int32_t) &scan, &err); 

The example above enables scanning for access points or ad-hoc networks operating on any channel and at any transmission rate. Scan results will be delivered to the application every 1,000 milliseconds.

To disable passive scanning, issue the WIOCPASSIVESCAN command again, with the enableScanning field set to false.

Obtaining Scan Results ^TOP^

Normally, your application receives scan results as a wifiScanResults event in its event loop. The event's WifiEventType structure describes the detected access point in detail. Each time an access point or ad-hoc network is found, a wifiScanResults event is delivered.

You can also manually fetch the scan results from the WiFi adapter by using the WIOCGETSCANRESULTS command. This command can be used in a loop to fetch all the scan results available, as seen in Listing 16.11.

Listing 16.11  Using WIOCGETSCANRESULTS


uint16_t index = 0; 
uint16_t last = 0; 
WifiGetScanResultsType scan; 
status_t err;  
 
do { 
	memset(&scan, 0, sizeof(WifiGetScanResultsType)); 
	scan.last = last; 
	scan.index = index; 
 
	IOSIoctl(m_fd, WIOCGETSCANRESULTS, (int32_t)&scan, &err); 
 
	if (err == P_OK) { 
		/* results received successfully in scan */ 
	} 
	else { 
		/* error receiving scan results */ 
	} 
	 
	last = scan.last; 
	index = scan.index; 
 
	index++; 
} while (index <= last); 

Configuring Encryption ^TOP^

WiFi supports the concept of encryption to protect data security. There are two security modes currently supported by Palm OS: open system (unencrypted) and Wired Equivalent Privacy (WEP).

To use WEP encryption, an encryption key needs to be configured prior to connecting to the network. There are three steps required to accomplish this. First, it's necessary to store the key in the adapter. A WiFi adapter can store up to four encryption keys, which can then be selected among depending on which network is being accessed.

Listing 16.12  Setting an encryption key


WifiSetWEPKeyType arg; 
status_t err; 
 
arg.key = 0;                /* key number to set */ 
 
memset(arg.data, 0, 16); 
arg.data_len = Ascii2Binary(arg.data, keyString, 16); 
 
IOSIoctl(wifiFD, WIOCSETKEY, (int32_t) &arg, &err); 

The code in Listing 16.12 sets key 0 to the string specified by keyString. See Listing 16.17 for the code for the Ascii2Binary() function.

Once the key has been stored on the adapter, it must be selected using the WIOCSETDEFAULTKEY command. See Listing 16.13.

Listing 16.13  Selecting the default key


status_t err; 
 
IOSIoctl(wifiFD, WIOCSETDEFAULTKEY, (int32_t) 0, &err); 

Finally, once the key has been selected, it's possible to put the interface into WEP mode by using the WIOCSETSECMODE command, as seen in Listing 16.14.

Listing 16.14  Enabling encryption


status_t err; 
uint32_t mode = WifiSecWEP; 
 
IOSIoctl(wifiFD, WIOCSETSECMODE, (int32_t) &mode, &err); 

To disable encryption, simply set the mode to WifiSecOpen.

Connecting To a Network ^TOP^

Once you have found an access point or ad-hoc network to which you wish to connect, you can connect to that network using either the WIOCCONNECT or the WIOCJOIN ioctl.

If you have the SSID of the network or ad-hoc network, you use the WIOCCONNECT command, as shown in Listing 16.15.

Listing 16.15  Connecting to a wireless network using an SSID


WifiConnectType arg; 
status_t err; 
 
strncpy(arg.ssid, theSSID, 32); 
arg.timeout = 3000; 
arg.blockTillCompletion = false; 
IOSIoctl(wifiFD, WIOCCONNECT, (int32_t) &arg, &err); 

In this example, we choose to try for three seconds (3,000 milliseconds) before timing out. In addition, since the blockTillCompletion flag is set to false, the call will return at once. We must then check the status of the connection periodically to detect when the connection is actually opened (or if the connection fails to open).

Your event loop (using either a Pollbox or IOSPoll()) will receive notifications as the status of the connection changes: wifiConnectAccessPoint or wifiConnectAdHoc when the connection is established, wifiConnecting while connection is being attempted, wifiOutOfRange if the access point is out of range but was opened anyway under the assumption that it will be eventually, wifiMediaUnavailable if the 802.11 hardware is missing, or wifiConnectFailed if the connection could not be established.

If you have the BSSID (MAC address) and channel number of a network to which you wish to connect, you can use the WIOCJOIN command instead, as shown in Listing 16.16.

Listing 16.16  Connecting to a wireless network using a BSSID and channel number


WifiJoinType arg; 
status_t err; 
 
Ascii2Binary(arg.bssid, "FF:FF:FF:FF:FF", 6); 
arg.channel = theChannel; 
IOSIoctl(wifiFD, WIOCJOIN, (int32_t) &arg, &err); 

This code uses a function called Ascii2Binary() to convert the MAC ID string into the proper format. Ascii2Binary() is shown in Listing 16.17.

Listing 16.17  Converting a hex string into packed binary format


int Ascii2Binary(uint8_t * buf, const char* p, size_t length)  
{ 
	uint8_t nibble; 
	size_t i = 0; 
	static char map[22] = {'0', '1', '2', '3', '4', '5', '6', 
'7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 
'd', 'e', 'f'};  
 
	while (*p != NULL && i < length) { 
	 
		// Skip over MAC octet separators 
		if (*p == ':') { 
			p++; 
			continue;	 
		} 
		nibble = 0; 
		for(int j = 0; j < 22; j++) { 
			if (p[0] == map[j]) { 
				 
				if (j >= 16) 
					nibble = j - 6; 
				else 
					nibble = j; 
				break; 
			} 
		} 
		 
		buf[i] |= nibble << 4; 
		p++; 
		 
		if (*p == NULL) 
			break; 
		 
		nibble = 0; 
		for(int j = 0; j < 22; j++) { 
			if (p[0] == map[j]) { 
				if (j >= 16) 
					nibble = j - 6; 
				else 
					nibble = j; 
				break; 
			} 
		} 
		 
		buf[i] |= nibble; 
		i++; 
		p++; 
	} 
 
	return i; 
} 

Once a connection has been established, the wireless network can be used just like any other network connection, using the Sockets API or IOS STDIO calls.

Managing a Wireless Connection ^TOP^

Once the connection is established, your application's event loop will receive events on the WiFi management file descriptor, informing you of changes in the status of the connection, as well as results of specific requests you issue. Your event loop needs to either poll the file descriptor, or use a Pollbox. These concepts are covered in "Polling STREAMS File Descriptors".

WiFi events use the WifiEventType structure to return data to your event handler. The possible events are listed in "Event Type Constants".

Disconnecting From a Network ^TOP^

To disconnect from a WiFi network, use the WIOCDISCONNECT command. See Listing 16.18.

Listing 16.18  Disconnecting from a WiFi network


status_t err; 
IOSIoctl(wifiFD, WIOCDISCONNECT, NULL, &err); 

Creating an Ad-hoc Network ^TOP^

Palm OS devices can create an ad-hoc network using the WIOCCREATEIBSS ioctl.

Listing 16.19  Creating an ad-hoc network


WifiCreateIBSSType ibss; 
status_t err; 
 
memset(&ibss, 0, sizeof(WifiCreateIBSSType)); 
strncpy(ibss.ssid, "MyAdhocNet", 32); 
ibss.channel = 8; 
 
IOSIoctl(wifiFD, WIOCCREATEIBSS, (int32_t) &ibss, &err); 

The example in Listing 16.19 creates a new ad-hoc network named "MyAdhocNet" operating on channel 8. If this is successful, other WiFi-enabled devices can then connect to the new ad-hoc network just like any other network.