Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Ultra_bcm_config - A utility that does one thing, pretty well.
- *
- * Andrew Robinson <andrew.robinson@gmail.com>
- *
- * Based off of the framework provided by iwconfig.c - the standard
- * linux wireless driver configuration tool. Modified to pass a special
- * structure to the custom Broadcom BCM4329 chipset driver running in the
- * kernel to enable AccessPoint mode, broadcasting of the SSID, and WEP/WPA
- * encryption.
- *
- * Also references a publically available implementation of the SHA1
- * hashing algorthim for WPA key generation. The BCM driver requires a fully
- * hashed key to enable WPA encryption. Function has been modified to return
- * proper ASCII characters for sending in the ASCII_CMD structure.
- *
- * TODO:
- * - Advanced error checking - We look for arg counts right now... more could
- * be done.
- * - TX Power Config - Easy call to bcm4329 driver, uses same offset as current.
- */
- #include "iwlib.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include "wpa_supplicant/includes.h"
- #include "wpa_supplicant/common.h"
- #include "wpa_supplicant/sha1.h"
- #define WSEC_MAX_PSK_LEN 64
- /**************************** CONSTANTS ****************************/
- /*
- * Error codes defined for setting args
- */
- #define IWERR_ARG_NUM -2
- #define IWERR_ARG_TYPE -3
- #define IWERR_ARG_SIZE -4
- #define IWERR_ARG_CONFLICT -5
- #define IWERR_SET_EXT -6
- #define IWERR_GET_EXT -7
- /**************************** VARIABLES ****************************/
- /*
- * Deal with errors in set_info() efficiently...
- */
- static int errarg;
- static int errmax;
- static void
- build_ap_string(char * output,
- char * ssid,
- char * sec,
- char * key,
- char * channel,
- char secondString )
- {
- if(secondString)
- {
- strcpy(output, "ASCII_CMD=AP_BSS_START,SSID=");
- output += 28;
- }
- else
- {
- strcpy(output, "ASCII_CMD=AP_CFG,SSID=");
- output += 22;
- }
- strcpy(output, ssid);
- output += strlen(ssid);
- strcpy(output, ",SEC=");
- output += 5;
- strcpy(output, sec);
- output += strlen(sec);
- strcpy(output, ",KEY=");
- output += 5;
- unsigned char psk[32];
- pbkdf2_sha1(key, ssid, strlen(ssid), 4096, psk, 32);
- int i;
- char* ptr;
- char key_str_buf[WSEC_MAX_PSK_LEN+1];
- ptr = key_str_buf;
- for (i=0; i<(WSEC_MAX_PSK_LEN/8); i++){
- sprintf(ptr, "%02x%02x%02x%02x", (uint)psk[i*4], (uint)psk[i*4+1], (uint)psk[i*4+2], (uint)psk[i*4+3]);
- ptr += 8;
- }
- strcpy(output, key_str_buf);
- output += strlen(key_str_buf);
- strcpy(output, ",CHANNEL=");
- output += 9;
- strcpy(output, channel);
- output += strlen(channel);
- strcpy(output, ",PREAMBLE=0,MAX_SCB=8,END");
- output += 25;
- *output = 0;
- }
- /*
- * set_mode_info
- * This function is completely original code
- */
- static int
- set_mode_info(int skfd, /* Socket name */
- char * ifname, /* Dev name */
- char * args[], /* Command line args */
- int count) /* Args count */
- {
- /* 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);
- /* 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);
- }
- else
- {
- /* ASCII STRING BUILD */
- /* maxmimum length of this string will be <300 bytes */
- wrq.u.data.length = 300;
- wrq.u.data.pointer = malloc(300);
- /* Test commands + formatting template:
- //char *cmd = "ASCII_CMD= ASCII_CMD=AP_CFG,SSID=AndroidTether,SEC=open,KEY=28e4636bb4e166ab752b859f7b2bc7b26db3d817b5ef79965f48fd76be8d2a19,CHANNEL=6,PREAMBLE=0,MAX_SCB=8,END";
- //char *cmd2 = "ASCII_CMD= ASCII_CMD=AP_BSS_START,SSID=AndroidTether,SEC=open,KEY=28e4636bb4e166ab752b859f7b2bc7b26db3d817b5ef79965f48fd76be8d2a19,CHANNEL=6,PREAMBLE=0,MAX_SCB=8,END";
- */
- /* Added 32 spaces and command text for command */
- char cmd[267] = "ASCII_CMD= ";
- /* Call string builder function */
- build_ap_string(cmd+32,args[1],args[2],args[3],args[4],0);
- fprintf(stderr, cmd);
- strcpy(wrq.u.data.pointer, cmd);
- if(iw_set_ext(skfd, ifname, SIOCSIWPRIV, &wrq) < 0)
- return(IWERR_SET_EXT);
- build_ap_string(cmd+32,args[1],args[2],args[3],args[4],1);
- fprintf(stderr, cmd);
- strcpy(wrq.u.data.pointer, cmd);
- if(iw_set_ext(skfd, ifname, SIOCSIWPRIV, &wrq) < 0)
- return(IWERR_SET_EXT);
- }
- /* Free allocated memory. */
- free(wrq.u.data.pointer);
- return(1);
- }
- /*
- * set_info
- * In the original iwconfig file this function acted as a branching conditional function that would ferry the input parameters to the
- neccesary functions and deal with return values. Even though we only have one command I have left it in tact for future expansion.
- */
- static int
- set_info(int skfd, /* The socket */
- char * args[], /* Command line args */
- int count, /* Args count */
- char * ifname) /* Dev name */
- {
- int ret;
- /* Call the command */
- ret = set_mode_info(skfd, ifname, args, count);
- /* Deal with various errors, taken from iwconfig.c */
- if(ret < 0)
- {
- switch(ret)
- {
- case IWERR_ARG_NUM:
- fprintf(stderr, " too few arguments.\n");
- break;
- case IWERR_ARG_TYPE:
- if(errarg < 0)
- errarg = 0;
- if(errarg >= count)
- errarg = count - 1;
- fprintf(stderr, " invalid argument \"%s\".\n", args[errarg]);
- break;
- case IWERR_ARG_SIZE:
- fprintf(stderr, " argument too big (max %d)\n", errmax);
- break;
- case IWERR_ARG_CONFLICT:
- if(errarg < 0)
- errarg = 0;
- if(errarg >= count)
- errarg = count - 1;
- fprintf(stderr, " conflicting argument \"%s\".\n", args[errarg]);
- break;
- case IWERR_SET_EXT:
- fprintf(stderr, " SET failed on device %-1.16s ; %s.\n",
- ifname, strerror(errno));
- break;
- case IWERR_GET_EXT:
- fprintf(stderr, " GET failed on device %-1.16s ; %s.\n",
- ifname, strerror(errno));
- break;
- }
- return(ret);
- }
- /* Done, all done */
- return(0);
- }
- /*
- * MAIN Body. Returns 0 on success, -1 on failure to the system
- */
- int
- main(int argc,
- char ** argv)
- {
- /* Raw socket descriptor, skfd is -1 on failure to open */
- int skfd;
- int goterr = 0;
- /* Create a channel to the NET kernel using iw system call, defined in iwlib.h. */
- /* All io_ctl will be carried out referencing this socket descripter*/
- if((skfd = iw_sockets_open()) < 0)
- {
- perror("socket");
- exit(-1);
- }
- /* Ensure the proper number of arguments has been passed */
- if(argc == 7)
- /* The other args on the line specify options to be set... */
- goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
- else
- {
- goterr = -1;
- fprintf(stderr, "Wrong number of args.");
- }
- /* Close the NET socket. */
- iw_sockets_close(skfd);
- return(goterr);
- }
Add Comment
Please, Sign In to add comment