2 * iwinfo - Wireless Information Library - Linux Wireless Extension Backend
4 * Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
6 * The iwinfo library is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
10 * The iwinfo library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
18 * Parts of this code are derived from the Linux wireless tools, iwlib.c,
19 * iwlist.c and iwconfig.c in particular.
23 #include "iwinfo/wext_scan.h"
26 static int wext_ioctl(const char *ifname
, int cmd
, struct iwreq
*wrq
)
28 strncpy(wrq
->ifr_name
, ifname
, IFNAMSIZ
);
29 return iwinfo_ioctl(cmd
, wrq
);
32 static inline double wext_freq2float(const struct iw_freq
*in
)
35 double res
= (double) in
->m
;
36 for(i
= 0; i
< in
->e
; i
++) res
*= 10;
40 static inline int wext_extract_event(struct stream_descr
*stream
, struct iw_event
*iwe
, int wev
)
42 const struct iw_ioctl_description
*descr
= NULL
;
44 unsigned int event_len
= 1;
46 unsigned cmd_index
; /* *MUST* be unsigned */
48 /* Check for end of stream */
49 if((stream
->current
+ IW_EV_LCP_PK_LEN
) > stream
->end
)
52 /* Extract the event header (to get the event id).
53 * Note : the event may be unaligned, therefore copy... */
54 memcpy((char *) iwe
, stream
->current
, IW_EV_LCP_PK_LEN
);
56 /* Check invalid events */
57 if(iwe
->len
<= IW_EV_LCP_PK_LEN
)
60 /* Get the type and length of that event */
61 if(iwe
->cmd
<= SIOCIWLAST
)
63 cmd_index
= iwe
->cmd
- SIOCIWFIRST
;
64 if(cmd_index
< standard_ioctl_num
)
65 descr
= &(standard_ioctl_descr
[cmd_index
]);
69 cmd_index
= iwe
->cmd
- IWEVFIRST
;
70 if(cmd_index
< standard_event_num
)
71 descr
= &(standard_event_descr
[cmd_index
]);
75 event_type
= descr
->header_type
;
77 /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
78 event_len
= event_type_size
[event_type
];
80 /* Fixup for earlier version of WE */
81 if((wev
<= 18) && (event_type
== IW_HEADER_TYPE_POINT
))
82 event_len
+= IW_EV_POINT_OFF
;
84 /* Check if we know about this event */
85 if(event_len
<= IW_EV_LCP_PK_LEN
)
87 /* Skip to next event */
88 stream
->current
+= iwe
->len
;
92 event_len
-= IW_EV_LCP_PK_LEN
;
94 /* Set pointer on data */
95 if(stream
->value
!= NULL
)
96 pointer
= stream
->value
; /* Next value in event */
98 pointer
= stream
->current
+ IW_EV_LCP_PK_LEN
; /* First value in event */
100 /* Copy the rest of the event (at least, fixed part) */
101 if((pointer
+ event_len
) > stream
->end
)
103 /* Go to next event */
104 stream
->current
+= iwe
->len
;
108 /* Fixup for WE-19 and later : pointer no longer in the stream */
109 /* Beware of alignement. Dest has local alignement, not packed */
110 if( (wev
> 18) && (event_type
== IW_HEADER_TYPE_POINT
) )
111 memcpy((char *) iwe
+ IW_EV_LCP_LEN
+ IW_EV_POINT_OFF
, pointer
, event_len
);
113 memcpy((char *) iwe
+ IW_EV_LCP_LEN
, pointer
, event_len
);
115 /* Skip event in the stream */
116 pointer
+= event_len
;
118 /* Special processing for iw_point events */
119 if(event_type
== IW_HEADER_TYPE_POINT
)
121 /* Check the length of the payload */
122 unsigned int extra_len
= iwe
->len
- (event_len
+ IW_EV_LCP_PK_LEN
);
125 /* Set pointer on variable part (warning : non aligned) */
126 iwe
->u
.data
.pointer
= pointer
;
128 /* Check that we have a descriptor for the command */
130 /* Can't check payload -> unsafe... */
131 iwe
->u
.data
.pointer
= NULL
; /* Discard paylod */
134 /* Those checks are actually pretty hard to trigger,
135 * because of the checks done in the kernel... */
137 unsigned int token_len
= iwe
->u
.data
.length
* descr
->token_size
;
139 /* Ugly fixup for alignement issues.
140 * If the kernel is 64 bits and userspace 32 bits,
141 * we have an extra 4+4 bytes.
142 * Fixing that in the kernel would break 64 bits userspace. */
143 if((token_len
!= extra_len
) && (extra_len
>= 4))
145 uint16_t alt_dlen
= *((uint16_t *) pointer
);
146 unsigned int alt_token_len
= alt_dlen
* descr
->token_size
;
147 if((alt_token_len
+ 8) == extra_len
)
149 /* Ok, let's redo everything */
150 pointer
-= event_len
;
152 /* Dest has local alignement, not packed */
153 memcpy((char *) iwe
+ IW_EV_LCP_LEN
+ IW_EV_POINT_OFF
, pointer
, event_len
);
154 pointer
+= event_len
+ 4;
155 iwe
->u
.data
.pointer
= pointer
;
156 token_len
= alt_token_len
;
160 /* Discard bogus events which advertise more tokens than
161 * what they carry... */
162 if(token_len
> extra_len
)
163 iwe
->u
.data
.pointer
= NULL
; /* Discard paylod */
165 /* Check that the advertised token size is not going to
166 * produce buffer overflow to our caller... */
167 if((iwe
->u
.data
.length
> descr
->max_tokens
)
168 && !(descr
->flags
& IW_DESCR_FLAG_NOMAX
))
169 iwe
->u
.data
.pointer
= NULL
; /* Discard paylod */
171 /* Same for underflows... */
172 if(iwe
->u
.data
.length
< descr
->min_tokens
)
173 iwe
->u
.data
.pointer
= NULL
; /* Discard paylod */
178 iwe
->u
.data
.pointer
= NULL
;
180 /* Go to next event */
181 stream
->current
+= iwe
->len
;
185 /* Ugly fixup for alignement issues.
186 * If the kernel is 64 bits and userspace 32 bits,
187 * we have an extra 4 bytes.
188 * Fixing that in the kernel would break 64 bits userspace. */
189 if((stream
->value
== NULL
)
190 && ((((iwe
->len
- IW_EV_LCP_PK_LEN
) % event_len
) == 4)
191 || ((iwe
->len
== 12) && ((event_type
== IW_HEADER_TYPE_UINT
) ||
192 (event_type
== IW_HEADER_TYPE_QUAL
))) ))
194 pointer
-= event_len
;
196 /* Beware of alignement. Dest has local alignement, not packed */
197 memcpy((char *) iwe
+ IW_EV_LCP_LEN
, pointer
, event_len
);
198 pointer
+= event_len
;
201 /* Is there more value in the event ? */
202 if((pointer
+ event_len
) <= (stream
->current
+ iwe
->len
))
203 /* Go to next value */
204 stream
->value
= pointer
;
207 /* Go to next event */
208 stream
->value
= NULL
;
209 stream
->current
+= iwe
->len
;
216 static inline void wext_fill_wpa(unsigned char *iebuf
, int ielen
, struct iwinfo_scanlist_entry
*e
)
218 static unsigned char ms_oui
[3] = { 0x00, 0x50, 0xf2 };
220 while (ielen
>= 2 && ielen
>= iebuf
[1])
225 iwinfo_parse_rsn(&e
->crypto
, iebuf
+ 2, iebuf
[1],
226 IWINFO_CIPHER_CCMP
, IWINFO_KMGMT_8021x
);
229 case 221: /* Vendor */
230 if (iebuf
[1] >= 4 && !memcmp(iebuf
+ 2, ms_oui
, 3) && iebuf
[5] == 1)
231 iwinfo_parse_rsn(&e
->crypto
, iebuf
+ 6, iebuf
[1] - 4,
232 IWINFO_CIPHER_TKIP
, IWINFO_KMGMT_PSK
);
236 ielen
-= iebuf
[1] + 2;
237 iebuf
+= iebuf
[1] + 2;
242 static inline void wext_fill_entry(struct stream_descr
*stream
, struct iw_event
*event
,
243 struct iw_range
*iw_range
, int has_range
, struct iwinfo_scanlist_entry
*e
)
248 /* Now, let's decode the event */
252 memcpy(e
->mac
, &event
->u
.ap_addr
.sa_data
, 6);
256 if( event
->u
.freq
.m
>= 1000 )
258 freq
= wext_freq2float(&(event
->u
.freq
));
260 for(i
= 0; i
< iw_range
->num_frequency
; i
++)
262 if( wext_freq2float(&iw_range
->freq
[i
]) == freq
)
264 e
->channel
= iw_range
->freq
[i
].i
;
271 e
->channel
= event
->u
.freq
.m
;
277 switch(event
->u
.mode
)
280 e
->mode
= IWINFO_OPMODE_ADHOC
;
285 e
->mode
= IWINFO_OPMODE_MASTER
;
289 e
->mode
= IWINFO_OPMODE_UNKNOWN
;
296 if( event
->u
.essid
.pointer
&& event
->u
.essid
.length
&& event
->u
.essid
.flags
)
297 memcpy(e
->ssid
, event
->u
.essid
.pointer
, event
->u
.essid
.length
);
302 e
->crypto
.enabled
= !(event
->u
.data
.flags
& IW_ENCODE_DISABLED
);
306 e
->signal
= event
->u
.qual
.level
;
307 e
->quality
= event
->u
.qual
.qual
;
308 e
->quality_max
= iw_range
->max_qual
.qual
;
312 if(state
->val_index
== 0)
314 lua_pushstring(L
, "bitrates");
317 //iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
318 snprintf(buffer
, sizeof(buffer
), "%d", event
->u
.bitrate
.value
);
319 lua_pushinteger(L
, state
->val_index
+ 1);
320 lua_pushstring(L
, buffer
);
323 /* Check for termination */
324 if(stream
->value
== NULL
)
327 state
->val_index
= 0;
333 wext_fill_wpa(event
->u
.data
.pointer
, event
->u
.data
.length
, e
);
339 int wext_get_scanlist(const char *ifname
, char *buf
, int *len
)
342 struct iw_scan_req scanopt
; /* Options for 'set' */
343 unsigned char *buffer
= NULL
; /* Results */
344 int buflen
= IW_SCAN_MAX_DATA
; /* Min for compat WE<17 */
345 struct iw_range range
;
347 struct timeval tv
; /* Select timeout */
348 int timeout
= 15000000; /* 15s */
351 struct iwinfo_scanlist_entry e
;
353 wrq
.u
.data
.pointer
= (caddr_t
) &range
;
354 wrq
.u
.data
.length
= sizeof(struct iw_range
);
355 wrq
.u
.data
.flags
= 0;
357 if( wext_ioctl(ifname
, SIOCGIWRANGE
, &wrq
) >= 0 )
359 /* Init timeout value -> 250ms between set and first get */
363 /* Clean up set args */
364 memset(&scanopt
, 0, sizeof(scanopt
));
366 wrq
.u
.data
.pointer
= NULL
;
367 wrq
.u
.data
.flags
= 0;
368 wrq
.u
.data
.length
= 0;
370 /* Initiate Scanning */
371 if( wext_ioctl(ifname
, SIOCSIWSCAN
, &wrq
) >= 0 )
373 timeout
-= tv
.tv_usec
;
378 fd_set rfds
; /* File descriptors for select */
379 int last_fd
; /* Last fd */
382 /* Guess what ? We must re-generate rfds each time */
385 /* In here, add the rtnetlink fd in the list */
387 /* Wait until something happens */
388 ret
= select(last_fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
390 /* Check if there was an error */
393 if(errno
== EAGAIN
|| errno
== EINTR
)
399 /* Check if there was a timeout */
402 unsigned char *newbuf
;
405 /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
406 newbuf
= realloc(buffer
, buflen
);
417 /* Try to read the results */
418 wrq
.u
.data
.pointer
= buffer
;
419 wrq
.u
.data
.flags
= 0;
420 wrq
.u
.data
.length
= buflen
;
422 if( wext_ioctl(ifname
, SIOCGIWSCAN
, &wrq
) )
424 /* Check if buffer was too small (WE-17 only) */
425 if((errno
== E2BIG
) && (range
.we_version_compiled
> 16))
427 /* Some driver may return very large scan results, either
428 * because there are many cells, or because they have many
429 * large elements in cells (like IWEVCUSTOM). Most will
430 * only need the regular sized buffer. We now use a dynamic
431 * allocation of the buffer to satisfy everybody. Of course,
432 * as we don't know in advance the size of the array, we try
433 * various increasing sizes. Jean II */
435 /* Check if the driver gave us any hints. */
436 if(wrq
.u
.data
.length
> buflen
)
437 buflen
= wrq
.u
.data
.length
;
445 /* Check if results not available yet */
448 /* Restart timer for only 100ms*/
451 timeout
-= tv
.tv_usec
;
454 continue; /* Try again later */
462 /* We have the results, go to process them */
468 if( wrq
.u
.data
.length
)
471 struct stream_descr stream
;
475 memset(&stream
, 0, sizeof(stream
));
476 stream
.current
= (char *)buffer
;
477 stream
.end
= (char *)buffer
+ wrq
.u
.data
.length
;
481 /* Extract an event and print it */
482 ret
= wext_extract_event(&stream
, &iwe
, range
.we_version_compiled
);
486 if( (iwe
.cmd
== SIOCGIWAP
) || (ret
== 0) )
492 else if( (entrylen
+ sizeof(struct iwinfo_scanlist_entry
)) <= IWINFO_BUFSIZE
)
494 /* if encryption is off, clear the crypto strunct */
495 if( !e
.crypto
.enabled
)
496 memset(&e
.crypto
, 0, sizeof(struct iwinfo_crypto_entry
));
498 memcpy(&buf
[entrylen
], &e
, sizeof(struct iwinfo_scanlist_entry
));
499 entrylen
+= sizeof(struct iwinfo_scanlist_entry
);
503 /* we exceed the callers buffer size, abort here ... */
507 memset(&e
, 0, sizeof(struct iwinfo_scanlist_entry
));
510 wext_fill_entry(&stream
, &iwe
, &range
, has_range
, &e
);
This page took 0.076135 seconds and 5 git commands to generate.