BUGFIX#5730 : finally fixed
[wifihood] / wifiscand / wifiscand.c
1
2 #include <iwlib.h>
3
4 #include <libosso.h>
5
6 #define WIFISCAND_VERSION_STRING  "1.0"
7
8 #define OSSO_NAME    "wifiscan"
9 #define OSSO_SERVICE "org.javiplx."OSSO_NAME
10 #define OSSO_OBJECT  "/org/javiplx/"OSSO_NAME
11 #define OSSO_IFACE   "org.javiplx."OSSO_NAME
12
13
14 typedef struct {
15         char          mac[18];
16         int           rssi;
17         int           noise;
18 } ScanInfo;
19
20
21 /* --------------------------------------------------------------------------- WirelessInterface */
22 typedef struct {
23         wireless_info info;
24         char*         ifname;
25         int           sock;
26 } WirelessInterface;
27
28 /* ------------------------------------------------------------------ WirelessInterface_ScanItem */
29
30 static int WirelessInterface_ScanItem(struct iw_event* event, ScanInfo **scaninfo) {
31
32         switch(event->cmd) {
33                                   
34                 case SIOCGIWAP: {
35
36                         *scaninfo = (ScanInfo*) malloc( sizeof(ScanInfo) );
37                         memset(*scaninfo, 0, sizeof(ScanInfo) );
38
39                         iw_ether_ntop( (const struct ether_addr*)(event->u.ap_addr.sa_data), (*scaninfo)->mac);
40                         return 1;
41                 }
42
43                 case IWEVQUAL: {
44                         (*scaninfo)->rssi = event->u.qual.level - 0x100;
45                         return 0;
46                 }
47
48                 default: {
49                          return 0;
50                  }
51         }
52 }
53
54 /* ---------------------------------------------------------------------- */
55
56 void* makeScan(WirelessInterface* coso, gchar *message) {
57         struct iwreq          wrq;
58         unsigned char* buffer     = NULL;
59         int            buflen     = IW_SCAN_MAX_DATA;
60         iwrange        range;
61         int            has_range;
62         struct timeval        tv;
63         int            timeout    = 10000000;
64
65         ScanInfo        **scan = NULL;
66
67         has_range = (iw_get_range_info(coso->sock, coso->ifname, &range) >= 0);
68
69         tv.tv_sec          = 0;
70         tv.tv_usec         = 250000;
71         wrq.u.data.pointer = NULL;
72         wrq.u.data.flags   = 0;
73         wrq.u.data.length  = 0;
74
75         if(iw_set_ext(coso->sock, coso->ifname, SIOCSIWSCAN, &wrq) < 0) {
76                 if(errno != EPERM) {
77                         message = "Interface doesn't support scanning";
78                         return NULL;
79                 }
80                 tv.tv_usec = 0;
81         }
82         timeout -= tv.tv_usec;
83
84         while(1) {
85                 fd_set rfds;
86                 int    last_fd;
87                 int    ret;
88
89                 FD_ZERO(&rfds);
90                 last_fd = -1;
91
92                 ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
93
94                 if(ret < 0) {
95                         if(errno == EAGAIN || errno == EINTR) continue;
96                         
97                         else {
98                                 message = "Unknown scanning error";
99                                 return NULL;
100                         }
101                 }
102
103                 if(!ret) {
104                         unsigned char* newbuf;
105
106                         realloc:
107                         newbuf = (unsigned char*) realloc(buffer, buflen);
108                         
109                         if(!newbuf) {
110                                 if(buffer) free(buffer);
111                                 message = "Memory allocation failure in scan";
112                                 return NULL;
113                         }
114                         
115                         buffer = newbuf;
116
117                         wrq.u.data.pointer = buffer;
118                         wrq.u.data.flags   = 0;
119                         wrq.u.data.length  = buflen;
120                         
121                         if(iw_get_ext(coso->sock, coso->ifname, SIOCGIWSCAN, &wrq) < 0) {
122                                 if((errno == E2BIG)) {
123                                         if(wrq.u.data.length > buflen) buflen = wrq.u.data.length;
124                                         else buflen *= 2;
125
126                                         goto realloc;
127                                 }
128
129                                 if(errno == EAGAIN) {
130                                         tv.tv_sec   = 0;
131                                         tv.tv_usec  = 100000;
132                                         timeout    -= tv.tv_usec;
133                                         
134                                         if(timeout > 0) continue;
135                                 }
136
137                                 free(buffer);
138                                 
139                                 message = "Unable to read scan data";
140
141                                 return NULL;
142                         }
143                         
144                         else break;
145                 }
146         }
147
148
149         if(wrq.u.data.length)   {
150                 struct iw_event      iwe;
151                 stream_descr stream;
152                 int          ret;
153                 void*    scan_dict = NULL;
154                 
155                 iw_init_event_stream(&stream, (char*)(buffer), wrq.u.data.length);
156                 
157                 scan = (ScanInfo**) malloc( 25 * sizeof(ScanInfo *) );
158                 memset(scan, 0, 25 * sizeof(ScanInfo *) );
159                 *scan = NULL;
160                 int i;
161                 for (i=0; i<25; i++) *(scan+i) = NULL;
162
163                 i = 0;
164                 ScanInfo *sc = NULL;
165                 do {
166                         ret = iw_extract_event_stream(&stream, &iwe, range.we_version_compiled);
167                 
168                         if(ret > 0) {
169                                 int sr = WirelessInterface_ScanItem(&iwe, &sc);
170                                 if(sr && i<25) {
171                                         *(scan+i) = sc;
172                                         i++;
173                                 }
174                         }
175                 }
176                 
177                 while(ret > 0);
178
179         } else {
180                 message = "Unknown error";
181                 free(buffer);
182                 return NULL;
183         }
184
185         free(buffer);
186         return scan;
187 }
188
189 static void refresh(WirelessInterface* coso) {
190         struct iwreq wrq;
191         
192         iw_get_basic_config(coso->sock, coso->ifname, &(coso->info.b));
193         iw_get_range_info(coso->sock, coso->ifname, &(coso->info.range));
194
195         iw_get_ext(coso->sock, coso->ifname, SIOCGIWRATE, &wrq);
196         memcpy(&(coso->info.bitrate), &wrq.u.bitrate, sizeof(iwparam));
197
198         iw_get_ext(coso->sock, coso->ifname, SIOCGIWAP, &wrq);
199         memcpy(&(coso->info.ap_addr), &wrq.u.ap_addr, sizeof (sockaddr));
200
201         iw_get_stats(
202                 coso->sock, coso->ifname, &(coso->info.stats), 
203                 &(coso->info.range), coso->info.has_range
204         );
205 }
206
207 /* Application UI data struct */
208 typedef struct _AppData AppData;
209 struct _AppData {
210     WirelessInterface iface;
211     osso_context_t *osso_context;
212 };
213
214 static GMainLoop *event_loop = NULL;
215 static short int start_flags = 0;
216
217 /* Callback for normal D-BUS messages */
218 gint dbus_req_handler(const gchar * interface, const gchar * method,
219                       GArray * arguments, gpointer data,
220                       osso_rpc_t * retval)
221 {
222     AppData *appdata;
223     appdata = (AppData *) data;
224
225     retval->type = DBUS_TYPE_STRING;
226     retval->value.s = (gchar*) malloc( sizeof(gchar *) );
227     retval->value.s[0] = '\0';
228
229     if ( strcmp(method,"start")==0 ) {
230     //    osso_system_note_infoprint(appdata->osso_context, "Starting WifiScan", NULL);
231         return OSSO_OK;
232     }
233
234     if ( strcmp(method,"stop")==0 ) {
235         struct ifreq frq;
236         strncpy(frq.ifr_name, appdata->iface.ifname, IFNAMSIZ);
237         if(!ioctl(appdata->iface.sock, SIOCGIFFLAGS, &frq)) {
238             frq.ifr_flags = start_flags;
239             ioctl(appdata->iface.sock, SIOCSIFFLAGS, &frq);
240         }
241         iw_sockets_close(appdata->iface.sock);
242         appdata->iface.sock = 0;
243     //    osso_system_note_infoprint(appdata->osso_context, "Stopping WifiScan", NULL);
244         osso_deinitialize(appdata->osso_context);
245         exit(0);
246     }
247
248     if ( strcmp(method,"scan")==0 ) {
249     //    osso_system_note_infoprint(appdata->osso_context, "Scanning ...", NULL);
250
251         ScanInfo **scan = (ScanInfo **) makeScan(&appdata->iface,retval->value.s);
252         if(scan == NULL) {
253             retval->value.s = (gchar *) realloc(retval->value.s,64*sizeof(gchar *));
254             snprintf(retval->value.s,64,"ERROR");
255             return OSSO_ERROR;
256         }
257
258         int i;
259         for (i=0; i<25&&*(scan+i)!=NULL; i++) {
260             ScanInfo* sc = *(scan+i);
261             retval->value.s = (gchar *) realloc(retval->value.s,23*(i+1)*sizeof(gchar *));
262             if ( retval->value.s == NULL ) {
263                 retval->value.s = "Error allocating memory";
264                 return OSSO_ERROR;
265             }
266             sprintf(retval->value.s+strlen(retval->value.s),"%s:%d ",sc->mac,sc->rssi);
267         }
268
269         retval->value.s[strlen(retval->value.s)-1]  = '\0';
270         return OSSO_OK;
271     }
272
273     retval->value.s = (gchar *) realloc(retval->value.s,64*sizeof(gchar *));
274     snprintf(retval->value.s,64,"Unknown method");
275     return OSSO_ERROR;
276 }
277
278
279 int main( void ) {
280
281         osso_context_t *osso_context;
282
283         /* Initialize maemo application */
284         osso_context = osso_initialize(OSSO_NAME, WIFISCAND_VERSION_STRING, TRUE, NULL);
285
286         /* Check that initialization was ok */
287         if (osso_context == NULL) {
288                 exit(OSSO_ERROR);
289                 }
290
291         /* Create AppData */
292         AppData *appdata;
293         appdata = g_new0(AppData, 1);
294         appdata->osso_context = osso_context;
295
296         memset(&(appdata->iface.info), 0, sizeof(wireless_info));
297         appdata->iface.ifname = "wlan0";
298         appdata->iface.sock   = 0;
299
300         /* Add handler for hello D-BUS messages */
301         osso_return_t result = osso_rpc_set_cb_f(osso_context, OSSO_SERVICE, OSSO_OBJECT, OSSO_IFACE, dbus_req_handler, appdata);
302         if (result != OSSO_OK) {
303                 osso_system_note_infoprint(appdata->osso_context, "Failure while setting OSSO callback", NULL);
304                 return OSSO_ERROR;
305         }
306
307         /* INITIALIZATION */
308         appdata->iface.sock = iw_sockets_open();
309
310         if(appdata->iface.sock < 0) {
311                 osso_system_note_infoprint(osso_context, "Failure in socket initialization", NULL);
312                 return OSSO_ERROR;
313         }
314
315         struct ifreq frq;
316
317         strncpy(frq.ifr_name, appdata->iface.ifname, IFNAMSIZ);
318                         
319         if(ioctl(appdata->iface.sock, SIOCGIFFLAGS, &frq)) {
320                 osso_system_note_infoprint(osso_context, "Cannot scan", NULL);
321                 return OSSO_ERROR;
322         }
323
324         start_flags = frq.ifr_flags;
325         frq.ifr_flags |= IFF_UP | IFF_RUNNING;
326                 
327         ioctl(appdata->iface.sock, SIOCSIFFLAGS, &frq);
328                         
329         refresh(&appdata->iface);
330         /* INITIALIZATION FINISH */
331
332         event_loop = g_main_loop_new(NULL, FALSE);
333         g_main_loop_run(event_loop);
334
335         frq.ifr_flags = start_flags;
336         ioctl(appdata->iface.sock, SIOCSIFFLAGS, &frq);
337                         
338         /* Deinitialize OSSO */
339         osso_deinitialize(osso_context);
340
341         exit(0);
342 }
343