Quantcast
Channel: Moving Forward » Android
Viewing all articles
Browse latest Browse all 2

Android WiFi tether Infrastructure Mode

$
0
0

With the addition of a little bit of elbow grease infrastructure mode on the HTC EVO is officially working. Over the coming days I hope to integrate it with android-wifi-tether and release the first and only application for any Android platform to support infrastructure mode tethering that doesn’t cost $30 a month. This application serves as literally a step-in replacement for the Sprint Hotspot application with the complete functionality set, minus the cost. Support for WEP and WPA comes standard out of the box, as well as open functionality. Unlike the Sprint application this method will not impose an artificial limit on the number of users to connect to your hotspot. 

How does it work?

The Broadcom drivers expose some additional functionality that is related to the wireless access point mode of the device. Using a system call that has absolutely no documentation and the driver from the bravo kernel I was able to build up a call in user-space C that emulates the structures expected by the hidden Android system call. You can see the Gist in its full glory here: ultra_bcm_config.c.

What I did was grab the latest iwconfig file from the tool’s repo, and rewrote it to send the correct ioctl to the driver. To start we define the struct the broadcom driver specifies in the driver source:

#define SSID_LEN	33
#define SEC_LEN		16
#define KEY_LEN		65
#define PROFILE_OFFSET	32

 struct ap_profile {
	char	ssid[SSID_LEN];
	char	sec[SEC_LEN];
	char	key[KEY_LEN];
	unsigned int	channel; /* 0 for auto */
	unsigned int	preamble;
	unsigned int	max_scb;	/*maxmium number of station */
};

It’s rather interesting, the way the Linux kernel handles wireless interfaces. In wireless.h you’ll find a struct called iwreq, and inside this struct you’ll find a terrible abuse of void pointers. Almost all of the wireless ioctl requests are passed using a structure called iwreq, which contains a union of a couple dozen structs that support various wireless configuration modes. What we do is make use of the data union member of the union, in which we pass a pointer to an allocated space of memory. From ultra_bcm_config.c:

	/* The wrq pointer struct is a mechanism to pass data from user-land to kernel-space memory.
	*  It has a allocatable field where we can stuff a struct of an arbitary size into it for
	*  passing custom code to the driver
	*/
  	struct iwreq		wrq;
  	unsigned int		k;		/* Must be unsigned */

  	/* Arguments to be passed:
  	1 - AP Name
  	2 - Encryption Type
  	3 - Encryption Key (unencrypted)
  	4 - Channel Number (0 is automatically scan) */

  	// Some length error checking. Lengths are defined in iwlib.h as part of the ap_profile struct
  	if(strlen(args[1]) > SSID_LEN)
	{
		errmax = IW_ESSID_MAX_SIZE;
		return(IWERR_ARG_SIZE);
	}

	if(strlen(args[3]) > KEY_LEN)
	{
		errmax = IW_ESSID_MAX_SIZE;
		return(IWERR_ARG_SIZE);
	}

	double		freq;
	char *		unit;
	freq = strtod(args[4], &unit);

  	/* This is the original functionality of set_mode in iwconfig.
  	*  It is not strictly nessessary anymore but will
  	*  make it look like the interface
  	*  is an access point to the kernel and iwconfig utilities,
  	*  instead of just making it
  	*  an access point and not showing anything.
  	*/
  	wrq.u.mode = 3;
	if(iw_set_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
		return(IWERR_SET_EXT);

	/* There are two different versions of the bcm driver on android phones. For some
	   it requires us to build an ASCII string in memory and then send that string to the driver
	   using io_ctl commands. The other version requires us to use a struct and send a more compact
	   binary representation of the data to the driver. I believe google will be looking to use the first
	   method because it's dead simple. We switch on arg[0] to determine
	*/
  	if(!strcmp(args[0], "softap_htc"))
  	{
		/* STANDARD STRUCT BUILDING MODE */
		if(strlen(args[2]) > SEC_LEN)
		{
		errmax = IW_ESSID_MAX_SIZE;
		return(IWERR_ARG_SIZE);
		}

		/* Data is a union member of what can be stored within the wrq pointer. In this case we set it to the maximum string
		   length and manually allocate memory for it.
		*/
		wrq.u.data.length = 162;
		wrq.u.data.pointer = malloc(162);

		/* Now that we have 162 bytes of free memory allocation is important. The way
		   the bcm driver hands it is it does a strcom on the first 31 characters and stores
		   the command string within this block of memory. We will now write the required
		   piece into memory
		*/
		strcpy(wrq.u.data.pointer, "AP_PROFILE_SET");

		/* ap_profile is defined in iwlib by me.
		* we toss it 32 bytes deep into the wrq pointer, because
		*  the bcm driver expects it there.
		*/

		/* Create a ap_profile pointer and assign it to a memory location 32 bytes deep within the wrq data struct */
		struct ap_profile * ap = (struct ap_profile *)(wrq.u.data.pointer + 32);

From there we’ve created a pointer to the ap_profile appropriate for setting the various wireless parameters required for ap-mode to be enabled:

		/* Setup our payload for delivery */
		strcpy(ap->ssid,args[1]);
		strcpy(ap->sec ,args[2]);
		strcpy(ap->key , args[3]);

		/* 0 means auto config on the channel. I recommend using that one.*/
		ap->channel = (int) freq;
		ap->max_scb = 2;

		/* Pass the wrq structure deep into kernel memory for copying and processing. */
		if(iw_set_ext(skfd, ifname, SIOCSIWPRIV, &wrq) < 0)
			return(IWERR_SET_EXT);

Really that’s all there is to it, throw some timing into the mix and just the right amount of luck and you have yourself a working wireless driver. When we run this utility, you’ll see in the kernel log:

<4>[19452.040679] penguin, get AP_PROFILE_SET
<4>[19452.041076] wl_iw: set ap profile:
<4>[19452.041442]       ssid = AndrewsAndroidAP
<4>[19452.042144]       security = wpa-psk
<4>[19452.042510]       key = 1234567890
<4>[19452.042877]       channel = 0
<4>[19452.043243]       max scb = 2
<4>[19454.110931] Set auto channel = 1
<4>[19454.112182] wl_iw_setap: do passhash...
<4>[19454.210723] [00]: aa2f2f2c
<4>[19454.210845] [01]: f4081ab1
<4>[19454.211059] [02]: ccc1d613
<4>[19454.211181] [03]: 887fd525
<4>[19454.211273] [04]: b51d0c01
<4>[19454.211395] [05]: 781b89b1
<4>[19454.211608] [06]: b5de9c57
<4>[19454.211730] [07]: 2f8812e2
<4>[19454.211853] wl_iw_setap: passphase = 2c2f2faab11a08f413d6c1cc25d57f88010c1db5b1891b78579cdeb5e212882f
<4>[19454.222106] ap setup done
<4>[19454.224487] send AP_UP

Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images