Added scanner application
[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 /* Callback for normal D-BUS messages */
215 gint dbus_req_handler(const gchar * interface, const gchar * method,
216                       GArray * arguments, gpointer data,
217                       osso_rpc_t * retval)
218 {
219     AppData *appdata;
220     appdata = (AppData *) data;
221
222     retval->type = DBUS_TYPE_STRING;
223     retval->value.s = (gchar*) malloc( sizeof(gchar *) );
224     retval->value.s[0] = '\0';
225
226     if ( strcmp(method,"start")==0 ) {
227     //    osso_system_note_infoprint(appdata->osso_context, "Starting WifiScan", NULL);
228         return OSSO_OK;
229     }
230
231     if ( strcmp(method,"stop")==0 ) {
232         iw_sockets_close(appdata->iface.sock);
233         appdata->iface.sock = 0;
234     //    osso_system_note_infoprint(appdata->osso_context, "Stopping WifiScan", NULL);
235         osso_deinitialize(appdata->osso_context);
236         exit(0);
237     }
238
239     if ( strcmp(method,"scan")==0 ) {
240     //    osso_system_note_infoprint(appdata->osso_context, "Scanning ...", NULL);
241
242         ScanInfo **scan = (ScanInfo **) makeScan(&appdata->iface,retval->value.s);
243         if(scan == NULL) {
244             retval->value.s = (gchar *) realloc(retval->value.s,64*sizeof(gchar *));
245             snprintf(retval->value.s,64,"ERROR");
246             return OSSO_ERROR;
247         }
248
249         int i;
250         for (i=0; i<25&&*(scan+i)!=NULL; i++) {
251             ScanInfo* sc = *(scan+i);
252             retval->value.s = (gchar *) realloc(retval->value.s,23*(i+1)*sizeof(gchar *));
253             if ( retval->value.s == NULL ) {
254                 retval->value.s = "Error allocating memory";
255                 return OSSO_ERROR;
256             }
257             sprintf(retval->value.s+strlen(retval->value.s),"%s:%d ",sc->mac,sc->rssi);
258         }
259
260         retval->value.s[strlen(retval->value.s)-1]  = '\0';
261         return OSSO_OK;
262     }
263
264     retval->value.s = (gchar *) realloc(retval->value.s,64*sizeof(gchar *));
265     snprintf(retval->value.s,64,"Unknown method");
266     return OSSO_ERROR;
267 }
268
269 static GMainLoop *event_loop = NULL;
270
271 int main( void ) {
272
273         osso_context_t *osso_context;
274
275         /* Initialize maemo application */
276         osso_context = osso_initialize(OSSO_NAME, WIFISCAND_VERSION_STRING, TRUE, NULL);
277
278         /* Check that initialization was ok */
279         if (osso_context == NULL) {
280                 exit(OSSO_ERROR);
281                 }
282
283         /* Create AppData */
284         AppData *appdata;
285         appdata = g_new0(AppData, 1);
286         appdata->osso_context = osso_context;
287
288         memset(&(appdata->iface.info), 0, sizeof(wireless_info));
289         appdata->iface.ifname = "wlan0";
290         appdata->iface.sock   = 0;
291
292         /* Add handler for hello D-BUS messages */
293         osso_return_t result = osso_rpc_set_cb_f(osso_context, OSSO_SERVICE, OSSO_OBJECT, OSSO_IFACE, dbus_req_handler, appdata);
294         if (result != OSSO_OK) {
295                 osso_system_note_infoprint(appdata->osso_context, "Failure while setting OSSO callback", NULL);
296                 return OSSO_ERROR;
297         }
298
299         /* INITIALIZATION */
300         appdata->iface.sock = iw_sockets_open();
301
302         if(appdata->iface.sock < 0) {
303                 osso_system_note_infoprint(osso_context, "Failure in socket initialization", NULL);
304                 return OSSO_ERROR;
305         }
306
307         struct ifreq frq;
308
309         strncpy(frq.ifr_name, appdata->iface.ifname, IFNAMSIZ);
310                         
311         if(ioctl(appdata->iface.sock, SIOCGIFFLAGS, &frq)) {
312                 osso_system_note_infoprint(osso_context, "Cannot scan", NULL);
313                 return OSSO_ERROR;
314         }
315
316         frq.ifr_flags |= IFF_UP | IFF_RUNNING;
317                 
318         ioctl(appdata->iface.sock, SIOCSIFFLAGS, &frq);
319                         
320         refresh(&appdata->iface);
321         /* INITIALIZATION FINISH */
322
323         event_loop = g_main_loop_new(NULL, FALSE);
324         g_main_loop_run(event_loop);
325
326         /* Deinitialize OSSO */
327         osso_deinitialize(osso_context);
328
329         exit(0);
330 }
331