diff --git a/libwlocate/src/Makefile b/libwlocate/src/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..0670ef31935c1ce711d5dbcc3a57568b7bb34b3d --- /dev/null +++ b/libwlocate/src/Makefile @@ -0,0 +1,23 @@ +CCOMPILER=gcc -Wall -fPIC -shared -Wno-unused -O2 -g0 -DNDEBUG -D_REENTRANT -DENV_LINUX -I. -I.. + +SYSLIBRARIES= -lm + +LIBS = $(SYSLIBRARIES) -liw + +EXECUTABLE=libwlocate.so + +LINK=$(CC) -shared -Wl,--no-as-needed + +OBJECTS = connect.o wlan.o libwlocate.o iwlist.o + +default: $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(LINK) $(SYSLDFLAGS) $(LDFLAGS) -o $(EXECUTABLE) $(OBJECTS) $(LIBS) + +%.o: %.c + $(CCOMPILER) -c $< -o $@ + +clean: + rm -f $(OBJECTS) $(EXECUTABLE) + diff --git a/libwlocate/src/connect.c b/libwlocate/src/connect.c new file mode 100755 index 0000000000000000000000000000000000000000..cb9fffa6c4a49c02441737e96ed46f3d3780a77e --- /dev/null +++ b/libwlocate/src/connect.c @@ -0,0 +1,261 @@ +/** + * libwlocate - WLAN-based location service + * Copyright (C) 2010 Oxygenic/VWP virtual_worlds(at)gmx.de + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <unistd.h> + + +#ifdef ENV_WINDOWS + #include <winsock2.h> + #define MSG_NOSIGNAL 0 +#else + #include <sys/socket.h> + #include <sys/types.h> + #include <sys/ioctl.h> + #include <netinet/in.h> + #include <arpa/inet.h> + #include <unistd.h> + #include <netdb.h> +#endif + +#ifndef ENV_WINDOWSCE + #include <fcntl.h> + #include <errno.h> +#else + #ifndef EAGIAN + #define EAGAIN 11 // really the correct value? there is no errno.h for WinCE + #endif +#endif + + +#ifdef ENV_QNX + #define MSG_NOSIGNAL 0 +#endif + + +static int util_thread_sleep(int msecs) +{ +#ifdef ENV_WINDOWS + Sleep(msecs); +#else + usleep(msecs*1000); +#endif + return msecs; +} + + + +/** +Receive data from a socket connection +@param[in] sock the identifier of the opened socket connection +@param[in] data the memory area where the received data have to be stored into +@param[in] len the maximum length of data that have to be read +@param[in] termStr an optional termination string; when this value is not NULL and the character + defined here is received the function returns +@param[in] timeout when this time is exceeded the function returns also if not all data could + be read; this parameter is valid only in case the socket is non-blocking +*/ +int tcp_recv(int sock,char *data, int len,const char *termStr,long timeout) +{ + long /*size_t*/ rc; + long ctr=0,readLen=0; + #ifdef ENV_WINDOWS + long err; + #endif + + // data from source client side + while (readLen<len) + { + rc = recv(sock,data+readLen,1/*len-readLen*/,MSG_NOSIGNAL); + if (rc>0) + { + readLen+=rc; + if (termStr) + { + if (readLen+1<len) data[readLen+1]=0; + if (strstr(data,termStr)) return readLen; + } + if (readLen>=len) return readLen; + } + else if (rc==0) return readLen; + else + { +#ifdef ENV_WINDOWS + err=GetLastError(); + if ((err!=EAGAIN) && (err!=WSAEWOULDBLOCK)) +#else + if ((errno!=EAGAIN) && (errno!=EINPROGRESS) && (errno!=0)) +#endif + return readLen; + ctr+=10; + util_thread_sleep(10); + } + if (ctr>timeout) break; + } + return readLen; +} + + + +/** +Send data to a socket connection +@param[in] sock the identifier of the opened socket connection +@param[in] msg the data that have to be send +@param[in] len the length of the data +@param[in] msecs when this time is exceeded the function returns also if not all data could + be sent; this parameter is valid only in case the socket is non-blocking +*/ +int tcp_send(int sock, const char *msg,int len,int msecs) +{ + int rlen=0; + int ctr=0,val; +#ifdef ENV_WINDOWS + int errno; +#else + + errno=0; +#endif + while ((rlen<len) && (ctr<msecs)) + { +#ifdef ENV_LINUX + val=send(sock,msg+rlen,len-rlen,MSG_NOSIGNAL); +#else + val=send(sock,msg+rlen,len-rlen,0); +#endif + if (val>=0) rlen+=val; + else + { +#ifndef ENV_WINDOWS + if (errno==EAGAIN) ctr-=2; // in case of eagain we expect a longer send-timeout +#else + errno=WSAGetLastError(); + if (errno==WSAEWOULDBLOCK) ctr-=2; // in case of eagain we expect a longer send-timeout +#endif + else if (errno!=0) + { + rlen=-1; + break; + } +#ifndef ENV_WINDOWS + errno=0; +#endif + } + if (rlen<len) + { + util_thread_sleep(2); + ctr+=2; + } + if ((rlen==0) && (ctr>msecs/2)) break; + } + return rlen; +} + + + +/** +Closes an opened socket connection +@param[in] sock the socket that has to be closed +*/ +void tcp_closesocket (int sock) +{ +#ifdef ENV_WINDOWS + shutdown(sock,SD_SEND); + shutdown(sock,SD_RECEIVE); + closesocket(sock); +#else + shutdown(sock,SHUT_WR); + shutdown(sock,SHUT_RD); + if (close (sock)<0) perror("close failed"); +#endif +} + + + +/** +Tries to establish a client connection to a (remote) server socket +@param[in] address address of the remote server in style a.b.c.d or www.domain.tld +@param[in] port number to connect with +@return the socket identifier of the established connection or a value <=0 in case of an + error +*/ +int tcp_connect_to(const char *address) +{ + struct addrinfo hints, *servinfo, *p; + int s; + int r; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 + hints.ai_socktype = SOCK_STREAM; // Set TCP protocol + + if ((r = getaddrinfo(address, "http", &hints, &servinfo)) != 0) + { + perror("getaddrinfo: wrong URL %s\n" + strlen(gai_strerror(r))); + return -1; + } + + // connect to the first addr that we can. + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((s = socket(p->ai_family, p->ai_socktype,p->ai_protocol)) == -1) { + perror("socket"); + continue; + } + + if (connect(s, p->ai_addr, p->ai_addrlen) == -1) { + close(s); + perror("connect"); + continue; + } + + break; // if we get here, connection must have established + } + + if (p == NULL) { + // if there above for does not got an connection + perror("failed to connect\n"); + return -1; + } + + freeaddrinfo(servinfo); // all done with this structure + return s; +} + +/** +Configures the blocking mode of an opened socket +@param[in] sock identifier of the socket to configure +@param[in] block 1 to set the socket to blocking mode, 0 to set it to non-blocking +*/ +void tcp_set_blocking(int sock,char block) +{ + int flags; + +#ifndef ENV_WINDOWS + flags=fcntl(sock,F_GETFL, 0); + if (block) flags&=~O_NONBLOCK; + else flags|=O_NONBLOCK; + fcntl(sock,F_SETFL, flags); +#else + if (block) flags=0; + else flags=13; + ioctlsocket(sock,FIONBIO,(unsigned long*)&flags); +#endif +} + diff --git a/libwlocate/src/connect.h b/libwlocate/src/connect.h new file mode 100755 index 0000000000000000000000000000000000000000..3361ba06da0ce73c2ca16da239466fa8c1e5fcc2 --- /dev/null +++ b/libwlocate/src/connect.h @@ -0,0 +1,28 @@ +/** + * libwlocate - WLAN-based location service + * Copyright (C) 2010 Oxygenic/VWP virtual_worlds(at)gmx.de + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef CONNECT_H +#define CONNECT_H + +extern int tcp_recv(int sock,char *data, int len,const char *termStr,long timeout); +extern int tcp_send(int sock, const char *msg,int len,int msecs); +extern void tcp_closesocket (int sock); +extern int tcp_connect_to(const char *address); +extern void tcp_set_blocking(int sock,char block); + +#endif diff --git a/libwlocate/src/iwlist.c b/libwlocate/src/iwlist.c new file mode 100755 index 0000000000000000000000000000000000000000..5d1b1308ef11e2146339b519cc2e7c61bc2fcd41 --- /dev/null +++ b/libwlocate/src/iwlist.c @@ -0,0 +1,481 @@ +/* + * Wireless Tools + * + * Jean II - HPLB '99 - HPL 99->07 + * + * This tool can access various piece of information on the card + * not part of iwconfig... + * You need to link this code against "iwlist.c" and "-lm". + * + * This file is released under the GPL license. + * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com> + */ + +#include "iwlib.h" /* Header */ +#include "libwlocate.h" +#include <sys/time.h> + +static struct wloc_req *g_request; +static struct iwscan_state state; + +/****************************** TYPES ******************************/ + +/* + * Scan state and meta-information, used to decode events... + */ +typedef struct iwscan_state +{ + /* State */ + int ap_num; /* Access Point number 1->N */ + int val_index; /* Value in table 0->(N-1) */ +} iwscan_state; + +/* + * Bit to name mapping + */ +typedef struct iwmask_name +{ + unsigned int mask; /* bit mask for the value */ + const char * name; /* human readable name for the value */ +} iwmask_name; + +/* + * Types of authentication parameters + */ +typedef struct iw_auth_descr +{ + int value; /* Type of auth value */ + const char * label; /* User readable version */ + const struct iwmask_name * names; /* Names for this value */ + const int num_names; /* Number of names */ +} iw_auth_descr; + +/**************************** CONSTANTS ****************************/ + +#define IW_SCAN_HACK 0x8000 + +#define IW_EXTKEY_SIZE (sizeof(struct iw_encode_ext) + IW_ENCODING_TOKEN_MAX) + + + +/***************************** SCANNING *****************************/ +/* + * This one behave quite differently from the others + * + * Note that we don't use the scanning capability of iwlib (functions + * iw_process_scan() and iw_scan()). The main reason is that + * iw_process_scan() return only a subset of the scan data to the caller, + * for example custom elements and bitrates are ommited. Here, we + * do the complete job... + */ + +/*------------------------------------------------------------------*/ +/* + * Print one element from the scanning results + */ +static inline void +print_scanning_token(struct stream_descr * stream, /* Stream of events */ + struct iw_event * event, /* Extracted token */ + struct iwscan_state * state, + struct iw_range * iw_range, /* Range info */ + int has_range) +{ + int i; + char buffer[128]; + + if (state->ap_num>=WLOC_MAX_NETWORKS) + return; + /* Now, let's decode the event */ + switch(event->cmd) + { + case SIOCGIWAP: +// printf(" Cell %02d - Address: %s\n", state->ap_num, iw_saether_ntop(&event->u.ap_addr, buffer)); + state->ap_num++; + for (i=0; i<6; i++) + g_request->bssids[state->ap_num-1][i]=(event->u.ap_addr.sa_data[i] & 0xFF); + break; + case IWEVQUAL: + { +// if (iw_range->max_qual.qual==0) g_request->signal[state->ap_num-1]=abs(event->u.qual.qual); +// else g_request->signal[state->ap_num-1]=100.0*event->u.qual.qual/iw_range->max_qual.qual; +// printf(" Signal: %d\n",g_request->signal[state->ap_num-1]); + break; + } + default: + break; + } /* switch(event->cmd) */ +} + +/*------------------------------------------------------------------*/ +/* + * Perform a scanning on one device + */ +static int +print_scanning_info(int skfd, + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ +{ + struct iwreq wrq; + struct iw_scan_req scanopt; /* Options for 'set' */ + int scanflags = 0; /* Flags for scan */ + unsigned char * buffer = NULL; /* Results */ + int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */ + struct iw_range range; + int has_range; + struct timeval tv; /* Select timeout */ + int timeout = 15000000; /* 15s */ + + /* Avoid "Unused parameter" warning */ + args = args; count = count; + + /* Debugging stuff */ +/* if((IW_EV_LCP_PK2_LEN != IW_EV_LCP_PK_LEN) || (IW_EV_POINT_PK2_LEN != IW_EV_POINT_PK_LEN)) + { + fprintf(stderr, "*** Please report to jt@hpl.hp.com your platform details\n"); + fprintf(stderr, "*** and the following line :\n"); + fprintf(stderr, "*** IW_EV_LCP_PK2_LEN = %zu ; IW_EV_POINT_PK2_LEN = %zu\n\n", + IW_EV_LCP_PK2_LEN, IW_EV_POINT_PK2_LEN); + }*/ + + /* Get range stuff */ + has_range = (iw_get_range_info(skfd, ifname, &range) >= 0); + + /* Check if the interface could support scanning. */ + if (range.we_version_compiled==0) range.we_version_compiled=29; + if((!has_range) || (range.we_version_compiled < 14)) + { + fprintf(stderr, "%-8.16s Interface doesn't support scanning.\n\n", + ifname); + return(-1); + } + + /* Init timeout value -> 250ms between set and first get */ + tv.tv_sec = 0; + tv.tv_usec = 250000; + + /* Clean up set args */ + memset(&scanopt, 0, sizeof(scanopt)); + + /* Parse command line arguments and extract options. + * Note : when we have enough options, we should use the parser + * from iwconfig... */ +/* while(count > 0) + { + + count--; + + if(!strncmp(args[0], "essid", 5)) + { + if(count < 1) + { + fprintf(stderr, "Too few arguments for scanning option [%s]\n", + args[0]); + return(-1); + } + args++; + count--; + + scanopt.essid_len = strlen(args[0]); + memcpy(scanopt.essid, args[0], scanopt.essid_len); + if(scanopt.bssid.sa_family == 0) + { + scanopt.bssid.sa_family = ARPHRD_ETHER; + memset(scanopt.bssid.sa_data, 0xff, ETH_ALEN); + } + scanflags |= IW_SCAN_THIS_ESSID; + } + else + if(!strncmp(args[0], "last", 4)) + { + scanflags |= IW_SCAN_HACK; + } + else + { + fprintf(stderr, "Invalid scanning option [%s]\n", args[0]); + return(-1); + } + + args++; + }*/ + + /* Check if we have scan options */ +/* if(scanflags) + { + wrq.u.data.pointer = (caddr_t) &scanopt; + wrq.u.data.length = sizeof(scanopt); + wrq.u.data.flags = scanflags; + } + else*/ + { + wrq.u.data.pointer = NULL; + wrq.u.data.flags = 0; + wrq.u.data.length = 0; + } + + /* If only 'last' was specified on command line, don't trigger a scan */ +/* if(scanflags == IW_SCAN_HACK) + { + tv.tv_usec = 0; + } + else*/ + { + /* Initiate Scanning */ + if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0) + { + if((errno != EPERM) || (scanflags != 0)) + { + fprintf(stderr, "%-8.16s Interface doesn't support scanning : %s\n\n", + ifname, strerror(errno)); + return(-1); + } + /* If we don't have the permission to initiate the scan, we may + * still have permission to read left-over results. + * But, don't wait !!! */ +#if 0 + /* Not cool, it display for non wireless interfaces... */ + fprintf(stderr, "%-8.16s (Could not trigger scanning, just reading left-over results)\n", ifname); +#endif + tv.tv_usec = 0; + } + } + timeout -= tv.tv_usec; + + /* Forever */ + while(1) + { + fd_set rfds; /* File descriptors for select */ + int last_fd; /* Last fd */ + int ret; + + /* Guess what ? We must re-generate rfds each time */ + FD_ZERO(&rfds); + last_fd = -1; + + /* In here, add the rtnetlink fd in the list */ + + /* Wait until something happens */ + ret = select(last_fd + 1, &rfds, NULL, NULL, &tv); + + /* Check if there was an error */ + if(ret < 0) + { + if(errno == EAGAIN || errno == EINTR) + continue; + fprintf(stderr, "Unhandled signal - exiting...\n"); + return(-1); + } + + /* Check if there was a timeout */ + if(ret == 0) + { + unsigned char * newbuf; + + realloc: + /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */ + newbuf = (unsigned char*)realloc(buffer, buflen); + if(newbuf == NULL) + { + if(buffer) + free(buffer); + fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__); + return(-1); + } + buffer = newbuf; + + /* Try to read the results */ + wrq.u.data.pointer = buffer; + wrq.u.data.flags = 0; + wrq.u.data.length = buflen; + if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0) + { + /* Check if buffer was too small (WE-17 only) */ + if((errno == E2BIG) && (range.we_version_compiled > 16)) + { + /* Some driver may return very large scan results, either + * because there are many cells, or because they have many + * large elements in cells (like IWEVCUSTOM). Most will + * only need the regular sized buffer. We now use a dynamic + * allocation of the buffer to satisfy everybody. Of course, + * as we don't know in advance the size of the array, we try + * various increasing sizes. Jean II */ + + /* Check if the driver gave us any hints. */ + if(wrq.u.data.length > buflen) + buflen = wrq.u.data.length; + else + buflen *= 2; + + /* Try again */ + goto realloc; + } + + /* Check if results not available yet */ + if(errno == EAGAIN) + { + /* Restart timer for only 100ms*/ + tv.tv_sec = 0; + tv.tv_usec = 100000; + timeout -= tv.tv_usec; + if(timeout > 0) + continue; /* Try again later */ + } + + /* Bad error */ + free(buffer); + fprintf(stderr, "%-8.16s Failed to read scan data : %s\n\n", + ifname, strerror(errno)); + return(-2); + } + else + /* We have the results, go to process them */ + break; + } + + /* In here, check if event and event type + * if scan event, read results. All errors bad & no reset timeout */ + } + + if(wrq.u.data.length) + { + struct iw_event iwe; + struct stream_descr stream; + int ret; + + state.ap_num = 0; + state.val_index = 0; +#ifdef DEBUG + /* Debugging code. In theory useless, because it's debugged ;-) */ + int i; + printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]); + for(i = 1; i < wrq.u.data.length; i++) + printf(":%02X", buffer[i]); + printf("]\n"); +#endif + printf("%-8.16s Scan completed :\n", ifname); + iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length); + do + { + /* Extract an event and print it */ + ret = iw_extract_event_stream(&stream, &iwe, + range.we_version_compiled); + if(ret > 0) + print_scanning_token(&stream, &iwe, &state, + &range, has_range); + } + while(ret > 0); + printf("\n"); + } + else + printf("%-8.16s No scan results\n\n", ifname); + + free(buffer); + return(0); +} + +/*********************** FREQUENCIES/CHANNELS ***********************/ + +/*------------------------------------------------------------------*/ +/* + * Power Management types of values + */ +static const unsigned int pm_type_flags[] = { + IW_POWER_PERIOD, + IW_POWER_TIMEOUT, + IW_POWER_SAVING, +}; +static const int pm_type_flags_size = (sizeof(pm_type_flags)/sizeof(pm_type_flags[0])); + + + +/************************* COMMON UTILITIES *************************/ +/* + * This section was initially written by Michael Tokarev <mjt@tls.msk.ru> + * but heavily modified by me ;-) + */ + +/*------------------------------------------------------------------*/ +/* + * Map command line arguments to the proper procedure... + */ +typedef struct iwlist_entry { + const char * cmd; /* Command line shorthand */ + iw_enum_handler fn; /* Subroutine */ + int max_count; + const char * argsname; /* Args as human readable string */ +} iwlist_cmd; + +static const struct iwlist_entry iwlist_cmds[] = { + { "scanning", print_scanning_info, -1, "[essid NNN] [last]" }, + { NULL, NULL, 0, 0 }, +}; + +/*------------------------------------------------------------------*/ +/* + * Find the most appropriate command matching the command line + */ +static inline const iwlist_cmd * +find_command(const char * cmd) +{ + const iwlist_cmd * found = NULL; + int ambig = 0; + unsigned int len = strlen(cmd); + int i; + + /* Go through all commands */ + for(i = 0; iwlist_cmds[i].cmd != NULL; ++i) + { + /* No match -> next one */ + if(strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0) + continue; + + /* Exact match -> perfect */ + if(len == strlen(iwlist_cmds[i].cmd)) + return &iwlist_cmds[i]; + + /* Partial match */ + if(found == NULL) + /* First time */ + found = &iwlist_cmds[i]; + else + /* Another time */ + if (iwlist_cmds[i].fn != found->fn) + ambig = 1; + } + + if(found == NULL) + { + fprintf(stderr, "iwlist: unknown command `%s' (check 'iwlist --help').\n", cmd); + return NULL; + } + + if(ambig) + { + fprintf(stderr, "iwlist: command `%s' is ambiguous (check 'iwlist --help').\n", cmd); + return NULL; + } + + return found; +} + + + +int iw_fill_structure(struct wloc_req *request) +{ + int skfd; + /* Create a channel to the NET kernel. */ + if((skfd = iw_sockets_open()) < 0) + { + perror("socket"); + return -1; + } + g_request=request; + + /* do the actual work */ + iw_enum_devices(skfd,print_scanning_info,NULL,-1); + + /* Close the socket. */ + iw_sockets_close(skfd); + + return state.ap_num; +} diff --git a/libwlocate/src/libwlocate.c b/libwlocate/src/libwlocate.c new file mode 100755 index 0000000000000000000000000000000000000000..0152948483ed4959bd95a979df8cc521d5c0f6a7 --- /dev/null +++ b/libwlocate/src/libwlocate.c @@ -0,0 +1,640 @@ +/** + * libwlocate - WLAN-based location service + * Copyright (C) 2010-2014 Oxygenic/VWP virtual_worlds(at)gmx.de + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <locale.h> +#ifndef ENV_WINDOWS + #include <arpa/inet.h> +#else + #define snprintf _snprintf +#endif + +#include "libwlocate.h" +#include "connect.h" +#include "wlan.h" +#include "assert.h" +#include "errno.h" + + +WLOC_EXT_API int get_position(const char *domain,const struct wloc_req *request,double *lat,double *lon,char *quality,short *ccode) +{ + int sock=0,ret,i; + char head[500+1]; + char data[500+1]; + char responseOK=0; + + setlocale(LC_ALL,"C"); + sock=tcp_connect_to(domain); + if (sock<=0) + { + printf("Connect error %d\n",errno); + return WLOC_SERVER_ERROR; + } + tcp_set_blocking(sock,0); // set to non-blocking, we do not want to wait endless for a dead connection + + data[0]=0; + for (i=0; i<WLOC_MAX_NETWORKS; i++) + { + if (request->bssids[i][0]+request->bssids[i][1]+request->bssids[i][2]+request->bssids[i][3]+request->bssids[i][4]+request->bssids[i][5]>0) + { + snprintf(data + strlen(data), 500 - strlen(data), + "%02X%02X%02X%02X%02X%02X\r\n", + request->bssids[i][0],request->bssids[i][1],request->bssids[i][2], + request->bssids[i][3],request->bssids[i][4],request->bssids[i][5]); + } + } + snprintf(head,500, + "POST /getpos.php HTTP/1.0\r\nHost: %s\r\nContent-type: application/x-www-form-urlencoded, *.*\r\nContent-length: %d\r\n\r\n", + domain,strlen(data)); + ret=tcp_send(sock,head,strlen(head),5000); + ret+=tcp_send(sock,data,strlen(data),5000); + if (ret<(int)(strlen(head)+strlen(data))) + { + tcp_closesocket(sock); + return WLOC_CONNECTION_ERROR; + } + + data[0]=0; + for (;;) + { + ret=tcp_recv(sock,head,500,NULL,100); + if (ret>0) + { + char *pos; + int dataFound=0; + + snprintf(data,500,"%s%s",data,head); + if (strstr(data,"\r\n")) + { + // one line received at least so check response code + if (!responseOK) + { + if (!strstr(data,"200 OK")) + { + printf("Error: %s\n",data); + tcp_closesocket(sock); + return WLOC_SERVER_ERROR; + } + responseOK=1; + } + if (strstr(data,"result=0")) + { + tcp_closesocket(sock); + return WLOC_LOCATION_ERROR; + } + pos=strstr(data,"quality="); + if (pos); + { + pos+=8; + *quality=atoi(pos); + dataFound|=0x0001; + } + pos=strstr(data,"lat="); + if (pos); + { + pos+=4; + *lat=atof(pos); + if (*lat!=0.0) dataFound|=0x0002; + } + pos=strstr(data,"lon="); + if (pos); + { + pos+=4; + *lon=atof(pos); + if (*lon!=0.0) dataFound|=0x0004; + } + if ((dataFound & 0x0007)==0x0007) break; // all required data received + } + } + } + + tcp_closesocket(sock); + + // this should never happen, the server should send quality values in range 0..99 only +// assert((*quality>=0) && (*quality<=99)); + if (*quality<0) *quality=0; + else if (*quality>99) *quality=99; + // end of this should never happen + + *ccode=-1; + return WLOC_OK; +} + + +/** please refer to libwlocate.h for a description of this function! */ +WLOC_EXT_API int wloc_get_location(double *lat,double *lon,char *quality,short *ccode) +{ + return wloc_get_location_from("openwlanmap.org",lat,lon,quality,ccode); +} + + +/** please refer to libwlocate.h for a description of this function! */ +WLOC_EXT_API int wloc_get_location_from(const char *domain,double *lat,double *lon,char *quality,short *ccode) +{ +#ifdef ENV_LINUX + int sock,i,j; +#endif + struct wloc_req request; + int ret=0; + + memset((char*)&request,0,sizeof(struct wloc_req)); +//#ifdef ENV_LINUX + // for Linux we have some special handling because only root has full access to the WLAN-hardware: + // there a wlocd-daemon may run with root privileges, so we try to connect to it and receive the + // BSSID data from there. Only in case this fails the way via iwtools is used + //sock=tcp_connect_to("localhost"); +/* if (sock>0) + { + ret=tcp_recv(sock,(char*)&request,sizeof(struct wloc_req),NULL,7500); + tcp_closesocket(sock); + if (ret==sizeof(struct wloc_req)) + { + ret=0; + for (i=0; i<WLOC_MAX_NETWORKS; i++) + { + if (request.bssids[i][0]+request.bssids[i][1]+request.bssids[i][2]+ + request.bssids[i][3]+request.bssids[i][4]+request.bssids[i][5]>0) ret++; + } + } + }*/ +/*#else + ret=0; +#endif + if (ret==0) + {*/ + if (wloc_get_wlan_data(&request)<2) + { + wloc_get_wlan_data(&request); // try two times in case the device was currently used or could not find all networks + // in case of no success request localisation without WLAN data + } +// } +// for (i=0; i<WLOC_MAX_NETWORKS; i++) +// printf("BSSID: %02X:%02X:%02X:%02X:%02X:%02X Signal: %d\n",request.bssids[i][0] & 0xFF,request.bssids[i][1] & 0xFF,request.bssids[i][2] & 0xFF, +// request.bssids[i][3] & 0xFF,request.bssids[i][4] & 0xFF,request.bssids[i][5] & 0xFF,request.signal[i]); + return get_position(domain,&request,lat,lon,quality,ccode); +} + + + +/** please refer to libwlocate.h for a description of this function! */ +WLOC_EXT_API int wloc_get_country_from_code(short ccode,char *country) +{ + switch (ccode) + { + case 1: + strncpy(country,"DE",2); + return WLOC_OK; + case 2: + strncpy(country,"AT",2); + return WLOC_OK; + case 3: + strncpy(country,"CH",2); + return WLOC_OK; + case 4: + strncpy(country,"NL",2); + return WLOC_OK; + case 5: + strncpy(country,"BE",2); + return WLOC_OK; + case 6: + strncpy(country,"LU",2); + return WLOC_OK; + case 7: + strncpy(country,"NO",2); + return WLOC_OK; + case 8: + strncpy(country,"SE",2); + return WLOC_OK; + case 9: + strncpy(country,"DK",2); + return WLOC_OK; + case 10: + strncpy(country,"AF",2); + return WLOC_OK; + case 12: + strncpy(country,"AL",2); + return WLOC_OK; + case 13: + strncpy(country,"DZ",2); + return WLOC_OK; + case 17: + strncpy(country,"AN",2); + return WLOC_OK; + case 18: + strncpy(country,"AG",2); + return WLOC_OK; + case 19: + strncpy(country,"AR",2); + return WLOC_OK; + case 20: + strncpy(country,"AM",2); + return WLOC_OK; + case 21: + strncpy(country,"AU",2); + return WLOC_OK; + case 23: + strncpy(country,"BS",2); + return WLOC_OK; + case 24: + strncpy(country,"BH",2); + return WLOC_OK; + case 25: + strncpy(country,"BD",2); + return WLOC_OK; + case 26: + strncpy(country,"BB",2); + return WLOC_OK; + case 27: + strncpy(country,"BY",2); + return WLOC_OK; + case 28: + strncpy(country,"BZ",2); + return WLOC_OK; + case 29: + strncpy(country,"BJ",2); + return WLOC_OK; + case 30: + strncpy(country,"BM",2); + return WLOC_OK; + case 32: + strncpy(country,"BO",2); + return WLOC_OK; + case 33: + strncpy(country,"BA",2); + return WLOC_OK; + case 36: + strncpy(country,"BR",2); + return WLOC_OK; + case 37: + strncpy(country,"BN",2); + return WLOC_OK; + case 38: + strncpy(country,"BG",2); + return WLOC_OK; + case 43: + strncpy(country,"CA",2); + return WLOC_OK; + case 44: + strncpy(country,"CV",2); + return WLOC_OK; + case 47: + strncpy(country,"CL",2); + return WLOC_OK; + case 48: + strncpy(country,"CN",2); + return WLOC_OK; + case 49: + strncpy(country,"CO",2); + return WLOC_OK; + case 52: + strncpy(country,"CR",2); + return WLOC_OK; + case 53: + strncpy(country,"HR",2); + return WLOC_OK; + case 55: + strncpy(country,"CY",2); + return WLOC_OK; + case 56: + strncpy(country,"CZ",2); + return WLOC_OK; + case 59: + strncpy(country,"DO",2); + return WLOC_OK; + case 60: + strncpy(country,"EC",2); + return WLOC_OK; + case 61: + strncpy(country,"EG",2); + return WLOC_OK; + case 66: + strncpy(country,"ET",2); + return WLOC_OK; + case 68: + strncpy(country,"FI",2); + return WLOC_OK; + case 69: + strncpy(country,"FR",2); + return WLOC_OK; + case 73: + strncpy(country,"GH",2); + return WLOC_OK; + case 75: + strncpy(country,"GR",2); + return WLOC_OK; + case 76: + strncpy(country,"GL",2); + return WLOC_OK; + case 77: + strncpy(country,"GD",2); + return WLOC_OK; + case 78: + strncpy(country,"GU",2); + return WLOC_OK; + case 79: + strncpy(country,"GT",2); + return WLOC_OK; + case 82: + strncpy(country,"HT",2); + return WLOC_OK; + case 83: + strncpy(country,"HN",2); + return WLOC_OK; + case 84: + strncpy(country,"HK",2); + return WLOC_OK; + case 85: + strncpy(country,"HU",2); + return WLOC_OK; + case 86: + strncpy(country,"IS",2); + return WLOC_OK; + case 87: + strncpy(country,"IN",2); + return WLOC_OK; + case 88: + strncpy(country,"ID",2); + return WLOC_OK; + case 89: + strncpy(country,"IR",2); + return WLOC_OK; + case 90: + strncpy(country,"IQ",2); + return WLOC_OK; + case 91: + strncpy(country,"IE",2); + return WLOC_OK; + case 93: + strncpy(country,"IT",2); + return WLOC_OK; + case 94: + strncpy(country,"JM",2); + return WLOC_OK; + case 95: + strncpy(country,"JP",2); + return WLOC_OK; + case 97: + strncpy(country,"JO",2); + return WLOC_OK; + case 98: + strncpy(country,"KZ",2); + return WLOC_OK; + case 99: + strncpy(country,"KE",2); + return WLOC_OK; + case 102: + strncpy(country,"KR",2); + return WLOC_OK; + case 103: + strncpy(country,"KW",2); + return WLOC_OK; + case 104: + strncpy(country,"KG",2); + return WLOC_OK; + case 105: + strncpy(country,"LA",2); + return WLOC_OK; + case 106: + strncpy(country,"LV",2); + return WLOC_OK; + case 107: + strncpy(country,"LB",2); + return WLOC_OK; + case 108: + strncpy(country,"LS",2); + return WLOC_OK; + case 111: + strncpy(country,"LT",2); + return WLOC_OK; + case 115: + strncpy(country,"MY",2); + return WLOC_OK; + case 116: + strncpy(country,"MV",2); + return WLOC_OK; + case 118: + strncpy(country,"MT",2); + return WLOC_OK; + case 119: + strncpy(country,"MQ",2); + return WLOC_OK; + case 121: + strncpy(country,"MU",2); + return WLOC_OK; + case 123: + strncpy(country,"MX",2); + return WLOC_OK; + case 124: + strncpy(country,"MC",2); + return WLOC_OK; + case 125: + strncpy(country,"MN",2); + return WLOC_OK; + case 126: + strncpy(country,"MA",2); + return WLOC_OK; + case 127: + strncpy(country,"MZ",2); + return WLOC_OK; + case 131: + strncpy(country,"NZ",2); + return WLOC_OK; + case 133: + strncpy(country,"NI",2); + return WLOC_OK; + case 135: + strncpy(country,"NG",2); + return WLOC_OK; + case 137: + strncpy(country,"OM",2); + return WLOC_OK; + case 138: + strncpy(country,"PK",2); + return WLOC_OK; + case 141: + strncpy(country,"PA",2); + return WLOC_OK; + case 142: + strncpy(country,"PY",2); + return WLOC_OK; + case 144: + strncpy(country,"PE",2); + return WLOC_OK; + case 145: + strncpy(country,"PH",2); + return WLOC_OK; + case 147: + strncpy(country,"PL",2); + return WLOC_OK; + case 148: + strncpy(country,"PT",2); + return WLOC_OK; + case 149: + strncpy(country,"PR",2); + return WLOC_OK; + case 150: + strncpy(country,"QA",2); + return WLOC_OK; + case 151: + strncpy(country,"RO",2); + return WLOC_OK; + case 152: + strncpy(country,"RU",2); + return WLOC_OK; + case 155: + strncpy(country,"SM",2); + return WLOC_OK; + case 157: + strncpy(country,"SA",2); + return WLOC_OK; + case 158: + strncpy(country,"SN",2); + return WLOC_OK; + case 161: + strncpy(country,"SG",2); + return WLOC_OK; + case 162: + strncpy(country,"SK",2); + return WLOC_OK; + case 163: + strncpy(country,"SI",2); + return WLOC_OK; + case 166: + strncpy(country,"ZA",2); + return WLOC_OK; + case 167: + strncpy(country,"ES",2); + return WLOC_OK; + case 168: + strncpy(country,"LK",2); + return WLOC_OK; + case 169: + strncpy(country,"SD",2); + return WLOC_OK; + case 170: + strncpy(country,"SR",2); + return WLOC_OK; + case 172: + strncpy(country,"SY",2); + return WLOC_OK; + case 173: + strncpy(country,"TW",2); + return WLOC_OK; + case 174: + strncpy(country,"TJ",2); + return WLOC_OK; + case 175: + strncpy(country,"TZ",2); + return WLOC_OK; + case 176: + strncpy(country,"TH",2); + return WLOC_OK; + case 179: + strncpy(country,"TT",2); + return WLOC_OK; + case 180: + strncpy(country,"TN",2); + return WLOC_OK; + case 181: + strncpy(country,"TR",2); + return WLOC_OK; + case 182: + strncpy(country,"TM",2); + return WLOC_OK; + case 185: + strncpy(country,"UA",2); + return WLOC_OK; + case 186: + strncpy(country,"AE",2); + return WLOC_OK; + case 187: + strncpy(country,"UK",2); + return WLOC_OK; + case 188: + strncpy(country,"US",2); + return WLOC_OK; + case 189: + strncpy(country,"UY",2); + return WLOC_OK; + case 191: + strncpy(country,"VE",2); + return WLOC_OK; + case 192: + strncpy(country,"VN",2); + return WLOC_OK; + case 195: + strncpy(country,"ZM",2); + return WLOC_OK; + case 196: + strncpy(country,"ZW",2); + return WLOC_OK; + default: + return WLOC_ERROR; + } +} + + +/** please refer to libwlocate.h for a description of this function! */ +WLOC_EXT_API char* wloc_get_countryname_from_code(short ccode) +{ + #define MAX_COUNTRY_NUM 196 + + static char countrynames[MAX_COUNTRY_NUM][42]={"Deutschland","�sterreich","Schweiz","Nederland","Belgi�","Luxemburg","Norge","Sverige", + "Danmark", + "Afghanistan","�land Islands","Albania","Algeria","American Samoa","Andorra","Angola", + "Anguilla","Antigua And Barbuda","Argentina","Armenia","Australia","Azerbaijan", + "Bahamas","Bahrain","Bangladesh","Barbados","Belarus","Belize","Benin","Bermuda","Bhutan", + "Bolivia","Bosnia And Herzegovina","Botswana","Bouvet Island","Brazil","Brunei Darussalam", + "Bulgaria","Burkina Faso","Burundi", + "Cambodia","Cameroon","Canada","Cape Verde","Central African Republic","Chad","Chile", + "China","Colombia","Comoros","Congo","Costa Rica","Croatia","Cuba","Cyprus","Czech Republic", + "Djibouti","Dominica","Dominican Republic", + "Ecuador","Egypt","El Salvador","Equatorial Guinea","Eritrea","Estonia","Ethiopia", + "Fiji","Finland","France", + "Gabon","Gambia","Georgia","Ghana","Gibraltar","Greece","Greenland","Grenada","Guam", + "Guatemala","Guernsey","Guyana", + "Haiti","Honduras","Hong Kong","Hungary", + "Iceland","India","Indonesia","Iran","Iraq","Ireland","Israel","Italy", + "Jamaica","Japan","Jersey","Jordan", + "Kazakhstan","Kenya","Kiribati","Korea, Democratic People's Republic Of","Korea, Republic Of", + "Kuwait","Kyrgyzstan", + "Lao People's Democratic Republic","Latvia","Lebanon","Lesotho","Liberia", + "Libyan Arab Jamahiriya","Lithuania", + "Macao","Madagascar","Malawi","Malaysia","Maldives","Mali","Malta","Martinique","Mauritania", + "Mauritius","Mayotte","Mexico","Monaco","Mongolia","Morocco","Mozambique", + "Namibia","Nauru","Nepal","New Caledonia","New Zealand","Nicaragua","Niger","Nigeria","Niue", + "Oman", + "Pakistan","Palau","Palestine","Panama","Papua New Guinea","Paraguay","Peru","Philippines", + "Pitcairn","Poland","Portugal","Puerto Rico", + "Qatar", + "Romania","Russian Federation","Rwanda", + "Samoa","San Marino","Sao Tome And Principe","Saudi Arabia","Senegal","Seychelles", + "Sierra Leone","Singapore","Slovakia","Slovenia","Solomon Islands","Somalia","South Africa", + "Spain","Sri Lanka","Sudan","Suriname","Swaziland","Syrian Arab Republic", + "Taiwan","Tajikistan","Tanzania","Thailand","Togo","Tonga","Trinidad And Tobago","Tunisia", + "Turkey","Turkmenistan","Tuvalu", + "Uganda","Ukraine","United Arab Emirates","United Kingdom","United States of America", + "Uruguay","Uzbekistan", + "Venezuela","Viet Nam", + "Western Sahara","Yemen","Zambia","Zimbabwe"}; + if ((ccode<1) || (ccode>=MAX_COUNTRY_NUM)) return NULL; + return countrynames[ccode-1]; +} + diff --git a/libwlocate/src/libwlocate.h b/libwlocate/src/libwlocate.h new file mode 100755 index 0000000000000000000000000000000000000000..ab0eb2da1fd4b3cf461926d29df88f6306af6b45 --- /dev/null +++ b/libwlocate/src/libwlocate.h @@ -0,0 +1,178 @@ +/** + * libwlocate - WLAN-based location service + * Copyright (C) 2010 Oxygenic/VWP virtual_worlds(at)gmx.de + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LIBWLOCATE_H +#define LIBWLOCATE_H + +#if defined __GNUC__ && !defined ENV_LINUX && !defined ENV_QNX + #define ENV_LINUX +#endif + +#if defined _MSC_VER && !defined ENV_WINDOWS + #define ENV_WINDOWS +#endif + +#ifndef WLOC_EXT_API + #ifdef ENV_LINUX + #define WLOC_EXT_API extern + #endif + + #ifdef ENV_QNX + #define WLOC_EXT_API extern + #endif + + #ifdef ENV_WINDOWS + #define WLOC_EXT_API __declspec(dllexport) + #endif +#endif + +#ifndef __cplusplus + typedef unsigned char bool; + #define false 0 + #define true 1 +#endif + +#ifdef ENV_WINDOWS + #include <windows.h> +#endif + +#ifdef ENV_QNX + #include <stdint.h> +#endif + +#define WLOC_MAX_NETWORKS 16 + +#pragma pack(1) // 1 byte alignment, calculation speed doesn't matters but data transfer sizes + +// internally used communication structures and defines ====================================================================== +struct wloc_req +{ + unsigned char version,length; + unsigned char bssids[WLOC_MAX_NETWORKS][6]; + char signal_off[WLOC_MAX_NETWORKS]; // no longer used in interface version 2 since signal strength does not provide any useful information for position calculation + unsigned long cgiIP; +}; + +#define WLOC_RESULT_OK 1 // a position could be calculated +#define WLOC_RESULT_ERROR 2 // the location could not be retrieved +#define WLOC_RESULT_IERROR 3 // an internal error occured, no data are available + +struct wloc_res +{ + char version,length; + char result,iresult,quality; + char cres6,cres7,cres8; // reserved variables + int lat,lon; + short ccode; + unsigned short wres34,wres56,wres78; // reserved variables +}; +// end of internally used communication structures and defines ================================================================ + + + +// public defines and function definitions ==================================================================================== +#define WLOC_OK 0 // result is OK, location could be retrieved +#define WLOC_CONNECTION_ERROR 1 // could not send data to/receive data from server +#define WLOC_SERVER_ERROR 2// could not connect to server to get position data +#define WLOC_LOCATION_ERROR 3 // could not retrieve location, detected WLAN networks are unknown +#define WLOC_ERROR 100 // some other error + +#ifdef __cplusplus +extern "C" +{ +#endif + /** + * This function retrieves the current geographic position of a system, the returned + * position values can be used directly within maps like OpenStreetMap or Google Earth + * @param[out] lat the latitude of the geographic position + * @param[out] lon the longitude of the geographic position + * @param[out] quality the percentual quality of the returned position, the given result + * is as more exact as closer the quality value is to 100%, as smaller this + * value is as bigger is the possible maximum deviation between returned + * and the real position + * @return only in case the returned value is equal WLOC_OK the values given back via the + * functions parameters can be used; in case an error occurred an error code + * WLOC_xxx is returned and the position and quality values given back are + * undefined and don't have to be used + */ + WLOC_EXT_API int wloc_get_location_from(const char *domain,double *lat,double *lon,char *quality,short *ccode); + + /** + * This function retrieves the current geographic position of a system using a selectable + * source for retrieval of position. The returned position values can be used directly + * within maps like OpenStreetMap or Google Earth + * @param[in] domain the domain name of the project to get the position from (e.g. + "openwifi.su") + * @param[out] lat the latitude of the geographic position + * @param[out] lon the longitude of the geographic position + * @param[out] quality the percentual quality of the returned position, the given result + * is as more exact as closer the quality value is to 100%, as smaller this + * value is as bigger is the possible maximum deviation between returned + * and the real position + * @return only in case the returned value is equal WLOC_OK the values given back via the + * functions parameters can be used; in case an error occurred an error code + * WLOC_xxx is returned and the position and quality values given back are + * undefined and don't have to be used + */ + WLOC_EXT_API int wloc_get_location(double *lat,double *lon,char *quality,short *ccode); + + /** + * This function is used internally on step before the geolocation is calculated. It + * checks which WLAN networks are accessible at the moment with wich signal strength and + * fills the request structure wloc_req with these data. So this function can be called + * in order to check the number of available networks without performing any geolocation. + * @param[out] request a structure of type wloc_req that is filled with the WLAN data; + * BSSID entries of this structure that are set to 00-00-00-00-00-00 are + * unused and do not contain valid WLAN information + * @return the retruned value is equal to the number of WLAN networks that have been found, + * only in case it is greater than 0 the value given back via the functions + * parameter can be used, elsewhere the structures contents are undefined + */ + WLOC_EXT_API int wloc_get_wlan_data(struct wloc_req *request); + + /** + * Using this function the numeric country code that is returned by the wloc_get_location + * function can be decoded to a two-character identifier. + * @param[in] ccode a country code value that has to be bigger than 0 + * @param[out] country this parameter has to point to a char array with a length of at least + * two, here the country identifier is stored that belongs to the given code; + * in case the function returns an error the contents of this variable are + * undefined + * @return WLOC_OK in case a valid and known country code was given, WLOC_ERROR in case the + * country code is unknown + */ + WLOC_EXT_API int wloc_get_country_from_code(short ccode,char *country); + + /** + * Using this function the numeric country code that is returned by the wloc_get_location + * function can be decoded to a full-length country name. The name is returned as null- + * terminated string that does not need to be copied, it is allocated by the library and will + * be released by it. + * @param[in] ccode a country code value that has to be bigger than 0 + * @return NULL in case the country code could not be decoded or the country name in case of + * success + */ + WLOC_EXT_API char* wloc_get_countryname_from_code(short ccode); + + WLOC_EXT_API int get_position(const char *domain,const struct wloc_req *request,double *lat,double *lon,char *quality,short *ccode); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libwlocate/src/wlan.c b/libwlocate/src/wlan.c new file mode 100755 index 0000000000000000000000000000000000000000..0cd32b1fae68446792a440685dc6e984012f9c75 --- /dev/null +++ b/libwlocate/src/wlan.c @@ -0,0 +1,255 @@ +/** + * libwlocate - WLAN-based location service + * Copyright (C) 2010-2012 Oxygenic/VWP virtual_worlds(at)gmx.de + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef ENV_WINDOWS +#include <windows.h> +#include <objbase.h> +#include <wtypes.h> + +#if (_MSC_VER>1400) + #include <wlanapi.h> + #pragma comment(lib, "wlanapi.lib") +#endif +#include "wlanapi_cust.h" +#endif + +#include "libwlocate.h" + +#include <stdio.h> +#include <stdlib.h> + +#ifdef ENV_WINDOWS +/** + * Works with Windows Vista and newer + */ +static int WinMethod1(struct wloc_req *request) +{ +#if (_MSC_VER<=1400) + static HINSTANCE wlan_library=NULL; +#endif + HANDLE hClient = NULL; + DWORD dwCurVersion = 0; + DWORD dwResult = 0; + int iRet = 0,i,j,cnt; + WCHAR GuidString[40] = {0}; + PWLAN_INTERFACE_INFO_LIST pIfList = NULL; + PWLAN_INTERFACE_INFO pIfInfo = NULL; + PWLAN_BSS_LIST pBssList=NULL; + PWLAN_BSS_ENTRY pBssEntry=NULL; + +#if (_MSC_VER<=1400) + if (!wlan_library) + { + wlan_library = LoadLibrary("wlanapi"); + if (!wlan_library) return 0; + WlanOpenHandle = (WlanOpenHandleFunction)GetProcAddress(wlan_library, "WlanOpenHandle"); + WlanEnumInterfaces = (WlanEnumInterfacesFunction)GetProcAddress(wlan_library, "WlanEnumInterfaces"); + WlanGetNetworkBssList = (WlanGetNetworkBssListFunction)GetProcAddress(wlan_library, "WlanGetNetworkBssList"); + WlanCloseHandle = (WlanCloseHandleFunction)GetProcAddress(wlan_library, "WlanCloseHandle"); + WlanFreeMemory = (WlanFreeMemoryFunction)GetProcAddress(wlan_library, "WlanFreeMemory"); + if ((!WlanOpenHandle) || (!WlanEnumInterfaces) || (!WlanGetNetworkBssList) || + (!WlanCloseHandle) || (!WlanFreeMemory)) + { + FreeLibrary(wlan_library); + wlan_library=NULL; + return 0; + } + } +#endif + dwResult = WlanOpenHandle(1, NULL, &dwCurVersion, &hClient); + if (dwResult != ERROR_SUCCESS) return 0; + + dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList); + if (dwResult != ERROR_SUCCESS) + { + WlanCloseHandle(hClient,NULL); + return 0; + } + cnt=-1; + for (i = 0; i < (int) pIfList->dwNumberOfItems; i++) + { + pIfInfo = (WLAN_INTERFACE_INFO *) &pIfList->InterfaceInfo[i]; + dwResult=WlanGetNetworkBssList(hClient,&pIfInfo->InterfaceGuid,NULL,dot11_BSS_type_any,FALSE,NULL,&pBssList); + if (dwResult!=ERROR_SUCCESS) continue; + for (j=0; j<(int)pBssList->dwNumberOfItems; j++) + { + char *c; + + cnt++; + pBssEntry=&pBssList->wlanBssEntries[j]; + c=(char*)&pBssList->wlanBssEntries[j]; + memcpy(request->bssids[cnt],pBssEntry->dot11Bssid,6); +// request->signal[cnt]=(char)pBssEntry->uLinkQuality; + if (cnt>=WLOC_MAX_NETWORKS) break; + } + if (pBssList != NULL) WlanFreeMemory(pBssList); // ??? + if (cnt>=WLOC_MAX_NETWORKS) break; + } + if (pIfList != NULL) WlanFreeMemory(pIfList); + WlanCloseHandle(hClient,NULL); + return cnt+1; +} + + +/** + * Works with Windows XP >=SP2 and newer, outdated with Windows Vista and newer + */ +static int WinMethod2(struct wloc_req *request) +{ + static HINSTANCE wzc_library=NULL; + INTFS_KEY_TABLE interface_list; + ADAPTER_INFO adapter_info; + INTF_ENTRY interface_data; + DWORD result,dwOutFlags; + int i,j,length,cnt,data_until_padding; + PNDIS_802_11_BSSID_LIST pList; + const unsigned char *buffer_end; + PNDIS_WLAN_BSSID pBssid; + + if (wzc_library==NULL) + { + wzc_library = LoadLibrary("wzcsapi"); + if (!wzc_library) return 0; + WZCEnumInterfaces = (WZCEnumInterfacesFunction)GetProcAddress(wzc_library, "WZCEnumInterfaces"); + WZCQueryInterface = (WZCQueryInterfaceFunction)GetProcAddress(wzc_library, "WZCQueryInterface"); +#if (_MSC_VER<=1400) + WZCRefreshInterface = (WZCRefreshInterfaceFunction)GetProcAddress(wzc_library, "WZCRefreshInterface"); + + if ((!WZCEnumInterfaces) || (!WZCQueryInterface) || (!WZCRefreshInterface)) +#else + if ((!WZCEnumInterfaces) || (!WZCQueryInterface)) +#endif + { + FreeLibrary(wzc_library); + wzc_library=0; + return 0; + } + } + + memset(&interface_list, 0, sizeof(INTFS_KEY_TABLE)); + result = WZCEnumInterfaces(NULL, &interface_list); + if (result != ERROR_SUCCESS) return 0; + cnt=-1; + for (i = 0; i<(int)interface_list.dwNumIntfs; ++i) + { + memset(&interface_data, 0, sizeof(INTF_ENTRY)); + interface_data.wszGuid = interface_list.pIntfs[i].wszGuid; + dwOutFlags = 1; + result = WZCQueryInterface(NULL, INTF_DESCR, &interface_data, &dwOutFlags); + if (result != ERROR_SUCCESS) + { + LocalFree(interface_list.pIntfs); + return 0; + } + length = wcslen(interface_list.pIntfs[i].wszGuid); + if (length > 0 && length < ADAPTER_NAME_LENGTH) + { + memset(&adapter_info, 0, sizeof(adapter_info)); + wcscpy(adapter_info.name, interface_list.pIntfs[i].wszGuid); + length = wcslen(interface_data.wszDescr); + if (length > 0 && length < ADAPTER_DESCRIPTION_LENGTH) wcscpy(adapter_info.description, interface_data.wszDescr); + + memset(&interface_data, 0, sizeof(INTF_ENTRY)); + interface_data.wszGuid =interface_list.pIntfs[i].wszGuid; + + result = WZCQueryInterface(NULL, INTF_BSSIDLIST | INTF_LIST_SCAN, &interface_data, &dwOutFlags); + if (result != ERROR_SUCCESS) + { + LocalFree(interface_list.pIntfs); + return 0; + } + if ((dwOutFlags & INTF_BSSIDLIST) != INTF_BSSIDLIST) + { + printf("WZC: Interface query consistency failure: incorrect flags\n"); + LocalFree(interface_list.pIntfs); + return 0; + } + if (interface_data.rdBSSIDList.dwDataLen == 0 || interface_data.rdBSSIDList.dwDataLen < sizeof(NDIS_802_11_BSSID_LIST)) + { + data_until_padding = (UCHAR*)&interface_data.padding1 - (UCHAR*)&interface_data; + + // this is a hack to support Windows XP SP2 with WLAN Hotfix and SP3 + memmove((UCHAR*)&interface_data + data_until_padding, (UCHAR*)&interface_data + data_until_padding + 8, sizeof(interface_data) - data_until_padding - 8); + if (interface_data.rdBSSIDList.dwDataLen == 0 || interface_data.rdBSSIDList.dwDataLen < sizeof(NDIS_802_11_BSSID_LIST)) + { + // cleanup + printf("WZC: Interface query consistency failure: no data or incorrect data length (length: %ld)\n", interface_data.rdBSSIDList.dwDataLen); + LocalFree(interface_list.pIntfs); + LocalFree(interface_data.rdBSSIDList.pData); + return 0; + } + } + pList =(NDIS_802_11_BSSID_LIST*)(interface_data.rdBSSIDList.pData); + pBssid =(PNDIS_WLAN_BSSID)(&pList->Bssid[0]); + buffer_end =(unsigned char*)(pBssid) + interface_data.rdBSSIDList.dwDataLen; + for (j= 0; j<(int)pList->NumberOfItems; j++) + { + cnt++; + if (pBssid->Length < sizeof(NDIS_WLAN_BSSID) || ((unsigned char*)(pBssid) + pBssid->Length > buffer_end)) + { + // cleanup + LocalFree(interface_list.pIntfs); + LocalFree(interface_data.rdBSSIDList.pData); + printf("WZC: Bssid structure looks odd. Break!\n"); + return cnt; + } + memcpy(request->bssids[cnt],pBssid->MacAddress,6); +// request->signal[cnt]=(char)((100+pBssid->Rssi)*1.6); // is this really the correct calculation for a signal strength in percent? + pBssid=(PNDIS_WLAN_BSSID)((unsigned char*)(pBssid) + pBssid->Length); + } + LocalFree(interface_data.rdBSSIDList.pData); + } + } + LocalFree(interface_list.pIntfs); + + return cnt+1; +} +#endif + + + +#ifdef ENV_LINUX +extern int iw_fill_structure(struct wloc_req *request); +#endif + +WLOC_EXT_API int wloc_get_wlan_data(struct wloc_req *request) +{ +#ifdef ENV_WINDOWS + int ret; + + // here we have to try which one of the methods works because there is no stable and standardised API + // available on Windows that could be used securely + ret=WinMethod1(request); + if (ret==0) ret=WinMethod2(request); + + return ret; +#else + #ifdef ENV_LINUX + return iw_fill_structure(request); + #else + #ifdef ENV_QNX + #warning WLAN functionality not implemented, library will never use the more exact WLAN positioning! + #else + #error Not supported! + #endif + #endif +#endif + return 0; // no networks found +} + + diff --git a/libwlocate/src/wlan.h b/libwlocate/src/wlan.h new file mode 100755 index 0000000000000000000000000000000000000000..6e486fbde723418564062dbfb6fac5c4b185480a --- /dev/null +++ b/libwlocate/src/wlan.h @@ -0,0 +1,24 @@ +/** + * libwlocate - WLAN-based location service + * Copyright (C) 2010-2012 Oxygenic/VWP virtual_worlds(at)gmx.de + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef WLAN_H +#define WLAN_H + +// the prototype of the wlan.c-function can be found in libwlocate.h, it is used as library interface function too + +#endif diff --git a/libwlocate/src/wlanapi_cust.h b/libwlocate/src/wlanapi_cust.h new file mode 100644 index 0000000000000000000000000000000000000000..7f04c21bc924fb0cb26d18059a378a6bb0b0ad12 --- /dev/null +++ b/libwlocate/src/wlanapi_cust.h @@ -0,0 +1,341 @@ +/** + * libwlocate - WLAN-based location service + * Copyright (C) 2010-2012 Oxygenic/VWP virtual_worlds(at)gmx.de + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This code bases on the header files out of the WLAN-API from Moritz + * Mertinkat. + */ + +#ifndef WLANAPI_CUST_H +#define WLANAPI_CUST_H + +#if (_MSC_VER<=1400) + +typedef enum _WLAN_INTERFACE_STATE { + wlan_interface_state_not_ready = 0, + wlan_interface_state_connected, + wlan_interface_state_ad_hoc_network_formed, + wlan_interface_state_disconnecting, + wlan_interface_state_disconnected, + wlan_interface_state_associating, + wlan_interface_state_discovering, + wlan_interface_state_authenticating +} WLAN_INTERFACE_STATE, *PWLAN_INTERFACE_STATE; + +#define WLAN_MAX_NAME_LENGTH 256 + +typedef struct _WLAN_INTERFACE_INFO { + GUID InterfaceGuid; + WCHAR strInterfaceDescription[WLAN_MAX_NAME_LENGTH]; + WLAN_INTERFACE_STATE isState; +} WLAN_INTERFACE_INFO, *PWLAN_INTERFACE_INFO; + +typedef struct _WLAN_INTERFACE_INFO_LIST { + DWORD dwNumberOfItems; + DWORD dwIndex; + + WLAN_INTERFACE_INFO InterfaceInfo[1]; + +} WLAN_INTERFACE_INFO_LIST, *PWLAN_INTERFACE_INFO_LIST; + +#define DOT11_SSID_MAX_LENGTH 32 +#define DOT11_RATE_SET_MAX_LENGTH 126 + +typedef struct _DOT11_SSID { + ULONG uSSIDLength; + UCHAR ucSSID[DOT11_SSID_MAX_LENGTH]; +} DOT11_SSID, *PDOT11_SSID; + +typedef UCHAR DOT11_MAC_ADDRESS[6]; + +typedef enum _DOT11_BSS_TYPE { + dot11_BSS_type_infrastructure = 1, + dot11_BSS_type_independent = 2, + dot11_BSS_type_any = 3 +} DOT11_BSS_TYPE, * PDOT11_BSS_TYPE; + +typedef enum _DOT11_PHY_TYPE { + DOT11_PHY_TYPE_UNUSED, +} DOT11_PHY_TYPE; + +typedef struct _WLAN_RATE_SET { + ULONG uRateSetLength; + USHORT usRateSet[DOT11_RATE_SET_MAX_LENGTH]; +} WLAN_RATE_SET, *PWLAN_RATE_SET; + +/*typedef struct _WLAN_BSS_ENTRY { + DOT11_SSID dot11Ssid; + ULONG uPhyId; + DOT11_MAC_ADDRESS dot11Bssid; + DOT11_BSS_TYPE dot11BssType; + DOT11_PHY_TYPE dot11BssPhyType; + LONG lRssi; + ULONG uLinkQuality; + BOOLEAN bInRegDomain; + USHORT usBeaconPeriod; + ULONGLONG ullTimestamp; + ULONGLONG ullHostTimestamp; + USHORT usCapabilityInformation; + ULONG ulChCenterFrequency; + WLAN_RATE_SET wlanRateSet; // --> to be verified, according to MSDN this member exists, according to the include of the Platform SDK it doesn't + ULONG ulIeOffset; + ULONG ulIeSize; +} WLAN_BSS_ENTRY, * PWLAN_BSS_ENTRY;*/ + +typedef struct _WLAN_BSS_ENTRY +{ + DOT11_SSID dot11Ssid; + ULONG uPhyId; + DOT11_MAC_ADDRESS dot11Bssid; + DOT11_BSS_TYPE dot11BssType; + DOT11_PHY_TYPE dot11BssPhyType; + LONG lRssi; + ULONG uLinkQuality; + BOOLEAN bInRegDomain; + USHORT usBeaconPeriod; + ULONGLONG ullTimestamp; + ULONGLONG ullHostTimestamp; + USHORT usCapabilityInformation; + ULONG ulChCenterFrequency; + WLAN_RATE_SET wlanRateSet; + ULONG ulIeOffset; + ULONG ulIeSize; + DWORD pad1,pad2; // strange padding bytes, required since Vista + char pad3; // and Win 7 elsewhere this structure contains crap +} WLAN_BSS_ENTRY, *PWLAN_BSS_ENTRY; + +typedef struct _WLAN_BSS_LIST +{ + DWORD dwTotalSize; + DWORD dwNumberOfItems; + WLAN_BSS_ENTRY wlanBssEntries[1]; +} WLAN_BSS_LIST, *PWLAN_BSS_LIST; + +typedef DWORD (WINAPI *WlanOpenHandleFunction)( + DWORD dwClientVersion, + PVOID pReserved, + PDWORD pdwNegotiatedVersion, + PHANDLE phClientHandle +); + +typedef DWORD (WINAPI *WlanEnumInterfacesFunction)( + HANDLE hClientHandle, + PVOID pReserved, + PWLAN_INTERFACE_INFO_LIST *ppInterfaceList +); + +typedef DWORD (WINAPI *WlanGetNetworkBssListFunction)( + HANDLE hClientHandle, + const GUID *pInterfaceGuid, + const PDOT11_SSID pDot11Ssid, + DOT11_BSS_TYPE dot11BssType, + BOOL bSecurityEnabled, + PVOID pReserved, + PWLAN_BSS_LIST *ppWlanBssList +); + +typedef DWORD (WINAPI *WlanCloseHandleFunction)( + HANDLE hClientHandle, + PVOID pReserved +); + +typedef VOID (WINAPI *WlanFreeMemoryFunction)( + PVOID pMemory +); + +WlanOpenHandleFunction WlanOpenHandle; +WlanEnumInterfacesFunction WlanEnumInterfaces; +WlanGetNetworkBssListFunction WlanGetNetworkBssList; +WlanCloseHandleFunction WlanCloseHandle; +WlanFreeMemoryFunction WlanFreeMemory; + +#endif + + + +typedef struct +{ + LPWSTR wszGuid; +} INTF_KEY_ENTRY, *PINTF_KEY_ENTRY; + + + +typedef struct +{ + DWORD dwNumIntfs; + PINTF_KEY_ENTRY pIntfs; +} INTFS_KEY_TABLE, *PINTFS_KEY_TABLE; + + + +typedef DWORD (WINAPI *WZCEnumInterfacesFunction)(LPWSTR pSrvAddr, PINTFS_KEY_TABLE pIntfs); + + + +typedef struct +{ + DWORD dwDataLen; + LPBYTE pData; +} RAW_DATA, *PRAW_DATA; + + + +typedef struct +{ + LPWSTR wszGuid; + LPWSTR wszDescr; + ULONG ulMediaState; + ULONG ulMediaType; + ULONG ulPhysicalMediaType; + INT nInfraMode; + INT nAuthMode; + INT nWepStatus; + ULONG padding1[2]; // 16 chars on Windows XP SP3 or SP2 with WLAN Hotfix installed, 8 chars otherwise + DWORD dwCtlFlags; + DWORD dwCapabilities; + RAW_DATA rdSSID; + RAW_DATA rdBSSID; + RAW_DATA rdBSSIDList; + RAW_DATA rdStSSIDList; + RAW_DATA rdCtrlData; + BOOL bInitialized; + ULONG padding2[64]; // for security reason ... +} INTF_ENTRY, *PINTF_ENTRY; + + + +typedef DWORD (WINAPI *WZCQueryInterfaceFunction)(LPWSTR pSrvAddr, DWORD dwInFlags, PINTF_ENTRY pIntf, LPDWORD pdwOutFlags); + + + +typedef wchar_t ADAPTER_NAME; +typedef wchar_t ADAPTER_DESCRIPTION; +typedef char AP_NAME; + + + +#define ADAPTER_NAME_LENGTH 256 +#define ADAPTER_DESCRIPTION_LENGTH 256 +#define AP_NAME_LENGTH 256 +#define INTF_DESCR (0x00010000) +#define INTF_BSSIDLIST (0x04000000) +#define INTF_LIST_SCAN (0x08000000) + + + +typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; + + +typedef struct _ADAPTER_INFO +{ + ADAPTER_NAME name[ADAPTER_NAME_LENGTH]; + ADAPTER_DESCRIPTION description[ADAPTER_DESCRIPTION_LENGTH]; +} ADAPTER_INFO; + +#if (_MSC_VER<=1400) + +typedef struct _NDIS_802_11_SSID +{ + ULONG SsidLength; + UCHAR Ssid [32]; +} NDIS_802_11_SSID, *PNDIS_802_11_SSID; + +typedef UCHAR NDIS_802_11_RATES_EX[16]; +typedef LONG NDIS_802_11_RSSI; +typedef UCHAR NDIS_802_11_RATES_EX[16]; + +typedef enum _NDIS_802_11_NETWORK_TYPE +{ + Ndis802_11FH, + Ndis802_11DS, + Ndis802_11NetworkTypeMax, +} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; + +typedef struct _NDIS_802_11_CONFIGURATION_FH +{ + ULONG Length; + ULONG HopPattern; + ULONG HopSet; + ULONG DwellTime; +} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; + +typedef struct _NDIS_802_11_CONFIGURATION +{ + ULONG Length; + ULONG BeaconPeriod; + ULONG ATIMWindow; + ULONG DSConfig; + NDIS_802_11_CONFIGURATION_FH FHConfig; +} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; + +typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE +{ + Ndis802_11IBSS, + Ndis802_11Infrastructure, + Ndis802_11AutoUnknown, + Ndis802_11InfrastructureMax, +} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; + +typedef struct _NDIS_WLAN_BSSID_EX +{ + ULONG Length; + NDIS_802_11_MAC_ADDRESS MacAddress; + UCHAR Reserved[2]; + NDIS_802_11_SSID Ssid; + ULONG Privacy; + NDIS_802_11_RSSI Rssi; + NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; + NDIS_802_11_CONFIGURATION Configuration; + NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; + NDIS_802_11_RATES_EX SupportedRates; + ULONG IELength; + UCHAR IEs[1]; +} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; + +typedef struct _NDIS_WLAN_BSSID +{ + UCHAR padding1[4]; + ULONG Length; + UCHAR padding2[4]; + NDIS_802_11_MAC_ADDRESS MacAddress; + UCHAR Reserved[2]; + NDIS_802_11_SSID Ssid; + ULONG Privacy; + NDIS_802_11_RSSI Rssi; +} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; + +typedef struct _NDIS_802_11_BSSID_LIST +{ + ULONG NumberOfItems; + NDIS_WLAN_BSSID Bssid[1]; +} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; + +typedef DWORD (WINAPI *WZCRefreshInterfaceFunction) +( + LPWSTR pSrvAddr, + DWORD dwInFlags, + PINTF_ENTRY pIntf, + LPDWORD pdwOutFlags +); + +WZCRefreshInterfaceFunction WZCRefreshInterface; + +#endif + +WZCEnumInterfacesFunction WZCEnumInterfaces; +WZCQueryInterfaceFunction WZCQueryInterface; + +#endif