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 buflen
, struct iwinfo_scanlist_entry
*e
)
218 int ielen
= iebuf
[1] + 2;
219 int offset
= 2; /* Skip the IE id, and the length. */
220 unsigned char wpa1_oui
[3] = {0x00, 0x50, 0xf2};
221 unsigned char wpa2_oui
[3] = {0x00, 0x0f, 0xac};
222 unsigned char *wpa_oui
;
226 int wpa1
= 0, wpa2
= 0;
229 struct iwinfo_crypto_entry
*ce
= &e
->crypto
;
236 case 0x30: /* WPA2 */
237 /* Check if we have enough data */
244 case 0xdd: /* WPA or else */
246 /* Not all IEs that start with 0xdd are WPA.
247 * * So check that the OUI is valid. */
248 if((ielen
< 8) || ((memcmp(&iebuf
[offset
], wpa_oui
, 3) != 0)
249 && (iebuf
[offset
+3] == 0x01)))
259 /* Pick version number (little endian) */
260 ver
= iebuf
[offset
] | (iebuf
[offset
+ 1] << 8);
269 if( wpa1
&& (ce
->wpa_version
== 2) )
271 else if( wpa2
&& (ce
->wpa_version
== 1) )
273 else if( wpa1
&& !ce
->wpa_version
)
275 else if( wpa2
&& !ce
->wpa_version
)
278 if(ielen
< (offset
+ 4))
280 ce
->group_ciphers
|= (1<<2); /* TKIP */
281 ce
->pair_ciphers
|= (1<<2); /* TKIP */
282 ce
->auth_suites
|= (1<<2); /* PSK */
286 if(memcmp(&iebuf
[offset
], wpa_oui
, 3) != 0)
287 ce
->group_ciphers
|= (1<<7); /* Proprietary */
289 ce
->group_ciphers
|= (1<<iebuf
[offset
+3]);
293 if(ielen
< (offset
+ 2))
295 ce
->pair_ciphers
|= (1<<2); /* TKIP */
296 ce
->auth_suites
|= (1<<2); /* PSK */
300 /* Otherwise, we have some number of pairwise ciphers. */
301 cnt
= iebuf
[offset
] | (iebuf
[offset
+ 1] << 8);
304 if(ielen
< (offset
+ 4*cnt
))
308 for(i
= 0; i
< cnt
; i
++)
310 if(memcmp(&iebuf
[offset
], wpa_oui
, 3) != 0)
311 ce
->pair_ciphers
|= (1<<7); /* Proprietary */
312 else if(iebuf
[offset
+3] <= IW_IE_CYPHER_NUM
)
313 ce
->pair_ciphers
|= (1<<iebuf
[offset
+3]);
315 // ce->pair_ciphers[ce->pair_cipher_num++] = 255; /* Unknown */
320 /* Check if we are done */
321 if(ielen
< (offset
+ 2))
324 /* Now, we have authentication suites. */
325 cnt
= iebuf
[offset
] | (iebuf
[offset
+ 1] << 8);
329 if(ielen
< (offset
+ 4*cnt
))
332 for(i
= 0; i
< cnt
; i
++)
334 if(memcmp(&iebuf
[offset
], wpa_oui
, 3) != 0)
335 ce
->auth_suites
|= (1<<7); /* Proprietary */
336 else if(iebuf
[offset
+3] <= IW_IE_KEY_MGMT_NUM
)
337 ce
->auth_suites
|= (1<<iebuf
[offset
+3]);
339 // ce->auth_suites[ce->auth_suite_num++] = 255; /* Unknown */
346 static inline void wext_fill_entry(struct stream_descr
*stream
, struct iw_event
*event
,
347 struct iw_range
*iw_range
, int has_range
, struct iwinfo_scanlist_entry
*e
)
352 /* Now, let's decode the event */
356 memcpy(e
->mac
, &event
->u
.ap_addr
.sa_data
, 6);
360 if( event
->u
.freq
.m
>= 1000 )
362 freq
= wext_freq2float(&(event
->u
.freq
));
364 for(i
= 0; i
< iw_range
->num_frequency
; i
++)
366 if( wext_freq2float(&iw_range
->freq
[i
]) == freq
)
368 e
->channel
= iw_range
->freq
[i
].i
;
375 e
->channel
= event
->u
.freq
.m
;
381 switch(event
->u
.mode
)
384 sprintf((char *) e
->mode
, "Ad-Hoc");
389 sprintf((char *) e
->mode
, "Master");
393 sprintf((char *) e
->mode
, "Unknown");
399 if( event
->u
.essid
.pointer
&& event
->u
.essid
.length
&& event
->u
.essid
.flags
)
400 memcpy(e
->ssid
, event
->u
.essid
.pointer
, event
->u
.essid
.length
);
405 e
->crypto
.enabled
= !(event
->u
.data
.flags
& IW_ENCODE_DISABLED
);
409 e
->signal
= event
->u
.qual
.level
;
410 e
->quality
= event
->u
.qual
.qual
;
411 e
->quality_max
= iw_range
->max_qual
.qual
;
415 if(state
->val_index
== 0)
417 lua_pushstring(L
, "bitrates");
420 //iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
421 snprintf(buffer
, sizeof(buffer
), "%d", event
->u
.bitrate
.value
);
422 lua_pushinteger(L
, state
->val_index
+ 1);
423 lua_pushstring(L
, buffer
);
426 /* Check for termination */
427 if(stream
->value
== NULL
)
430 state
->val_index
= 0;
438 while(i
<= (event
->u
.data
.length
- 2))
440 switch(((unsigned char *)event
->u
.data
.pointer
)[i
])
442 case 0xdd: /* WPA1 (and other) */
443 case 0x30: /* WPA2 */
444 wext_fill_wpa((unsigned char *)event
->u
.data
.pointer
+ i
,
445 event
->u
.data
.length
, e
);
450 i
+= ((unsigned char *)event
->u
.data
.pointer
)[i
+1] + 2;
458 int wext_get_scanlist(const char *ifname
, char *buf
, int *len
)
461 struct iw_scan_req scanopt
; /* Options for 'set' */
462 unsigned char *buffer
= NULL
; /* Results */
463 int buflen
= IW_SCAN_MAX_DATA
; /* Min for compat WE<17 */
464 struct iw_range range
;
466 struct timeval tv
; /* Select timeout */
467 int timeout
= 15000000; /* 15s */
470 struct iwinfo_scanlist_entry e
;
472 wrq
.u
.data
.pointer
= (caddr_t
) &range
;
473 wrq
.u
.data
.length
= sizeof(struct iw_range
);
474 wrq
.u
.data
.flags
= 0;
476 if( wext_ioctl(ifname
, SIOCGIWRANGE
, &wrq
) >= 0 )
478 /* Init timeout value -> 250ms between set and first get */
482 /* Clean up set args */
483 memset(&scanopt
, 0, sizeof(scanopt
));
485 wrq
.u
.data
.pointer
= NULL
;
486 wrq
.u
.data
.flags
= 0;
487 wrq
.u
.data
.length
= 0;
489 /* Initiate Scanning */
490 if( wext_ioctl(ifname
, SIOCSIWSCAN
, &wrq
) >= 0 )
492 timeout
-= tv
.tv_usec
;
497 fd_set rfds
; /* File descriptors for select */
498 int last_fd
; /* Last fd */
501 /* Guess what ? We must re-generate rfds each time */
504 /* In here, add the rtnetlink fd in the list */
506 /* Wait until something happens */
507 ret
= select(last_fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
509 /* Check if there was an error */
512 if(errno
== EAGAIN
|| errno
== EINTR
)
518 /* Check if there was a timeout */
521 unsigned char *newbuf
;
524 /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
525 newbuf
= realloc(buffer
, buflen
);
536 /* Try to read the results */
537 wrq
.u
.data
.pointer
= buffer
;
538 wrq
.u
.data
.flags
= 0;
539 wrq
.u
.data
.length
= buflen
;
541 if( wext_ioctl(ifname
, SIOCGIWSCAN
, &wrq
) )
543 /* Check if buffer was too small (WE-17 only) */
544 if((errno
== E2BIG
) && (range
.we_version_compiled
> 16))
546 /* Some driver may return very large scan results, either
547 * because there are many cells, or because they have many
548 * large elements in cells (like IWEVCUSTOM). Most will
549 * only need the regular sized buffer. We now use a dynamic
550 * allocation of the buffer to satisfy everybody. Of course,
551 * as we don't know in advance the size of the array, we try
552 * various increasing sizes. Jean II */
554 /* Check if the driver gave us any hints. */
555 if(wrq
.u
.data
.length
> buflen
)
556 buflen
= wrq
.u
.data
.length
;
564 /* Check if results not available yet */
567 /* Restart timer for only 100ms*/
570 timeout
-= tv
.tv_usec
;
573 continue; /* Try again later */
581 /* We have the results, go to process them */
587 if( wrq
.u
.data
.length
)
590 struct stream_descr stream
;
594 memset(&stream
, 0, sizeof(stream
));
595 stream
.current
= (char *)buffer
;
596 stream
.end
= (char *)buffer
+ wrq
.u
.data
.length
;
600 /* Extract an event and print it */
601 ret
= wext_extract_event(&stream
, &iwe
, range
.we_version_compiled
);
605 if( (iwe
.cmd
== SIOCGIWAP
) || (ret
== 0) )
611 else if( (entrylen
+ sizeof(struct iwinfo_scanlist_entry
)) <= IWINFO_BUFSIZE
)
613 /* if encryption is off, clear the crypto strunct */
614 if( !e
.crypto
.enabled
)
615 memset(&e
.crypto
, 0, sizeof(struct iwinfo_crypto_entry
));
617 memcpy(&buf
[entrylen
], &e
, sizeof(struct iwinfo_scanlist_entry
));
618 entrylen
+= sizeof(struct iwinfo_scanlist_entry
);
622 /* we exceed the callers buffer size, abort here ... */
626 memset(&e
, 0, sizeof(struct iwinfo_scanlist_entry
));
629 wext_fill_entry(&stream
, &iwe
, &range
, has_range
, &e
);
This page took 0.105081 seconds and 5 git commands to generate.