nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * Wireless Tools
3 *
4 * Jean II - HPLB 97->99 - HPL 99->07
5 *
6 * Common subroutines to all the wireless tools...
7 *
8 * This file is released under the GPL license.
9 * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
10 */
11  
12 /***************************** INCLUDES *****************************/
13  
14 #include "iwlib.h" /* Header */
15  
16 /************************ CONSTANTS & MACROS ************************/
17  
18 /*
19 * Constants fof WE-9->15
20 */
21 #define IW15_MAX_FREQUENCIES 16
22 #define IW15_MAX_BITRATES 8
23 #define IW15_MAX_TXPOWER 8
24 #define IW15_MAX_ENCODING_SIZES 8
25 #define IW15_MAX_SPY 8
26 #define IW15_MAX_AP 8
27  
28 /****************************** TYPES ******************************/
29  
30 /*
31 * Struct iw_range up to WE-15
32 */
33 struct iw15_range
34 {
35 __u32 throughput;
36 __u32 min_nwid;
37 __u32 max_nwid;
38 __u16 num_channels;
39 __u8 num_frequency;
40 struct iw_freq freq[IW15_MAX_FREQUENCIES];
41 __s32 sensitivity;
42 struct iw_quality max_qual;
43 __u8 num_bitrates;
44 __s32 bitrate[IW15_MAX_BITRATES];
45 __s32 min_rts;
46 __s32 max_rts;
47 __s32 min_frag;
48 __s32 max_frag;
49 __s32 min_pmp;
50 __s32 max_pmp;
51 __s32 min_pmt;
52 __s32 max_pmt;
53 __u16 pmp_flags;
54 __u16 pmt_flags;
55 __u16 pm_capa;
56 __u16 encoding_size[IW15_MAX_ENCODING_SIZES];
57 __u8 num_encoding_sizes;
58 __u8 max_encoding_tokens;
59 __u16 txpower_capa;
60 __u8 num_txpower;
61 __s32 txpower[IW15_MAX_TXPOWER];
62 __u8 we_version_compiled;
63 __u8 we_version_source;
64 __u16 retry_capa;
65 __u16 retry_flags;
66 __u16 r_time_flags;
67 __s32 min_retry;
68 __s32 max_retry;
69 __s32 min_r_time;
70 __s32 max_r_time;
71 struct iw_quality avg_qual;
72 };
73  
74 /*
75 * Union for all the versions of iwrange.
76 * Fortunately, I mostly only add fields at the end, and big-bang
77 * reorganisations are few.
78 */
79 union iw_range_raw
80 {
81 struct iw15_range range15; /* WE 9->15 */
82 struct iw_range range; /* WE 16->current */
83 };
84  
85 /*
86 * Offsets in iw_range struct
87 */
88 #define iwr15_off(f) ( ((char *) &(((struct iw15_range *) NULL)->f)) - \
89 (char *) NULL)
90 #define iwr_off(f) ( ((char *) &(((struct iw_range *) NULL)->f)) - \
91 (char *) NULL)
92  
93 /**************************** VARIABLES ****************************/
94  
95 /* Modes as human readable strings */
96 const char * const iw_operation_mode[] = { "Auto",
97 "Ad-Hoc",
98 "Managed",
99 "Master",
100 "Repeater",
101 "Secondary",
102 "Monitor",
103 "Unknown/bug" };
104  
105 /* Modulations as human readable strings */
106 const struct iw_modul_descr iw_modul_list[] = {
107 /* Start with aggregate types, so that they display first */
108 { IW_MODUL_11AG, "11ag",
109 "IEEE 802.11a + 802.11g (2.4 & 5 GHz, up to 54 Mb/s)" },
110 { IW_MODUL_11AB, "11ab",
111 "IEEE 802.11a + 802.11b (2.4 & 5 GHz, up to 54 Mb/s)" },
112 { IW_MODUL_11G, "11g", "IEEE 802.11g (2.4 GHz, up to 54 Mb/s)" },
113 { IW_MODUL_11A, "11a", "IEEE 802.11a (5 GHz, up to 54 Mb/s)" },
114 { IW_MODUL_11B, "11b", "IEEE 802.11b (2.4 GHz, up to 11 Mb/s)" },
115  
116 /* Proprietary aggregates */
117 { IW_MODUL_TURBO | IW_MODUL_11A, "turboa",
118 "Atheros turbo mode at 5 GHz (up to 108 Mb/s)" },
119 { IW_MODUL_TURBO | IW_MODUL_11G, "turbog",
120 "Atheros turbo mode at 2.4 GHz (up to 108 Mb/s)" },
121 { IW_MODUL_PBCC | IW_MODUL_11B, "11+",
122 "TI 802.11+ (2.4 GHz, up to 22 Mb/s)" },
123  
124 /* Individual modulations */
125 { IW_MODUL_OFDM_G, "OFDMg",
126 "802.11g higher rates, OFDM at 2.4 GHz (up to 54 Mb/s)" },
127 { IW_MODUL_OFDM_A, "OFDMa", "802.11a, OFDM at 5 GHz (up to 54 Mb/s)" },
128 { IW_MODUL_CCK, "CCK", "802.11b higher rates (2.4 GHz, up to 11 Mb/s)" },
129 { IW_MODUL_DS, "DS", "802.11 Direct Sequence (2.4 GHz, up to 2 Mb/s)" },
130 { IW_MODUL_FH, "FH", "802.11 Frequency Hopping (2,4 GHz, up to 2 Mb/s)" },
131  
132 /* Proprietary modulations */
133 { IW_MODUL_TURBO, "turbo",
134 "Atheros turbo mode, channel bonding (up to 108 Mb/s)" },
135 { IW_MODUL_PBCC, "PBCC",
136 "TI 802.11+ higher rates (2.4 GHz, up to 22 Mb/s)" },
137 { IW_MODUL_CUSTOM, "custom",
138 "Driver specific modulation (check driver documentation)" },
139 };
140  
141 /* Disable runtime version warning in iw_get_range_info() */
142 int iw_ignore_version = 0;
143  
144 /************************ SOCKET SUBROUTINES *************************/
145  
146 /*------------------------------------------------------------------*/
147 /*
148 * Open a socket.
149 * Depending on the protocol present, open the right socket. The socket
150 * will allow us to talk to the driver.
151 */
152 int
153 iw_sockets_open(void)
154 {
155 static const int families[] = {
156 AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
157 };
158 unsigned int i;
159 int sock;
160  
161 /*
162 * Now pick any (exisiting) useful socket family for generic queries
163 * Note : don't open all the socket, only returns when one matches,
164 * all protocols might not be valid.
165 * Workaround by Jim Kaba <jkaba@sarnoff.com>
166 * Note : in 99% of the case, we will just open the inet_sock.
167 * The remaining 1% case are not fully correct...
168 */
169  
170 /* Try all families we support */
171 for(i = 0; i < sizeof(families)/sizeof(int); ++i)
172 {
173 /* Try to open the socket, if success returns it */
174 sock = socket(families[i], SOCK_DGRAM, 0);
175 if(sock >= 0)
176 return sock;
177 }
178  
179 return -1;
180 }
181  
182 /*------------------------------------------------------------------*/
183 /*
184 * Extract the interface name out of /proc/net/wireless or /proc/net/dev.
185 */
186 static inline char *
187 iw_get_ifname(char * name, /* Where to store the name */
188 int nsize, /* Size of name buffer */
189 char * buf) /* Current position in buffer */
190 {
191 char * end;
192  
193 /* Skip leading spaces */
194 while(isspace(*buf))
195 buf++;
196  
197 #ifndef IW_RESTRIC_ENUM
198 /* Get name up to the last ':'. Aliases may contain ':' in them,
199 * but the last one should be the separator */
200 end = strrchr(buf, ':');
201 #else
202 /* Get name up to ": "
203 * Note : we compare to ": " to make sure to process aliased interfaces
204 * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
205 * a ' ' after the ':'*/
206 end = strstr(buf, ": ");
207 #endif
208  
209 /* Not found ??? To big ??? */
210 if((end == NULL) || (((end - buf) + 1) > nsize))
211 return(NULL);
212  
213 /* Copy */
214 memcpy(name, buf, (end - buf));
215 name[end - buf] = '\0';
216  
217 /* Return value currently unused, just make sure it's non-NULL */
218 return(end);
219 }
220  
221 /*------------------------------------------------------------------*/
222 /*
223 * Enumerate devices and call specified routine
224 * The new way just use /proc/net/wireless, so get all wireless interfaces,
225 * whether configured or not. This is the default if available.
226 * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
227 * or not).
228 */
229 void
230 iw_enum_devices(int skfd,
231 iw_enum_handler fn,
232 char * args[],
233 int count)
234 {
235 char buff[1024];
236 FILE * fh;
237 struct ifconf ifc;
238 struct ifreq *ifr;
239 int i;
240  
241 #ifndef IW_RESTRIC_ENUM
242 /* Check if /proc/net/dev is available */
243 fh = fopen(PROC_NET_DEV, "r");
244 #else
245 /* Check if /proc/net/wireless is available */
246 fh = fopen(PROC_NET_WIRELESS, "r");
247 #endif
248  
249 if(fh != NULL)
250 {
251 /* Success : use data from /proc/net/wireless */
252  
253 /* Eat 2 lines of header */
254 fgets(buff, sizeof(buff), fh);
255 fgets(buff, sizeof(buff), fh);
256  
257 /* Read each device line */
258 while(fgets(buff, sizeof(buff), fh))
259 {
260 char name[IFNAMSIZ + 1];
261 char *s;
262  
263 /* Skip empty or almost empty lines. It seems that in some
264 * cases fgets return a line with only a newline. */
265 if((buff[0] == '\0') || (buff[1] == '\0'))
266 continue;
267  
268 /* Extract interface name */
269 s = iw_get_ifname(name, sizeof(name), buff);
270  
271 if(!s)
272 {
273 /* Failed to parse, complain and continue */
274 #ifndef IW_RESTRIC_ENUM
275 fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
276 #else
277 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
278 #endif
279 }
280 else
281 /* Got it, print info about this interface */
282 (*fn)(skfd, name, args, count);
283 }
284  
285 fclose(fh);
286 }
287 else
288 {
289 /* Get list of configured devices using "traditional" way */
290 ifc.ifc_len = sizeof(buff);
291 ifc.ifc_buf = buff;
292 if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
293 {
294 fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
295 return;
296 }
297 ifr = ifc.ifc_req;
298  
299 /* Print them */
300 for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
301 (*fn)(skfd, ifr->ifr_name, args, count);
302 }
303 }
304  
305 /*********************** WIRELESS SUBROUTINES ************************/
306  
307 /*------------------------------------------------------------------*/
308 /*
309 * Extract WE version number from /proc/net/wireless
310 * In most cases, you really want to get version information from
311 * the range info (range->we_version_compiled), see below...
312 *
313 * If we have WE-16 and later, the WE version is available at the
314 * end of the header line of the file.
315 * For version prior to that, we can only detect the change from
316 * v11 to v12, so we do an approximate job. Fortunately, v12 to v15
317 * are highly binary compatible (on the struct level).
318 */
319 int
320 iw_get_kernel_we_version(void)
321 {
322 char buff[1024];
323 FILE * fh;
324 char * p;
325 int v;
326  
327 /* Check if /proc/net/wireless is available */
328 fh = fopen(PROC_NET_WIRELESS, "r");
329  
330 if(fh == NULL)
331 {
332 fprintf(stderr, "Cannot read " PROC_NET_WIRELESS "\n");
333 return(-1);
334 }
335  
336 /* Read the first line of buffer */
337 fgets(buff, sizeof(buff), fh);
338  
339 if(strstr(buff, "| WE") == NULL)
340 {
341 /* Prior to WE16, so explicit version not present */
342  
343 /* Black magic */
344 if(strstr(buff, "| Missed") == NULL)
345 v = 11;
346 else
347 v = 15;
348 fclose(fh);
349 return(v);
350 }
351  
352 /* Read the second line of buffer */
353 fgets(buff, sizeof(buff), fh);
354  
355 /* Get to the last separator, to get the version */
356 p = strrchr(buff, '|');
357 if((p == NULL) || (sscanf(p + 1, "%d", &v) != 1))
358 {
359 fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
360 fclose(fh);
361 return(-1);
362 }
363  
364 fclose(fh);
365 return(v);
366 }
367  
368 /*------------------------------------------------------------------*/
369 /*
370 * Print the WE versions of the interface.
371 */
372 static int
373 print_iface_version_info(int skfd,
374 char * ifname,
375 char * args[], /* Command line args */
376 int count) /* Args count */
377 {
378 struct iwreq wrq;
379 char buffer[sizeof(iwrange) * 2]; /* Large enough */
380 struct iw_range * range;
381  
382 /* Avoid "Unused parameter" warning */
383 args = args; count = count;
384  
385 /* If no wireless name : no wireless extensions.
386 * This enable us to treat the SIOCGIWRANGE failure below properly. */
387 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
388 return(-1);
389  
390 /* Cleanup */
391 memset(buffer, 0, sizeof(buffer));
392  
393 wrq.u.data.pointer = (caddr_t) buffer;
394 wrq.u.data.length = sizeof(buffer);
395 wrq.u.data.flags = 0;
396 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
397 {
398 /* Interface support WE (see above), but not IWRANGE */
399 fprintf(stderr, "%-8.16s Driver has no Wireless Extension version information.\n\n", ifname);
400 return(0);
401 }
402  
403 /* Copy stuff at the right place, ignore extra */
404 range = (struct iw_range *) buffer;
405  
406 /* For new versions, we can check the version directly, for old versions
407 * we use magic. 300 bytes is a also magic number, don't touch... */
408 if(wrq.u.data.length >= 300)
409 {
410 /* Version is always at the same offset, so it's ok */
411 printf("%-8.16s Recommend Wireless Extension v%d or later,\n",
412 ifname, range->we_version_source);
413 printf(" Currently compiled with Wireless Extension v%d.\n\n",
414 range->we_version_compiled);
415 }
416 else
417 {
418 fprintf(stderr, "%-8.16s Wireless Extension version too old.\n\n",
419 ifname);
420 }
421  
422  
423 return(0);
424 }
425  
426 /*------------------------------------------------------------------*/
427 /*
428 * Print the WE versions of the tools.
429 */
430 int
431 iw_print_version_info(const char * toolname)
432 {
433 int skfd; /* generic raw socket desc. */
434 int we_kernel_version;
435  
436 /* Create a channel to the NET kernel. */
437 if((skfd = iw_sockets_open()) < 0)
438 {
439 perror("socket");
440 return -1;
441 }
442  
443 /* Information about the tools themselves */
444 if(toolname != NULL)
445 printf("%-8.16s Wireless-Tools version %d\n", toolname, WT_VERSION);
446 printf(" Compatible with Wireless Extension v11 to v%d.\n\n",
447 WE_MAX_VERSION);
448  
449 /* Get version from kernel */
450 we_kernel_version = iw_get_kernel_we_version();
451 /* Only version >= 16 can be verified, other are guessed */
452 if(we_kernel_version > 15)
453 printf("Kernel Currently compiled with Wireless Extension v%d.\n\n",
454 we_kernel_version);
455  
456 /* Version for each device */
457 iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
458  
459 iw_sockets_close(skfd);
460  
461 return 0;
462 }
463  
464 /*------------------------------------------------------------------*/
465 /*
466 * Get the range information out of the driver
467 */
468 int
469 iw_get_range_info(int skfd,
470 const char * ifname,
471 iwrange * range)
472 {
473 struct iwreq wrq;
474 char buffer[sizeof(iwrange) * 2]; /* Large enough */
475 union iw_range_raw * range_raw;
476  
477 /* Cleanup */
478 bzero(buffer, sizeof(buffer));
479  
480 wrq.u.data.pointer = (caddr_t) buffer;
481 wrq.u.data.length = sizeof(buffer);
482 wrq.u.data.flags = 0;
483 if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
484 return(-1);
485  
486 /* Point to the buffer */
487 range_raw = (union iw_range_raw *) buffer;
488  
489 /* For new versions, we can check the version directly, for old versions
490 * we use magic. 300 bytes is a also magic number, don't touch... */
491 if(wrq.u.data.length < 300)
492 {
493 /* That's v10 or earlier. Ouch ! Let's make a guess...*/
494 range_raw->range.we_version_compiled = 9;
495 }
496  
497 /* Check how it needs to be processed */
498 if(range_raw->range.we_version_compiled > 15)
499 {
500 /* This is our native format, that's easy... */
501 /* Copy stuff at the right place, ignore extra */
502 memcpy((char *) range, buffer, sizeof(iwrange));
503 }
504 else
505 {
506 /* Zero unknown fields */
507 bzero((char *) range, sizeof(struct iw_range));
508  
509 /* Initial part unmoved */
510 memcpy((char *) range,
511 buffer,
512 iwr15_off(num_channels));
513 /* Frequencies pushed futher down towards the end */
514 memcpy((char *) range + iwr_off(num_channels),
515 buffer + iwr15_off(num_channels),
516 iwr15_off(sensitivity) - iwr15_off(num_channels));
517 /* This one moved up */
518 memcpy((char *) range + iwr_off(sensitivity),
519 buffer + iwr15_off(sensitivity),
520 iwr15_off(num_bitrates) - iwr15_off(sensitivity));
521 /* This one goes after avg_qual */
522 memcpy((char *) range + iwr_off(num_bitrates),
523 buffer + iwr15_off(num_bitrates),
524 iwr15_off(min_rts) - iwr15_off(num_bitrates));
525 /* Number of bitrates has changed, put it after */
526 memcpy((char *) range + iwr_off(min_rts),
527 buffer + iwr15_off(min_rts),
528 iwr15_off(txpower_capa) - iwr15_off(min_rts));
529 /* Added encoding_login_index, put it after */
530 memcpy((char *) range + iwr_off(txpower_capa),
531 buffer + iwr15_off(txpower_capa),
532 iwr15_off(txpower) - iwr15_off(txpower_capa));
533 /* Hum... That's an unexpected glitch. Bummer. */
534 memcpy((char *) range + iwr_off(txpower),
535 buffer + iwr15_off(txpower),
536 iwr15_off(avg_qual) - iwr15_off(txpower));
537 /* Avg qual moved up next to max_qual */
538 memcpy((char *) range + iwr_off(avg_qual),
539 buffer + iwr15_off(avg_qual),
540 sizeof(struct iw_quality));
541 }
542  
543 /* We are now checking much less than we used to do, because we can
544 * accomodate more WE version. But, there are still cases where things
545 * will break... */
546 if(!iw_ignore_version)
547 {
548 /* We don't like very old version (unfortunately kernel 2.2.X) */
549 if(range->we_version_compiled <= 10)
550 {
551 fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname);
552 fprintf(stderr, "of Wireless Extension, while this program support version 11 and later.\n");
553 fprintf(stderr, "Some things may be broken...\n\n");
554 }
555  
556 /* We don't like future versions of WE, because we can't cope with
557 * the unknown */
558 if(range->we_version_compiled > WE_MAX_VERSION)
559 {
560 fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
561 fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_MAX_VERSION);
562 fprintf(stderr, "Some things may be broken...\n\n");
563 }
564  
565 /* Driver version verification */
566 if((range->we_version_compiled > 10) &&
567 (range->we_version_compiled < range->we_version_source))
568 {
569 fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", ifname, range->we_version_source);
570 fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled);
571 fprintf(stderr, "may not be available...\n\n");
572 }
573 /* Note : we are only trying to catch compile difference, not source.
574 * If the driver source has not been updated to the latest, it doesn't
575 * matter because the new fields are set to zero */
576 }
577  
578 /* Don't complain twice.
579 * In theory, the test apply to each individual driver, but usually
580 * all drivers are compiled from the same kernel. */
581 iw_ignore_version = 1;
582  
583 return(0);
584 }
585  
586 /*------------------------------------------------------------------*/
587 /*
588 * Get information about what private ioctls are supported by the driver
589 *
590 * Note : there is one danger using this function. If it return 0, you
591 * still need to free() the buffer. Beware.
592 */
593 int
594 iw_get_priv_info(int skfd,
595 const char * ifname,
596 iwprivargs ** ppriv)
597 {
598 struct iwreq wrq;
599 iwprivargs * priv = NULL; /* Not allocated yet */
600 int maxpriv = 16; /* Minimum for compatibility WE<13 */
601 iwprivargs * newpriv;
602  
603 /* Some driver may return a very large number of ioctls. Some
604 * others a very small number. We now use a dynamic allocation
605 * of the array to satisfy everybody. Of course, as we don't know
606 * in advance the size of the array, we try various increasing
607 * sizes. Jean II */
608 do
609 {
610 /* (Re)allocate the buffer */
611 newpriv = realloc(priv, maxpriv * sizeof(priv[0]));
612 if(newpriv == NULL)
613 {
614 fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
615 break;
616 }
617 priv = newpriv;
618  
619 /* Ask the driver if it's large enough */
620 wrq.u.data.pointer = (caddr_t) priv;
621 wrq.u.data.length = maxpriv;
622 wrq.u.data.flags = 0;
623 if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) >= 0)
624 {
625 /* Success. Pass the buffer by pointer */
626 *ppriv = priv;
627 /* Return the number of ioctls */
628 return(wrq.u.data.length);
629 }
630  
631 /* Only E2BIG means the buffer was too small, abort on other errors */
632 if(errno != E2BIG)
633 {
634 /* Most likely "not supported". Don't barf. */
635 break;
636 }
637  
638 /* Failed. We probably need a bigger buffer. Check if the kernel
639 * gave us any hints. */
640 if(wrq.u.data.length > maxpriv)
641 maxpriv = wrq.u.data.length;
642 else
643 maxpriv *= 2;
644 }
645 while(maxpriv < 1000);
646  
647 /* Cleanup */
648 if(priv)
649 free(priv);
650 *ppriv = NULL;
651  
652 return(-1);
653 }
654  
655 /*------------------------------------------------------------------*/
656 /*
657 * Get essential wireless config from the device driver
658 * We will call all the classical wireless ioctl on the driver through
659 * the socket to know what is supported and to get the settings...
660 * Note : compare to the version in iwconfig, we extract only
661 * what's *really* needed to configure a device...
662 */
663 int
664 iw_get_basic_config(int skfd,
665 const char * ifname,
666 wireless_config * info)
667 {
668 struct iwreq wrq;
669  
670 memset((char *) info, 0, sizeof(struct wireless_config));
671  
672 /* Get wireless name */
673 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
674 /* If no wireless name : no wireless extensions */
675 return(-1);
676 else
677 {
678 strncpy(info->name, wrq.u.name, IFNAMSIZ);
679 info->name[IFNAMSIZ] = '\0';
680 }
681  
682 /* Get network ID */
683 if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
684 {
685 info->has_nwid = 1;
686 memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
687 }
688  
689 /* Get frequency / channel */
690 if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
691 {
692 info->has_freq = 1;
693 info->freq = iw_freq2float(&(wrq.u.freq));
694 info->freq_flags = wrq.u.freq.flags;
695 }
696  
697 /* Get encryption information */
698 wrq.u.data.pointer = (caddr_t) info->key;
699 wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
700 wrq.u.data.flags = 0;
701 if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
702 {
703 info->has_key = 1;
704 info->key_size = wrq.u.data.length;
705 info->key_flags = wrq.u.data.flags;
706 }
707  
708 /* Get ESSID */
709 wrq.u.essid.pointer = (caddr_t) info->essid;
710 wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
711 wrq.u.essid.flags = 0;
712 if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
713 {
714 info->has_essid = 1;
715 info->essid_on = wrq.u.data.flags;
716 }
717  
718 /* Get operation mode */
719 if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
720 {
721 info->has_mode = 1;
722 /* Note : event->u.mode is unsigned, no need to check <= 0 */
723 if(wrq.u.mode < IW_NUM_OPER_MODE)
724 info->mode = wrq.u.mode;
725 else
726 info->mode = IW_NUM_OPER_MODE; /* Unknown/bug */
727 }
728  
729 return(0);
730 }
731  
732 /*------------------------------------------------------------------*/
733 /*
734 * Set essential wireless config in the device driver
735 * We will call all the classical wireless ioctl on the driver through
736 * the socket to know what is supported and to set the settings...
737 * We support only the restricted set as above...
738 */
739 int
740 iw_set_basic_config(int skfd,
741 const char * ifname,
742 wireless_config * info)
743 {
744 struct iwreq wrq;
745 int ret = 0;
746  
747 /* Get wireless name (check if interface is valid) */
748 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
749 /* If no wireless name : no wireless extensions */
750 return(-2);
751  
752 /* Set the current mode of operation
753 * Mode need to be first : some settings apply only in a specific mode
754 * (such as frequency).
755 */
756 if(info->has_mode)
757 {
758 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
759 wrq.u.mode = info->mode;
760  
761 if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
762 {
763 fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
764 ret = -1;
765 }
766 }
767  
768 /* Set frequency / channel */
769 if(info->has_freq)
770 {
771 iw_float2freq(info->freq, &(wrq.u.freq));
772  
773 if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
774 {
775 fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
776 ret = -1;
777 }
778 }
779  
780 /* Set encryption information */
781 if(info->has_key)
782 {
783 int flags = info->key_flags;
784  
785 /* Check if there is a key index */
786 if((flags & IW_ENCODE_INDEX) > 0)
787 {
788 /* Set the index */
789 wrq.u.data.pointer = (caddr_t) NULL;
790 wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
791 wrq.u.data.length = 0;
792  
793 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
794 {
795 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
796 errno, strerror(errno));
797 ret = -1;
798 }
799 }
800  
801 /* Mask out index to minimise probability of reject when setting key */
802 flags = flags & (~IW_ENCODE_INDEX);
803  
804 /* Set the key itself (set current key in this case) */
805 wrq.u.data.pointer = (caddr_t) info->key;
806 wrq.u.data.length = info->key_size;
807 wrq.u.data.flags = flags;
808  
809 /* Compatibility with WE<13 */
810 if(flags & IW_ENCODE_NOKEY)
811 wrq.u.data.pointer = NULL;
812  
813 if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
814 {
815 fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
816 errno, strerror(errno));
817 ret = -1;
818 }
819 }
820  
821 /* Set Network ID, if available (this is for non-802.11 cards) */
822 if(info->has_nwid)
823 {
824 memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
825 wrq.u.nwid.fixed = 1; /* Hum... When in Rome... */
826  
827 if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
828 {
829 fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
830 ret = -1;
831 }
832 }
833  
834 /* Set ESSID (extended network), if available.
835 * ESSID need to be last : most device re-perform the scanning/discovery
836 * when this is set, and things like encryption keys are better be
837 * defined if we want to discover the right set of APs/nodes.
838 */
839 if(info->has_essid)
840 {
841 int we_kernel_version;
842 we_kernel_version = iw_get_kernel_we_version();
843  
844 wrq.u.essid.pointer = (caddr_t) info->essid;
845 wrq.u.essid.length = strlen(info->essid);
846 wrq.u.data.flags = info->essid_on;
847 if(we_kernel_version < 21)
848 wrq.u.essid.length++;
849  
850 if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
851 {
852 fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
853 ret = -1;
854 }
855 }
856  
857 return(ret);
858 }
859  
860 /*********************** PROTOCOL SUBROUTINES ***********************/
861 /*
862 * Fun stuff with protocol identifiers (SIOCGIWNAME).
863 * We assume that drivers are returning sensible values in there,
864 * which is not always the case :-(
865 */
866  
867 /*------------------------------------------------------------------*/
868 /*
869 * Compare protocol identifiers.
870 * We don't want to know if the two protocols are the exactly same,
871 * but if they interoperate at some level, and also if they accept the
872 * same type of config (ESSID vs NWID, freq...).
873 * This is supposed to work around the alphabet soup.
874 * Return 1 if protocols are compatible, 0 otherwise
875 */
876 int
877 iw_protocol_compare(const char * protocol1,
878 const char * protocol2)
879 {
880 const char * dot11 = "IEEE 802.11";
881 const char * dot11_ds = "Dbg";
882 const char * dot11_5g = "a";
883  
884 /* If the strings are the same -> easy */
885 if(!strncmp(protocol1, protocol2, IFNAMSIZ))
886 return(1);
887  
888 /* Are we dealing with one of the 802.11 variant ? */
889 if( (!strncmp(protocol1, dot11, strlen(dot11))) &&
890 (!strncmp(protocol2, dot11, strlen(dot11))) )
891 {
892 const char * sub1 = protocol1 + strlen(dot11);
893 const char * sub2 = protocol2 + strlen(dot11);
894 unsigned int i;
895 int isds1 = 0;
896 int isds2 = 0;
897 int is5g1 = 0;
898 int is5g2 = 0;
899  
900 /* Check if we find the magic letters telling it's DS compatible */
901 for(i = 0; i < strlen(dot11_ds); i++)
902 {
903 if(strchr(sub1, dot11_ds[i]) != NULL)
904 isds1 = 1;
905 if(strchr(sub2, dot11_ds[i]) != NULL)
906 isds2 = 1;
907 }
908 if(isds1 && isds2)
909 return(1);
910  
911 /* Check if we find the magic letters telling it's 5GHz compatible */
912 for(i = 0; i < strlen(dot11_5g); i++)
913 {
914 if(strchr(sub1, dot11_5g[i]) != NULL)
915 is5g1 = 1;
916 if(strchr(sub2, dot11_5g[i]) != NULL)
917 is5g2 = 1;
918 }
919 if(is5g1 && is5g2)
920 return(1);
921 }
922 /* Not compatible */
923 return(0);
924 }
925  
926 /********************** FREQUENCY SUBROUTINES ***********************/
927 /*
928 * Note : the two functions below are the cause of troubles on
929 * various embeeded platforms, as they are the reason we require
930 * libm (math library).
931 * In this case, please use enable BUILD_NOLIBM in the makefile
932 *
933 * FIXME : check negative mantissa and exponent
934 */
935  
936 /*------------------------------------------------------------------*/
937 /*
938 * Convert a floating point the our internal representation of
939 * frequencies.
940 * The kernel doesn't want to hear about floating point, so we use
941 * this custom format instead.
942 */
943 void
944 iw_float2freq(double in,
945 iwfreq * out)
946 {
947 #ifdef WE_NOLIBM
948 /* Version without libm : slower */
949 out->e = 0;
950 while(in > 1e9)
951 {
952 in /= 10;
953 out->e++;
954 }
955 out->m = (long) in;
956 #else /* WE_NOLIBM */
957 /* Version with libm : faster */
958 out->e = (short) (floor(log10(in)));
959 if(out->e > 8)
960 {
961 out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
962 out->e -= 8;
963 }
964 else
965 {
966 out->m = (long) in;
967 out->e = 0;
968 }
969 #endif /* WE_NOLIBM */
970 }
971  
972 /*------------------------------------------------------------------*/
973 /*
974 * Convert our internal representation of frequencies to a floating point.
975 */
976 double
977 iw_freq2float(const iwfreq * in)
978 {
979 #ifdef WE_NOLIBM
980 /* Version without libm : slower */
981 int i;
982 double res = (double) in->m;
983 for(i = 0; i < in->e; i++)
984 res *= 10;
985 return(res);
986 #else /* WE_NOLIBM */
987 /* Version with libm : faster */
988 return ((double) in->m) * pow(10,in->e);
989 #endif /* WE_NOLIBM */
990 }
991  
992 /*------------------------------------------------------------------*/
993 /*
994 * Output a frequency with proper scaling
995 */
996 void
997 iw_print_freq_value(char * buffer,
998 int buflen,
999 double freq)
1000 {
1001 if(freq < KILO)
1002 snprintf(buffer, buflen, "%g", freq);
1003 else
1004 {
1005 char scale;
1006 int divisor;
1007  
1008 if(freq >= GIGA)
1009 {
1010 scale = 'G';
1011 divisor = GIGA;
1012 }
1013 else
1014 {
1015 if(freq >= MEGA)
1016 {
1017 scale = 'M';
1018 divisor = MEGA;
1019 }
1020 else
1021 {
1022 scale = 'k';
1023 divisor = KILO;
1024 }
1025 }
1026 snprintf(buffer, buflen, "%g %cHz", freq / divisor, scale);
1027 }
1028 }
1029  
1030 /*------------------------------------------------------------------*/
1031 /*
1032 * Output a frequency with proper scaling
1033 */
1034 void
1035 iw_print_freq(char * buffer,
1036 int buflen,
1037 double freq,
1038 int channel,
1039 int freq_flags)
1040 {
1041 char sep = ((freq_flags & IW_FREQ_FIXED) ? '=' : ':');
1042 char vbuf[16];
1043  
1044 /* Print the frequency/channel value */
1045 iw_print_freq_value(vbuf, sizeof(vbuf), freq);
1046  
1047 /* Check if channel only */
1048 if(freq < KILO)
1049 snprintf(buffer, buflen, "Channel%c%s", sep, vbuf);
1050 else
1051 {
1052 /* Frequency. Check if we have a channel as well */
1053 if(channel >= 0)
1054 snprintf(buffer, buflen, "Frequency%c%s (Channel %d)",
1055 sep, vbuf, channel);
1056 else
1057 snprintf(buffer, buflen, "Frequency%c%s", sep, vbuf);
1058 }
1059 }
1060  
1061 /*------------------------------------------------------------------*/
1062 /*
1063 * Convert a frequency to a channel (negative -> error)
1064 */
1065 int
1066 iw_freq_to_channel(double freq,
1067 const struct iw_range * range)
1068 {
1069 double ref_freq;
1070 int k;
1071  
1072 /* Check if it's a frequency or not already a channel */
1073 if(freq < KILO)
1074 return(-1);
1075  
1076 /* We compare the frequencies as double to ignore differences
1077 * in encoding. Slower, but safer... */
1078 for(k = 0; k < range->num_frequency; k++)
1079 {
1080 ref_freq = iw_freq2float(&(range->freq[k]));
1081 if(freq == ref_freq)
1082 return(range->freq[k].i);
1083 }
1084 /* Not found */
1085 return(-2);
1086 }
1087  
1088 /*------------------------------------------------------------------*/
1089 /*
1090 * Convert a channel to a frequency (negative -> error)
1091 * Return the channel on success
1092 */
1093 int
1094 iw_channel_to_freq(int channel,
1095 double * pfreq,
1096 const struct iw_range * range)
1097 {
1098 int has_freq = 0;
1099 int k;
1100  
1101 /* Check if the driver support only channels or if it has frequencies */
1102 for(k = 0; k < range->num_frequency; k++)
1103 {
1104 if((range->freq[k].e != 0) || (range->freq[k].m > (int) KILO))
1105 has_freq = 1;
1106 }
1107 if(!has_freq)
1108 return(-1);
1109  
1110 /* Find the correct frequency in the list */
1111 for(k = 0; k < range->num_frequency; k++)
1112 {
1113 if(range->freq[k].i == channel)
1114 {
1115 *pfreq = iw_freq2float(&(range->freq[k]));
1116 return(channel);
1117 }
1118 }
1119 /* Not found */
1120 return(-2);
1121 }
1122  
1123 /*********************** BITRATE SUBROUTINES ***********************/
1124  
1125 /*------------------------------------------------------------------*/
1126 /*
1127 * Output a bitrate with proper scaling
1128 */
1129 void
1130 iw_print_bitrate(char * buffer,
1131 int buflen,
1132 int bitrate)
1133 {
1134 double rate = bitrate;
1135 char scale;
1136 int divisor;
1137  
1138 if(rate >= GIGA)
1139 {
1140 scale = 'G';
1141 divisor = GIGA;
1142 }
1143 else
1144 {
1145 if(rate >= MEGA)
1146 {
1147 scale = 'M';
1148 divisor = MEGA;
1149 }
1150 else
1151 {
1152 scale = 'k';
1153 divisor = KILO;
1154 }
1155 }
1156 snprintf(buffer, buflen, "%g %cb/s", rate / divisor, scale);
1157 }
1158  
1159 /************************ POWER SUBROUTINES *************************/
1160  
1161 /*------------------------------------------------------------------*/
1162 /*
1163 * Convert a value in dBm to a value in milliWatt.
1164 */
1165 int
1166 iw_dbm2mwatt(int in)
1167 {
1168 #ifdef WE_NOLIBM
1169 /* Version without libm : slower */
1170 int ip = in / 10;
1171 int fp = in % 10;
1172 int k;
1173 double res = 1.0;
1174  
1175 /* Split integral and floating part to avoid accumulating rounding errors */
1176 for(k = 0; k < ip; k++)
1177 res *= 10;
1178 for(k = 0; k < fp; k++)
1179 res *= LOG10_MAGIC;
1180 return((int) res);
1181 #else /* WE_NOLIBM */
1182 /* Version with libm : faster */
1183 return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
1184 #endif /* WE_NOLIBM */
1185 }
1186  
1187 /*------------------------------------------------------------------*/
1188 /*
1189 * Convert a value in milliWatt to a value in dBm.
1190 */
1191 int
1192 iw_mwatt2dbm(int in)
1193 {
1194 #ifdef WE_NOLIBM
1195 /* Version without libm : slower */
1196 double fin = (double) in;
1197 int res = 0;
1198  
1199 /* Split integral and floating part to avoid accumulating rounding errors */
1200 while(fin > 10.0)
1201 {
1202 res += 10;
1203 fin /= 10.0;
1204 }
1205 while(fin > 1.000001) /* Eliminate rounding errors, take ceil */
1206 {
1207 res += 1;
1208 fin /= LOG10_MAGIC;
1209 }
1210 return(res);
1211 #else /* WE_NOLIBM */
1212 /* Version with libm : faster */
1213 return((int) (ceil(10.0 * log10((double) in))));
1214 #endif /* WE_NOLIBM */
1215 }
1216  
1217 /*------------------------------------------------------------------*/
1218 /*
1219 * Output a txpower with proper conversion
1220 */
1221 void
1222 iw_print_txpower(char * buffer,
1223 int buflen,
1224 struct iw_param * txpower)
1225 {
1226 int dbm;
1227  
1228 /* Check if disabled */
1229 if(txpower->disabled)
1230 {
1231 snprintf(buffer, buflen, "off");
1232 }
1233 else
1234 {
1235 /* Check for relative values */
1236 if(txpower->flags & IW_TXPOW_RELATIVE)
1237 {
1238 snprintf(buffer, buflen, "%d", txpower->value);
1239 }
1240 else
1241 {
1242 /* Convert everything to dBm */
1243 if(txpower->flags & IW_TXPOW_MWATT)
1244 dbm = iw_mwatt2dbm(txpower->value);
1245 else
1246 dbm = txpower->value;
1247  
1248 /* Display */
1249 snprintf(buffer, buflen, "%d dBm", dbm);
1250 }
1251 }
1252 }
1253  
1254 /********************** STATISTICS SUBROUTINES **********************/
1255  
1256 /*------------------------------------------------------------------*/
1257 /*
1258 * Read /proc/net/wireless to get the latest statistics
1259 * Note : strtok not thread safe, not used in WE-12 and later.
1260 */
1261 int
1262 iw_get_stats(int skfd,
1263 const char * ifname,
1264 iwstats * stats,
1265 const iwrange * range,
1266 int has_range)
1267 {
1268 /* Fortunately, we can always detect this condition properly */
1269 if((has_range) && (range->we_version_compiled > 11))
1270 {
1271 struct iwreq wrq;
1272 wrq.u.data.pointer = (caddr_t) stats;
1273 wrq.u.data.length = sizeof(struct iw_statistics);
1274 wrq.u.data.flags = 1; /* Clear updated flag */
1275 strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
1276 if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
1277 return(-1);
1278  
1279 /* Format has not changed since WE-12, no conversion */
1280 return(0);
1281 }
1282 else
1283 {
1284 FILE * f = fopen(PROC_NET_WIRELESS, "r");
1285 char buf[256];
1286 char * bp;
1287 int t;
1288  
1289 if(f==NULL)
1290 return -1;
1291 /* Loop on all devices */
1292 while(fgets(buf,255,f))
1293 {
1294 bp=buf;
1295 while(*bp&&isspace(*bp))
1296 bp++;
1297 /* Is it the good device ? */
1298 if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
1299 {
1300 /* Skip ethX: */
1301 bp=strchr(bp,':');
1302 bp++;
1303 /* -- status -- */
1304 bp = strtok(bp, " ");
1305 sscanf(bp, "%X", &t);
1306 stats->status = (unsigned short) t;
1307 /* -- link quality -- */
1308 bp = strtok(NULL, " ");
1309 if(strchr(bp,'.') != NULL)
1310 stats->qual.updated |= 1;
1311 sscanf(bp, "%d", &t);
1312 stats->qual.qual = (unsigned char) t;
1313 /* -- signal level -- */
1314 bp = strtok(NULL, " ");
1315 if(strchr(bp,'.') != NULL)
1316 stats->qual.updated |= 2;
1317 sscanf(bp, "%d", &t);
1318 stats->qual.level = (unsigned char) t;
1319 /* -- noise level -- */
1320 bp = strtok(NULL, " ");
1321 if(strchr(bp,'.') != NULL)
1322 stats->qual.updated += 4;
1323 sscanf(bp, "%d", &t);
1324 stats->qual.noise = (unsigned char) t;
1325 /* -- discarded packets -- */
1326 bp = strtok(NULL, " ");
1327 sscanf(bp, "%d", &stats->discard.nwid);
1328 bp = strtok(NULL, " ");
1329 sscanf(bp, "%d", &stats->discard.code);
1330 bp = strtok(NULL, " ");
1331 sscanf(bp, "%d", &stats->discard.misc);
1332 fclose(f);
1333 /* No conversion needed */
1334 return 0;
1335 }
1336 }
1337 fclose(f);
1338 return -1;
1339 }
1340 }
1341  
1342 /*------------------------------------------------------------------*/
1343 /*
1344 * Output the link statistics, taking care of formating
1345 */
1346 void
1347 iw_print_stats(char * buffer,
1348 int buflen,
1349 const iwqual * qual,
1350 const iwrange * range,
1351 int has_range)
1352 {
1353 int len;
1354  
1355 /* People are very often confused by the 8 bit arithmetic happening
1356 * here.
1357 * All the values here are encoded in a 8 bit integer. 8 bit integers
1358 * are either unsigned [0 ; 255], signed [-128 ; +127] or
1359 * negative [-255 ; 0].
1360 * Further, on 8 bits, 0x100 == 256 == 0.
1361 *
1362 * Relative/percent values are always encoded unsigned, between 0 and 255.
1363 * Absolute/dBm values are always encoded between -192 and 63.
1364 * (Note that up to version 28 of Wireless Tools, dBm used to be
1365 * encoded always negative, between -256 and -1).
1366 *
1367 * How do we separate relative from absolute values ?
1368 * The old way is to use the range to do that. As of WE-19, we have
1369 * an explicit IW_QUAL_DBM flag in updated...
1370 * The range allow to specify the real min/max of the value. As the
1371 * range struct only specify one bound of the value, we assume that
1372 * the other bound is 0 (zero).
1373 * For relative values, range is [0 ; range->max].
1374 * For absolute values, range is [range->max ; 63].
1375 *
1376 * Let's take two example :
1377 * 1) value is 75%. qual->value = 75 ; range->max_qual.value = 100
1378 * 2) value is -54dBm. noise floor of the radio is -104dBm.
1379 * qual->value = -54 = 202 ; range->max_qual.value = -104 = 152
1380 *
1381 * Jean II
1382 */
1383  
1384 /* Just do it...
1385 * The old way to detect dBm require both the range and a non-null
1386 * level (which confuse the test). The new way can deal with level of 0
1387 * because it does an explicit test on the flag. */
1388 if(has_range && ((qual->level != 0)
1389 || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
1390 {
1391 /* Deal with quality : always a relative value */
1392 if(!(qual->updated & IW_QUAL_QUAL_INVALID))
1393 {
1394 len = snprintf(buffer, buflen, "Quality%c%d/%d ",
1395 qual->updated & IW_QUAL_QUAL_UPDATED ? '=' : ':',
1396 qual->qual, range->max_qual.qual);
1397 buffer += len;
1398 buflen -= len;
1399 }
1400  
1401 /* Check if the statistics are in RCPI (IEEE 802.11k) */
1402 if(qual->updated & IW_QUAL_RCPI)
1403 {
1404 /* Deal with signal level in RCPI */
1405 /* RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm */
1406 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1407 {
1408 double rcpilevel = (qual->level / 2.0) - 110.0;
1409 len = snprintf(buffer, buflen, "Signal level%c%g dBm ",
1410 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1411 rcpilevel);
1412 buffer += len;
1413 buflen -= len;
1414 }
1415  
1416 /* Deal with noise level in dBm (absolute power measurement) */
1417 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1418 {
1419 double rcpinoise = (qual->noise / 2.0) - 110.0;
1420 len = snprintf(buffer, buflen, "Noise level%c%g dBm",
1421 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1422 rcpinoise);
1423 }
1424 }
1425 else
1426 {
1427 /* Check if the statistics are in dBm */
1428 if((qual->updated & IW_QUAL_DBM)
1429 || (qual->level > range->max_qual.level))
1430 {
1431 /* Deal with signal level in dBm (absolute power measurement) */
1432 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1433 {
1434 int dblevel = qual->level;
1435 /* Implement a range for dBm [-192; 63] */
1436 if(qual->level >= 64)
1437 dblevel -= 0x100;
1438 len = snprintf(buffer, buflen, "Signal level%c%d dBm ",
1439 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1440 dblevel);
1441 buffer += len;
1442 buflen -= len;
1443 }
1444  
1445 /* Deal with noise level in dBm (absolute power measurement) */
1446 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1447 {
1448 int dbnoise = qual->noise;
1449 /* Implement a range for dBm [-192; 63] */
1450 if(qual->noise >= 64)
1451 dbnoise -= 0x100;
1452 len = snprintf(buffer, buflen, "Noise level%c%d dBm",
1453 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1454 dbnoise);
1455 }
1456 }
1457 else
1458 {
1459 /* Deal with signal level as relative value (0 -> max) */
1460 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1461 {
1462 len = snprintf(buffer, buflen, "Signal level%c%d/%d ",
1463 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1464 qual->level, range->max_qual.level);
1465 buffer += len;
1466 buflen -= len;
1467 }
1468  
1469 /* Deal with noise level as relative value (0 -> max) */
1470 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1471 {
1472 len = snprintf(buffer, buflen, "Noise level%c%d/%d",
1473 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1474 qual->noise, range->max_qual.noise);
1475 }
1476 }
1477 }
1478 }
1479 else
1480 {
1481 /* We can't read the range, so we don't know... */
1482 snprintf(buffer, buflen,
1483 "Quality:%d Signal level:%d Noise level:%d",
1484 qual->qual, qual->level, qual->noise);
1485 }
1486 }
1487  
1488 /*********************** ENCODING SUBROUTINES ***********************/
1489  
1490 /*------------------------------------------------------------------*/
1491 /*
1492 * Output the encoding key, with a nice formating
1493 */
1494 void
1495 iw_print_key(char * buffer,
1496 int buflen,
1497 const unsigned char * key, /* Must be unsigned */
1498 int key_size,
1499 int key_flags)
1500 {
1501 int i;
1502  
1503 /* Check buffer size -> 1 bytes => 2 digits + 1/2 separator */
1504 if((key_size * 3) > buflen)
1505 {
1506 snprintf(buffer, buflen, "<too big>");
1507 return;
1508 }
1509  
1510 /* Is the key present ??? */
1511 if(key_flags & IW_ENCODE_NOKEY)
1512 {
1513 /* Nope : print on or dummy */
1514 if(key_size <= 0)
1515 strcpy(buffer, "on"); /* Size checked */
1516 else
1517 {
1518 strcpy(buffer, "**"); /* Size checked */
1519 buffer +=2;
1520 for(i = 1; i < key_size; i++)
1521 {
1522 if((i & 0x1) == 0)
1523 strcpy(buffer++, "-"); /* Size checked */
1524 strcpy(buffer, "**"); /* Size checked */
1525 buffer +=2;
1526 }
1527 }
1528 }
1529 else
1530 {
1531 /* Yes : print the key */
1532 sprintf(buffer, "%.2X", key[0]); /* Size checked */
1533 buffer +=2;
1534 for(i = 1; i < key_size; i++)
1535 {
1536 if((i & 0x1) == 0)
1537 strcpy(buffer++, "-"); /* Size checked */
1538 sprintf(buffer, "%.2X", key[i]); /* Size checked */
1539 buffer +=2;
1540 }
1541 }
1542 }
1543  
1544 /*------------------------------------------------------------------*/
1545 /*
1546 * Convert a passphrase into a key
1547 * ### NOT IMPLEMENTED ###
1548 * Return size of the key, or 0 (no key) or -1 (error)
1549 */
1550 static int
1551 iw_pass_key(const char * input,
1552 unsigned char * key)
1553 {
1554 input = input; key = key;
1555 fprintf(stderr, "Error: Passphrase not implemented\n");
1556 return(-1);
1557 }
1558  
1559 /*------------------------------------------------------------------*/
1560 /*
1561 * Parse a key from the command line.
1562 * Return size of the key, or 0 (no key) or -1 (error)
1563 * If the key is too long, it's simply truncated...
1564 */
1565 int
1566 iw_in_key(const char * input,
1567 unsigned char * key)
1568 {
1569 int keylen = 0;
1570  
1571 /* Check the type of key */
1572 if(!strncmp(input, "s:", 2))
1573 {
1574 /* First case : as an ASCII string (Lucent/Agere cards) */
1575 keylen = strlen(input + 2); /* skip "s:" */
1576 if(keylen > IW_ENCODING_TOKEN_MAX)
1577 keylen = IW_ENCODING_TOKEN_MAX;
1578 memcpy(key, input + 2, keylen);
1579 }
1580 else
1581 if(!strncmp(input, "p:", 2))
1582 {
1583 /* Second case : as a passphrase (PrismII cards) */
1584 return(iw_pass_key(input + 2, key)); /* skip "p:" */
1585 }
1586 else
1587 {
1588 const char * p;
1589 int dlen; /* Digits sequence length */
1590 unsigned char out[IW_ENCODING_TOKEN_MAX];
1591  
1592 /* Third case : as hexadecimal digits */
1593 p = input;
1594 dlen = -1;
1595  
1596 /* Loop until we run out of chars in input or overflow the output */
1597 while(*p != '\0')
1598 {
1599 int temph;
1600 int templ;
1601 int count;
1602 /* No more chars in this sequence */
1603 if(dlen <= 0)
1604 {
1605 /* Skip separator */
1606 if(dlen == 0)
1607 p++;
1608 /* Calculate num of char to next separator */
1609 dlen = strcspn(p, "-:;.,");
1610 }
1611 /* Get each char separatly (and not by two) so that we don't
1612 * get confused by 'enc' (=> '0E'+'0C') and similar */
1613 count = sscanf(p, "%1X%1X", &temph, &templ);
1614 if(count < 1)
1615 return(-1); /* Error -> non-hex char */
1616 /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/
1617 if(dlen % 2)
1618 count = 1;
1619 /* Put back two chars as one byte and output */
1620 if(count == 2)
1621 templ |= temph << 4;
1622 else
1623 templ = temph;
1624 out[keylen++] = (unsigned char) (templ & 0xFF);
1625 /* Check overflow in output */
1626 if(keylen >= IW_ENCODING_TOKEN_MAX)
1627 break;
1628 /* Move on to next chars */
1629 p += count;
1630 dlen -= count;
1631 }
1632 /* We use a temporary output buffer 'out' so that if there is
1633 * an error, we don't overwrite the original key buffer.
1634 * Because of the way iwconfig loop on multiple key/enc arguments
1635 * until it finds an error in here, this is necessary to avoid
1636 * silently corrupting the encryption key... */
1637 memcpy(key, out, keylen);
1638 }
1639  
1640 #ifdef DEBUG
1641 {
1642 char buf[IW_ENCODING_TOKEN_MAX * 3];
1643 iw_print_key(buf, sizeof(buf), key, keylen, 0);
1644 printf("Got key : %d [%s]\n", keylen, buf);
1645 }
1646 #endif
1647  
1648 return(keylen);
1649 }
1650  
1651 /*------------------------------------------------------------------*/
1652 /*
1653 * Parse a key from the command line.
1654 * Return size of the key, or 0 (no key) or -1 (error)
1655 */
1656 int
1657 iw_in_key_full(int skfd,
1658 const char * ifname,
1659 const char * input,
1660 unsigned char * key,
1661 __u16 * flags)
1662 {
1663 int keylen = 0;
1664 char * p;
1665  
1666 if(!strncmp(input, "l:", 2))
1667 {
1668 struct iw_range range;
1669  
1670 /* Extra case : as a login (user:passwd - Cisco LEAP) */
1671 keylen = strlen(input + 2) + 1; /* skip "l:", add '\0' */
1672 /* Most user/password is 8 char, so 18 char total, < 32 */
1673 if(keylen > IW_ENCODING_TOKEN_MAX)
1674 keylen = IW_ENCODING_TOKEN_MAX;
1675 memcpy(key, input + 2, keylen);
1676  
1677 /* Separate the two strings */
1678 p = strchr((char *) key, ':');
1679 if(p == NULL)
1680 {
1681 fprintf(stderr, "Error: Invalid login format\n");
1682 return(-1);
1683 }
1684 *p = '\0';
1685  
1686 /* Extract range info */
1687 if(iw_get_range_info(skfd, ifname, &range) < 0)
1688 /* Hum... Maybe we should return an error ??? */
1689 memset(&range, 0, sizeof(range));
1690  
1691 if(range.we_version_compiled > 15)
1692 {
1693  
1694 printf("flags = %X, index = %X\n",
1695 *flags, range.encoding_login_index);
1696 if((*flags & IW_ENCODE_INDEX) == 0)
1697 {
1698 /* Extract range info */
1699 if(iw_get_range_info(skfd, ifname, &range) < 0)
1700 memset(&range, 0, sizeof(range));
1701 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1702 /* Set the index the driver expects */
1703 *flags |= range.encoding_login_index & IW_ENCODE_INDEX;
1704 }
1705 printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1706 }
1707 }
1708 else
1709 /* Simpler routine above */
1710 keylen = iw_in_key(input, key);
1711  
1712 return(keylen);
1713 }
1714  
1715 /******************* POWER MANAGEMENT SUBROUTINES *******************/
1716  
1717 /*------------------------------------------------------------------*/
1718 /*
1719 * Output a power management value with all attributes...
1720 */
1721 void
1722 iw_print_pm_value(char * buffer,
1723 int buflen,
1724 int value,
1725 int flags,
1726 int we_version)
1727 {
1728 /* Check size */
1729 if(buflen < 25)
1730 {
1731 snprintf(buffer, buflen, "<too big>");
1732 return;
1733 }
1734 buflen -= 25;
1735  
1736 /* Modifiers */
1737 if(flags & IW_POWER_MIN)
1738 {
1739 strcpy(buffer, " min"); /* Size checked */
1740 buffer += 4;
1741 }
1742 if(flags & IW_POWER_MAX)
1743 {
1744 strcpy(buffer, " max"); /* Size checked */
1745 buffer += 4;
1746 }
1747  
1748 /* Type */
1749 if(flags & IW_POWER_TIMEOUT)
1750 {
1751 strcpy(buffer, " timeout:"); /* Size checked */
1752 buffer += 9;
1753 }
1754 else
1755 {
1756 if(flags & IW_POWER_SAVING)
1757 {
1758 strcpy(buffer, " saving:"); /* Size checked */
1759 buffer += 8;
1760 }
1761 else
1762 {
1763 strcpy(buffer, " period:"); /* Size checked */
1764 buffer += 8;
1765 }
1766 }
1767  
1768 /* Display value without units */
1769 if(flags & IW_POWER_RELATIVE)
1770 {
1771 if(we_version < 21)
1772 value /= MEGA;
1773 snprintf(buffer, buflen, "%d", value);
1774 }
1775 else
1776 {
1777 /* Display value with units */
1778 if(value >= (int) MEGA)
1779 snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
1780 else
1781 if(value >= (int) KILO)
1782 snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
1783 else
1784 snprintf(buffer, buflen, "%dus", value);
1785 }
1786 }
1787  
1788 /*------------------------------------------------------------------*/
1789 /*
1790 * Output a power management mode
1791 */
1792 void
1793 iw_print_pm_mode(char * buffer,
1794 int buflen,
1795 int flags)
1796 {
1797 /* Check size */
1798 if(buflen < 28)
1799 {
1800 snprintf(buffer, buflen, "<too big>");
1801 return;
1802 }
1803  
1804 /* Print the proper mode... */
1805 switch(flags & IW_POWER_MODE)
1806 {
1807 case IW_POWER_UNICAST_R:
1808 strcpy(buffer, "mode:Unicast only received"); /* Size checked */
1809 break;
1810 case IW_POWER_MULTICAST_R:
1811 strcpy(buffer, "mode:Multicast only received"); /* Size checked */
1812 break;
1813 case IW_POWER_ALL_R:
1814 strcpy(buffer, "mode:All packets received"); /* Size checked */
1815 break;
1816 case IW_POWER_FORCE_S:
1817 strcpy(buffer, "mode:Force sending"); /* Size checked */
1818 break;
1819 case IW_POWER_REPEATER:
1820 strcpy(buffer, "mode:Repeat multicasts"); /* Size checked */
1821 break;
1822 default:
1823 strcpy(buffer, ""); /* Size checked */
1824 break;
1825 }
1826 }
1827  
1828 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
1829  
1830 /*------------------------------------------------------------------*/
1831 /*
1832 * Output a retry value with all attributes...
1833 */
1834 void
1835 iw_print_retry_value(char * buffer,
1836 int buflen,
1837 int value,
1838 int flags,
1839 int we_version)
1840 {
1841 /* Check buffer size */
1842 if(buflen < 20)
1843 {
1844 snprintf(buffer, buflen, "<too big>");
1845 return;
1846 }
1847 buflen -= 20;
1848  
1849 /* Modifiers */
1850 if(flags & IW_RETRY_MIN)
1851 {
1852 strcpy(buffer, " min"); /* Size checked */
1853 buffer += 4;
1854 }
1855 if(flags & IW_RETRY_MAX)
1856 {
1857 strcpy(buffer, " max"); /* Size checked */
1858 buffer += 4;
1859 }
1860 if(flags & IW_RETRY_SHORT)
1861 {
1862 strcpy(buffer, " short"); /* Size checked */
1863 buffer += 6;
1864 }
1865 if(flags & IW_RETRY_LONG)
1866 {
1867 strcpy(buffer, " long"); /* Size checked */
1868 buffer += 6;
1869 }
1870  
1871 /* Type lifetime of limit */
1872 if(flags & IW_RETRY_LIFETIME)
1873 {
1874 strcpy(buffer, " lifetime:"); /* Size checked */
1875 buffer += 10;
1876  
1877 /* Display value without units */
1878 if(flags & IW_RETRY_RELATIVE)
1879 {
1880 if(we_version < 21)
1881 value /= MEGA;
1882 snprintf(buffer, buflen, "%d", value);
1883 }
1884 else
1885 {
1886 /* Display value with units */
1887 if(value >= (int) MEGA)
1888 snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
1889 else
1890 if(value >= (int) KILO)
1891 snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
1892 else
1893 snprintf(buffer, buflen, "%dus", value);
1894 }
1895 }
1896 else
1897 snprintf(buffer, buflen, " limit:%d", value);
1898 }
1899  
1900 /************************* TIME SUBROUTINES *************************/
1901  
1902 /*------------------------------------------------------------------*/
1903 /*
1904 * Print timestamps
1905 * Inspired from irdadump...
1906 */
1907 void
1908 iw_print_timeval(char * buffer,
1909 int buflen,
1910 const struct timeval * timev,
1911 const struct timezone * tz)
1912 {
1913 int s;
1914  
1915 s = (timev->tv_sec - tz->tz_minuteswest * 60) % 86400;
1916 snprintf(buffer, buflen, "%02d:%02d:%02d.%06u",
1917 s / 3600, (s % 3600) / 60,
1918 s % 60, (u_int32_t) timev->tv_usec);
1919 }
1920  
1921 /*********************** ADDRESS SUBROUTINES ************************/
1922 /*
1923 * This section is mostly a cut & past from net-tools-1.2.0
1924 * (Well... This has evolved over the years)
1925 * manage address display and input...
1926 */
1927  
1928 /*------------------------------------------------------------------*/
1929 /*
1930 * Check if interface support the right MAC address type...
1931 */
1932 int
1933 iw_check_mac_addr_type(int skfd,
1934 const char * ifname)
1935 {
1936 struct ifreq ifr;
1937  
1938 /* Get the type of hardware address */
1939 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1940 if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
1941 ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
1942 && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211)))
1943 {
1944 /* Deep trouble... */
1945 fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
1946 ifname);
1947 return(-1);
1948 }
1949  
1950 #ifdef DEBUG
1951 {
1952 char buf[20];
1953 printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
1954 iw_saether_ntop(&ifr.ifr_hwaddr, buf));
1955 }
1956 #endif
1957  
1958 return(0);
1959 }
1960  
1961  
1962 /*------------------------------------------------------------------*/
1963 /*
1964 * Check if interface support the right interface address type...
1965 */
1966 int
1967 iw_check_if_addr_type(int skfd,
1968 const char * ifname)
1969 {
1970 struct ifreq ifr;
1971  
1972 /* Get the type of interface address */
1973 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1974 if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
1975 (ifr.ifr_addr.sa_family != AF_INET))
1976 {
1977 /* Deep trouble... */
1978 fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
1979 return(-1);
1980 }
1981  
1982 #ifdef DEBUG
1983 printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
1984 *((unsigned long *) ifr.ifr_addr.sa_data));
1985 #endif
1986  
1987 return(0);
1988 }
1989  
1990 #if 0
1991 /*------------------------------------------------------------------*/
1992 /*
1993 * Check if interface support the right address types...
1994 */
1995 int
1996 iw_check_addr_type(int skfd,
1997 char * ifname)
1998 {
1999 /* Check the interface address type */
2000 if(iw_check_if_addr_type(skfd, ifname) < 0)
2001 return(-1);
2002  
2003 /* Check the interface address type */
2004 if(iw_check_mac_addr_type(skfd, ifname) < 0)
2005 return(-1);
2006  
2007 return(0);
2008 }
2009 #endif
2010  
2011 #if 0
2012 /*------------------------------------------------------------------*/
2013 /*
2014 * Ask the kernel for the MAC address of an interface.
2015 */
2016 int
2017 iw_get_mac_addr(int skfd,
2018 const char * ifname,
2019 struct ether_addr * eth,
2020 unsigned short * ptype)
2021 {
2022 struct ifreq ifr;
2023 int ret;
2024  
2025 /* Prepare request */
2026 bzero(&ifr, sizeof(struct ifreq));
2027 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
2028  
2029 /* Do it */
2030 ret = ioctl(skfd, SIOCGIFHWADDR, &ifr);
2031  
2032 memcpy(eth->ether_addr_octet, ifr.ifr_hwaddr.sa_data, 6);
2033 *ptype = ifr.ifr_hwaddr.sa_family;
2034 return(ret);
2035 }
2036 #endif
2037  
2038 /*------------------------------------------------------------------*/
2039 /*
2040 * Display an arbitrary length MAC address in readable format.
2041 */
2042 char *
2043 iw_mac_ntop(const unsigned char * mac,
2044 int maclen,
2045 char * buf,
2046 int buflen)
2047 {
2048 int i;
2049  
2050 /* Overflow check (don't forget '\0') */
2051 if(buflen < (maclen * 3 - 1 + 1))
2052 return(NULL);
2053  
2054 /* First byte */
2055 sprintf(buf, "%02X", mac[0]);
2056  
2057 /* Other bytes */
2058 for(i = 1; i < maclen; i++)
2059 sprintf(buf + (i * 3) - 1, ":%02X", mac[i]);
2060 return(buf);
2061 }
2062  
2063 /*------------------------------------------------------------------*/
2064 /*
2065 * Display an Ethernet address in readable format.
2066 */
2067 void
2068 iw_ether_ntop(const struct ether_addr * eth,
2069 char * buf)
2070 {
2071 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
2072 eth->ether_addr_octet[0], eth->ether_addr_octet[1],
2073 eth->ether_addr_octet[2], eth->ether_addr_octet[3],
2074 eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
2075 }
2076  
2077 /*------------------------------------------------------------------*/
2078 /*
2079 * Display an Wireless Access Point Socket Address in readable format.
2080 * Note : 0x44 is an accident of history, that's what the Orinoco/PrismII
2081 * chipset report, and the driver doesn't filter it.
2082 */
2083 char *
2084 iw_sawap_ntop(const struct sockaddr * sap,
2085 char * buf)
2086 {
2087 const struct ether_addr ether_zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
2088 const struct ether_addr ether_bcast = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
2089 const struct ether_addr ether_hack = {{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }};
2090 const struct ether_addr * ether_wap = (const struct ether_addr *) sap->sa_data;
2091  
2092 if(!iw_ether_cmp(ether_wap, &ether_zero))
2093 sprintf(buf, "Not-Associated");
2094 else
2095 if(!iw_ether_cmp(ether_wap, &ether_bcast))
2096 sprintf(buf, "Invalid");
2097 else
2098 if(!iw_ether_cmp(ether_wap, &ether_hack))
2099 sprintf(buf, "None");
2100 else
2101 iw_ether_ntop(ether_wap, buf);
2102 return(buf);
2103 }
2104  
2105 /*------------------------------------------------------------------*/
2106 /*
2107 * Input an arbitrary length MAC address and convert to binary.
2108 * Return address size.
2109 */
2110 int
2111 iw_mac_aton(const char * orig,
2112 unsigned char * mac,
2113 int macmax)
2114 {
2115 const char * p = orig;
2116 int maclen = 0;
2117  
2118 /* Loop on all bytes of the string */
2119 while(*p != '\0')
2120 {
2121 int temph;
2122 int templ;
2123 int count;
2124 /* Extract one byte as two chars */
2125 count = sscanf(p, "%1X%1X", &temph, &templ);
2126 if(count != 2)
2127 break; /* Error -> non-hex chars */
2128 /* Output two chars as one byte */
2129 templ |= temph << 4;
2130 mac[maclen++] = (unsigned char) (templ & 0xFF);
2131  
2132 /* Check end of string */
2133 p += 2;
2134 if(*p == '\0')
2135 {
2136 #ifdef DEBUG
2137 char buf[20];
2138 iw_ether_ntop((const struct ether_addr *) mac, buf);
2139 fprintf(stderr, "iw_mac_aton(%s): %s\n", orig, buf);
2140 #endif
2141 return(maclen); /* Normal exit */
2142 }
2143  
2144 /* Check overflow */
2145 if(maclen >= macmax)
2146 {
2147 #ifdef DEBUG
2148 fprintf(stderr, "iw_mac_aton(%s): trailing junk!\n", orig);
2149 #endif
2150 errno = E2BIG;
2151 return(0); /* Error -> overflow */
2152 }
2153  
2154 /* Check separator */
2155 if(*p != ':')
2156 break;
2157 p++;
2158 }
2159  
2160 /* Error... */
2161 #ifdef DEBUG
2162 fprintf(stderr, "iw_mac_aton(%s): invalid ether address!\n", orig);
2163 #endif
2164 errno = EINVAL;
2165 return(0);
2166 }
2167  
2168 /*------------------------------------------------------------------*/
2169 /*
2170 * Input an Ethernet address and convert to binary.
2171 */
2172 int
2173 iw_ether_aton(const char *orig, struct ether_addr *eth)
2174 {
2175 int maclen;
2176 maclen = iw_mac_aton(orig, (unsigned char *) eth, ETH_ALEN);
2177 if((maclen > 0) && (maclen < ETH_ALEN))
2178 {
2179 errno = EINVAL;
2180 maclen = 0;
2181 }
2182 return(maclen);
2183 }
2184  
2185 /*------------------------------------------------------------------*/
2186 /*
2187 * Input an Internet address and convert to binary.
2188 */
2189 int
2190 iw_in_inet(char *name, struct sockaddr *sap)
2191 {
2192 struct hostent *hp;
2193 struct netent *np;
2194 struct sockaddr_in *sain = (struct sockaddr_in *) sap;
2195  
2196 /* Grmpf. -FvK */
2197 sain->sin_family = AF_INET;
2198 sain->sin_port = 0;
2199  
2200 /* Default is special, meaning 0.0.0.0. */
2201 if (!strcmp(name, "default")) {
2202 sain->sin_addr.s_addr = INADDR_ANY;
2203 return(1);
2204 }
2205  
2206 /* Try the NETWORKS database to see if this is a known network. */
2207 if ((np = getnetbyname(name)) != (struct netent *)NULL) {
2208 sain->sin_addr.s_addr = htonl(np->n_net);
2209 strcpy(name, np->n_name);
2210 return(1);
2211 }
2212  
2213 /* Always use the resolver (DNS name + IP addresses) */
2214 if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
2215 errno = h_errno;
2216 return(-1);
2217 }
2218 memcpy((char *) &sain->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
2219 strcpy(name, hp->h_name);
2220 return(0);
2221 }
2222  
2223 /*------------------------------------------------------------------*/
2224 /*
2225 * Input an address and convert to binary.
2226 */
2227 int
2228 iw_in_addr(int skfd,
2229 const char * ifname,
2230 char * bufp,
2231 struct sockaddr *sap)
2232 {
2233 /* Check if it is a hardware or IP address */
2234 if(strchr(bufp, ':') == NULL)
2235 {
2236 struct sockaddr if_address;
2237 struct arpreq arp_query;
2238  
2239 /* Check if we have valid interface address type */
2240 if(iw_check_if_addr_type(skfd, ifname) < 0)
2241 {
2242 fprintf(stderr, "%-8.16s Interface doesn't support IP addresses\n", ifname);
2243 return(-1);
2244 }
2245  
2246 /* Read interface address */
2247 if(iw_in_inet(bufp, &if_address) < 0)
2248 {
2249 fprintf(stderr, "Invalid interface address %s\n", bufp);
2250 return(-1);
2251 }
2252  
2253 /* Translate IP addresses to MAC addresses */
2254 memcpy((char *) &(arp_query.arp_pa),
2255 (char *) &if_address,
2256 sizeof(struct sockaddr));
2257 arp_query.arp_ha.sa_family = 0;
2258 arp_query.arp_flags = 0;
2259 /* The following restrict the search to the interface only */
2260 /* For old kernels which complain, just comment it... */
2261 strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
2262 if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
2263 !(arp_query.arp_flags & ATF_COM))
2264 {
2265 fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
2266 bufp, ifname, errno);
2267 return(-1);
2268 }
2269  
2270 /* Store new MAC address */
2271 memcpy((char *) sap,
2272 (char *) &(arp_query.arp_ha),
2273 sizeof(struct sockaddr));
2274  
2275 #ifdef DEBUG
2276 {
2277 char buf[20];
2278 printf("IP Address %s => Hw Address = %s\n",
2279 bufp, iw_saether_ntop(sap, buf));
2280 }
2281 #endif
2282 }
2283 else /* If it's an hardware address */
2284 {
2285 /* Check if we have valid mac address type */
2286 if(iw_check_mac_addr_type(skfd, ifname) < 0)
2287 {
2288 fprintf(stderr, "%-8.16s Interface doesn't support MAC addresses\n", ifname);
2289 return(-1);
2290 }
2291  
2292 /* Get the hardware address */
2293 if(iw_saether_aton(bufp, sap) == 0)
2294 {
2295 fprintf(stderr, "Invalid hardware address %s\n", bufp);
2296 return(-1);
2297 }
2298 }
2299  
2300 #ifdef DEBUG
2301 {
2302 char buf[20];
2303 printf("Hw Address = %s\n", iw_saether_ntop(sap, buf));
2304 }
2305 #endif
2306  
2307 return(0);
2308 }
2309  
2310 /************************* MISC SUBROUTINES **************************/
2311  
2312 /* Size (in bytes) of various events */
2313 static const int priv_type_size[] = {
2314 0, /* IW_PRIV_TYPE_NONE */
2315 1, /* IW_PRIV_TYPE_BYTE */
2316 1, /* IW_PRIV_TYPE_CHAR */
2317 0, /* Not defined */
2318 sizeof(__u32), /* IW_PRIV_TYPE_INT */
2319 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
2320 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
2321 0, /* Not defined */
2322 };
2323  
2324 /*------------------------------------------------------------------*/
2325 /*
2326 * Max size in bytes of an private argument.
2327 */
2328 int
2329 iw_get_priv_size(int args)
2330 {
2331 int num = args & IW_PRIV_SIZE_MASK;
2332 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
2333  
2334 return(num * priv_type_size[type]);
2335 }
2336  
2337 /************************ EVENT SUBROUTINES ************************/
2338 /*
2339 * The Wireless Extension API 14 and greater define Wireless Events,
2340 * that are used for various events and scanning.
2341 * Those functions help the decoding of events, so are needed only in
2342 * this case.
2343 */
2344  
2345 /* -------------------------- CONSTANTS -------------------------- */
2346  
2347 /* Type of headers we know about (basically union iwreq_data) */
2348 #define IW_HEADER_TYPE_NULL 0 /* Not available */
2349 #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
2350 #define IW_HEADER_TYPE_UINT 4 /* __u32 */
2351 #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
2352 #define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */
2353 #define IW_HEADER_TYPE_POINT 8 /* struct iw_point */
2354 #define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */
2355 #define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */
2356  
2357 /* Handling flags */
2358 /* Most are not implemented. I just use them as a reminder of some
2359 * cool features we might need one day ;-) */
2360 #define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */
2361 /* Wrapper level flags */
2362 #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
2363 #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
2364 #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
2365 /* SET : Omit payload from generated iwevent */
2366 #define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
2367 /* Driver level flags */
2368 #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
2369  
2370 /* ---------------------------- TYPES ---------------------------- */
2371  
2372 /*
2373 * Describe how a standard IOCTL looks like.
2374 */
2375 struct iw_ioctl_description
2376 {
2377 __u8 header_type; /* NULL, iw_point or other */
2378 __u8 token_type; /* Future */
2379 __u16 token_size; /* Granularity of payload */
2380 __u16 min_tokens; /* Min acceptable token number */
2381 __u16 max_tokens; /* Max acceptable token number */
2382 __u32 flags; /* Special handling of the request */
2383 };
2384  
2385 /* -------------------------- VARIABLES -------------------------- */
2386  
2387 /*
2388 * Meta-data about all the standard Wireless Extension request we
2389 * know about.
2390 */
2391 static const struct iw_ioctl_description standard_ioctl_descr[] = {
2392 [SIOCSIWCOMMIT - SIOCIWFIRST] = {
2393 .header_type = IW_HEADER_TYPE_NULL,
2394 },
2395 [SIOCGIWNAME - SIOCIWFIRST] = {
2396 .header_type = IW_HEADER_TYPE_CHAR,
2397 .flags = IW_DESCR_FLAG_DUMP,
2398 },
2399 [SIOCSIWNWID - SIOCIWFIRST] = {
2400 .header_type = IW_HEADER_TYPE_PARAM,
2401 .flags = IW_DESCR_FLAG_EVENT,
2402 },
2403 [SIOCGIWNWID - SIOCIWFIRST] = {
2404 .header_type = IW_HEADER_TYPE_PARAM,
2405 .flags = IW_DESCR_FLAG_DUMP,
2406 },
2407 [SIOCSIWFREQ - SIOCIWFIRST] = {
2408 .header_type = IW_HEADER_TYPE_FREQ,
2409 .flags = IW_DESCR_FLAG_EVENT,
2410 },
2411 [SIOCGIWFREQ - SIOCIWFIRST] = {
2412 .header_type = IW_HEADER_TYPE_FREQ,
2413 .flags = IW_DESCR_FLAG_DUMP,
2414 },
2415 [SIOCSIWMODE - SIOCIWFIRST] = {
2416 .header_type = IW_HEADER_TYPE_UINT,
2417 .flags = IW_DESCR_FLAG_EVENT,
2418 },
2419 [SIOCGIWMODE - SIOCIWFIRST] = {
2420 .header_type = IW_HEADER_TYPE_UINT,
2421 .flags = IW_DESCR_FLAG_DUMP,
2422 },
2423 [SIOCSIWSENS - SIOCIWFIRST] = {
2424 .header_type = IW_HEADER_TYPE_PARAM,
2425 },
2426 [SIOCGIWSENS - SIOCIWFIRST] = {
2427 .header_type = IW_HEADER_TYPE_PARAM,
2428 },
2429 [SIOCSIWRANGE - SIOCIWFIRST] = {
2430 .header_type = IW_HEADER_TYPE_NULL,
2431 },
2432 [SIOCGIWRANGE - SIOCIWFIRST] = {
2433 .header_type = IW_HEADER_TYPE_POINT,
2434 .token_size = 1,
2435 .max_tokens = sizeof(struct iw_range),
2436 .flags = IW_DESCR_FLAG_DUMP,
2437 },
2438 [SIOCSIWPRIV - SIOCIWFIRST] = {
2439 .header_type = IW_HEADER_TYPE_NULL,
2440 },
2441 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
2442 .header_type = IW_HEADER_TYPE_NULL,
2443 },
2444 [SIOCSIWSTATS - SIOCIWFIRST] = {
2445 .header_type = IW_HEADER_TYPE_NULL,
2446 },
2447 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
2448 .header_type = IW_HEADER_TYPE_NULL,
2449 .flags = IW_DESCR_FLAG_DUMP,
2450 },
2451 [SIOCSIWSPY - SIOCIWFIRST] = {
2452 .header_type = IW_HEADER_TYPE_POINT,
2453 .token_size = sizeof(struct sockaddr),
2454 .max_tokens = IW_MAX_SPY,
2455 },
2456 [SIOCGIWSPY - SIOCIWFIRST] = {
2457 .header_type = IW_HEADER_TYPE_POINT,
2458 .token_size = sizeof(struct sockaddr) +
2459 sizeof(struct iw_quality),
2460 .max_tokens = IW_MAX_SPY,
2461 },
2462 [SIOCSIWTHRSPY - SIOCIWFIRST] = {
2463 .header_type = IW_HEADER_TYPE_POINT,
2464 .token_size = sizeof(struct iw_thrspy),
2465 .min_tokens = 1,
2466 .max_tokens = 1,
2467 },
2468 [SIOCGIWTHRSPY - SIOCIWFIRST] = {
2469 .header_type = IW_HEADER_TYPE_POINT,
2470 .token_size = sizeof(struct iw_thrspy),
2471 .min_tokens = 1,
2472 .max_tokens = 1,
2473 },
2474 [SIOCSIWAP - SIOCIWFIRST] = {
2475 .header_type = IW_HEADER_TYPE_ADDR,
2476 },
2477 [SIOCGIWAP - SIOCIWFIRST] = {
2478 .header_type = IW_HEADER_TYPE_ADDR,
2479 .flags = IW_DESCR_FLAG_DUMP,
2480 },
2481 [SIOCSIWMLME - SIOCIWFIRST] = {
2482 .header_type = IW_HEADER_TYPE_POINT,
2483 .token_size = 1,
2484 .min_tokens = sizeof(struct iw_mlme),
2485 .max_tokens = sizeof(struct iw_mlme),
2486 },
2487 [SIOCGIWAPLIST - SIOCIWFIRST] = {
2488 .header_type = IW_HEADER_TYPE_POINT,
2489 .token_size = sizeof(struct sockaddr) +
2490 sizeof(struct iw_quality),
2491 .max_tokens = IW_MAX_AP,
2492 .flags = IW_DESCR_FLAG_NOMAX,
2493 },
2494 [SIOCSIWSCAN - SIOCIWFIRST] = {
2495 .header_type = IW_HEADER_TYPE_POINT,
2496 .token_size = 1,
2497 .min_tokens = 0,
2498 .max_tokens = sizeof(struct iw_scan_req),
2499 },
2500 [SIOCGIWSCAN - SIOCIWFIRST] = {
2501 .header_type = IW_HEADER_TYPE_POINT,
2502 .token_size = 1,
2503 .max_tokens = IW_SCAN_MAX_DATA,
2504 .flags = IW_DESCR_FLAG_NOMAX,
2505 },
2506 [SIOCSIWESSID - SIOCIWFIRST] = {
2507 .header_type = IW_HEADER_TYPE_POINT,
2508 .token_size = 1,
2509 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2510 .flags = IW_DESCR_FLAG_EVENT,
2511 },
2512 [SIOCGIWESSID - SIOCIWFIRST] = {
2513 .header_type = IW_HEADER_TYPE_POINT,
2514 .token_size = 1,
2515 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2516 .flags = IW_DESCR_FLAG_DUMP,
2517 },
2518 [SIOCSIWNICKN - SIOCIWFIRST] = {
2519 .header_type = IW_HEADER_TYPE_POINT,
2520 .token_size = 1,
2521 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2522 },
2523 [SIOCGIWNICKN - SIOCIWFIRST] = {
2524 .header_type = IW_HEADER_TYPE_POINT,
2525 .token_size = 1,
2526 .max_tokens = IW_ESSID_MAX_SIZE + 1,
2527 },
2528 [SIOCSIWRATE - SIOCIWFIRST] = {
2529 .header_type = IW_HEADER_TYPE_PARAM,
2530 },
2531 [SIOCGIWRATE - SIOCIWFIRST] = {
2532 .header_type = IW_HEADER_TYPE_PARAM,
2533 },
2534 [SIOCSIWRTS - SIOCIWFIRST] = {
2535 .header_type = IW_HEADER_TYPE_PARAM,
2536 },
2537 [SIOCGIWRTS - SIOCIWFIRST] = {
2538 .header_type = IW_HEADER_TYPE_PARAM,
2539 },
2540 [SIOCSIWFRAG - SIOCIWFIRST] = {
2541 .header_type = IW_HEADER_TYPE_PARAM,
2542 },
2543 [SIOCGIWFRAG - SIOCIWFIRST] = {
2544 .header_type = IW_HEADER_TYPE_PARAM,
2545 },
2546 [SIOCSIWTXPOW - SIOCIWFIRST] = {
2547 .header_type = IW_HEADER_TYPE_PARAM,
2548 },
2549 [SIOCGIWTXPOW - SIOCIWFIRST] = {
2550 .header_type = IW_HEADER_TYPE_PARAM,
2551 },
2552 [SIOCSIWRETRY - SIOCIWFIRST] = {
2553 .header_type = IW_HEADER_TYPE_PARAM,
2554 },
2555 [SIOCGIWRETRY - SIOCIWFIRST] = {
2556 .header_type = IW_HEADER_TYPE_PARAM,
2557 },
2558 [SIOCSIWENCODE - SIOCIWFIRST] = {
2559 .header_type = IW_HEADER_TYPE_POINT,
2560 .token_size = 1,
2561 .max_tokens = IW_ENCODING_TOKEN_MAX,
2562 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
2563 },
2564 [SIOCGIWENCODE - SIOCIWFIRST] = {
2565 .header_type = IW_HEADER_TYPE_POINT,
2566 .token_size = 1,
2567 .max_tokens = IW_ENCODING_TOKEN_MAX,
2568 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
2569 },
2570 [SIOCSIWPOWER - SIOCIWFIRST] = {
2571 .header_type = IW_HEADER_TYPE_PARAM,
2572 },
2573 [SIOCGIWPOWER - SIOCIWFIRST] = {
2574 .header_type = IW_HEADER_TYPE_PARAM,
2575 },
2576 [SIOCSIWMODUL - SIOCIWFIRST] = {
2577 .header_type = IW_HEADER_TYPE_PARAM,
2578 },
2579 [SIOCGIWMODUL - SIOCIWFIRST] = {
2580 .header_type = IW_HEADER_TYPE_PARAM,
2581 },
2582 [SIOCSIWGENIE - SIOCIWFIRST] = {
2583 .header_type = IW_HEADER_TYPE_POINT,
2584 .token_size = 1,
2585 .max_tokens = IW_GENERIC_IE_MAX,
2586 },
2587 [SIOCGIWGENIE - SIOCIWFIRST] = {
2588 .header_type = IW_HEADER_TYPE_POINT,
2589 .token_size = 1,
2590 .max_tokens = IW_GENERIC_IE_MAX,
2591 },
2592 [SIOCSIWAUTH - SIOCIWFIRST] = {
2593 .header_type = IW_HEADER_TYPE_PARAM,
2594 },
2595 [SIOCGIWAUTH - SIOCIWFIRST] = {
2596 .header_type = IW_HEADER_TYPE_PARAM,
2597 },
2598 [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
2599 .header_type = IW_HEADER_TYPE_POINT,
2600 .token_size = 1,
2601 .min_tokens = sizeof(struct iw_encode_ext),
2602 .max_tokens = sizeof(struct iw_encode_ext) +
2603 IW_ENCODING_TOKEN_MAX,
2604 },
2605 [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
2606 .header_type = IW_HEADER_TYPE_POINT,
2607 .token_size = 1,
2608 .min_tokens = sizeof(struct iw_encode_ext),
2609 .max_tokens = sizeof(struct iw_encode_ext) +
2610 IW_ENCODING_TOKEN_MAX,
2611 },
2612 [SIOCSIWPMKSA - SIOCIWFIRST] = {
2613 .header_type = IW_HEADER_TYPE_POINT,
2614 .token_size = 1,
2615 .min_tokens = sizeof(struct iw_pmksa),
2616 .max_tokens = sizeof(struct iw_pmksa),
2617 },
2618 };
2619 static const unsigned int standard_ioctl_num = (sizeof(standard_ioctl_descr) /
2620 sizeof(struct iw_ioctl_description));
2621  
2622 /*
2623 * Meta-data about all the additional standard Wireless Extension events
2624 * we know about.
2625 */
2626 static const struct iw_ioctl_description standard_event_descr[] = {
2627 [IWEVTXDROP - IWEVFIRST] = {
2628 .header_type = IW_HEADER_TYPE_ADDR,
2629 },
2630 [IWEVQUAL - IWEVFIRST] = {
2631 .header_type = IW_HEADER_TYPE_QUAL,
2632 },
2633 [IWEVCUSTOM - IWEVFIRST] = {
2634 .header_type = IW_HEADER_TYPE_POINT,
2635 .token_size = 1,
2636 .max_tokens = IW_CUSTOM_MAX,
2637 },
2638 [IWEVREGISTERED - IWEVFIRST] = {
2639 .header_type = IW_HEADER_TYPE_ADDR,
2640 },
2641 [IWEVEXPIRED - IWEVFIRST] = {
2642 .header_type = IW_HEADER_TYPE_ADDR,
2643 },
2644 [IWEVGENIE - IWEVFIRST] = {
2645 .header_type = IW_HEADER_TYPE_POINT,
2646 .token_size = 1,
2647 .max_tokens = IW_GENERIC_IE_MAX,
2648 },
2649 [IWEVMICHAELMICFAILURE - IWEVFIRST] = {
2650 .header_type = IW_HEADER_TYPE_POINT,
2651 .token_size = 1,
2652 .max_tokens = sizeof(struct iw_michaelmicfailure),
2653 },
2654 [IWEVASSOCREQIE - IWEVFIRST] = {
2655 .header_type = IW_HEADER_TYPE_POINT,
2656 .token_size = 1,
2657 .max_tokens = IW_GENERIC_IE_MAX,
2658 },
2659 [IWEVASSOCRESPIE - IWEVFIRST] = {
2660 .header_type = IW_HEADER_TYPE_POINT,
2661 .token_size = 1,
2662 .max_tokens = IW_GENERIC_IE_MAX,
2663 },
2664 [IWEVPMKIDCAND - IWEVFIRST] = {
2665 .header_type = IW_HEADER_TYPE_POINT,
2666 .token_size = 1,
2667 .max_tokens = sizeof(struct iw_pmkid_cand),
2668 },
2669 };
2670 static const unsigned int standard_event_num = (sizeof(standard_event_descr) /
2671 sizeof(struct iw_ioctl_description));
2672  
2673 /* Size (in bytes) of various events */
2674 static const int event_type_size[] = {
2675 IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */
2676 0,
2677 IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */
2678 0,
2679 IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */
2680 IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */
2681 IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */
2682 0,
2683 IW_EV_POINT_PK_LEN, /* Without variable payload */
2684 IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */
2685 IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */
2686 };
2687  
2688 /*------------------------------------------------------------------*/
2689 /*
2690 * Initialise the struct stream_descr so that we can extract
2691 * individual events from the event stream.
2692 */
2693 void
2694 iw_init_event_stream(struct stream_descr * stream, /* Stream of events */
2695 char * data,
2696 int len)
2697 {
2698 /* Cleanup */
2699 memset((char *) stream, '\0', sizeof(struct stream_descr));
2700  
2701 /* Set things up */
2702 stream->current = data;
2703 stream->end = data + len;
2704 }
2705  
2706 /*------------------------------------------------------------------*/
2707 /*
2708 * Extract the next event from the event stream.
2709 */
2710 int
2711 iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
2712 struct iw_event * iwe, /* Extracted event */
2713 int we_version)
2714 {
2715 const struct iw_ioctl_description * descr = NULL;
2716 int event_type = 0;
2717 unsigned int event_len = 1; /* Invalid */
2718 char * pointer;
2719 /* Don't "optimise" the following variable, it will crash */
2720 unsigned cmd_index; /* *MUST* be unsigned */
2721  
2722 /* Check for end of stream */
2723 if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
2724 return(0);
2725  
2726 #ifdef DEBUG
2727 printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
2728 stream->current, stream->value, stream->end);
2729 #endif
2730  
2731 /* Extract the event header (to get the event id).
2732 * Note : the event may be unaligned, therefore copy... */
2733 memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
2734  
2735 #ifdef DEBUG
2736 printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
2737 iwe->cmd, iwe->len);
2738 #endif
2739  
2740 /* Check invalid events */
2741 if(iwe->len <= IW_EV_LCP_PK_LEN)
2742 return(-1);
2743  
2744 /* Get the type and length of that event */
2745 if(iwe->cmd <= SIOCIWLAST)
2746 {
2747 cmd_index = iwe->cmd - SIOCIWFIRST;
2748 if(cmd_index < standard_ioctl_num)
2749 descr = &(standard_ioctl_descr[cmd_index]);
2750 }
2751 else
2752 {
2753 cmd_index = iwe->cmd - IWEVFIRST;
2754 if(cmd_index < standard_event_num)
2755 descr = &(standard_event_descr[cmd_index]);
2756 }
2757 if(descr != NULL)
2758 event_type = descr->header_type;
2759 /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
2760 event_len = event_type_size[event_type];
2761 /* Fixup for earlier version of WE */
2762 if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))
2763 event_len += IW_EV_POINT_OFF;
2764  
2765 /* Check if we know about this event */
2766 if(event_len <= IW_EV_LCP_PK_LEN)
2767 {
2768 /* Skip to next event */
2769 stream->current += iwe->len;
2770 return(2);
2771 }
2772 event_len -= IW_EV_LCP_PK_LEN;
2773  
2774 /* Set pointer on data */
2775 if(stream->value != NULL)
2776 pointer = stream->value; /* Next value in event */
2777 else
2778 pointer = stream->current + IW_EV_LCP_PK_LEN; /* First value in event */
2779  
2780 #ifdef DEBUG
2781 printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
2782 event_type, event_len, pointer);
2783 #endif
2784  
2785 /* Copy the rest of the event (at least, fixed part) */
2786 if((pointer + event_len) > stream->end)
2787 {
2788 /* Go to next event */
2789 stream->current += iwe->len;
2790 return(-2);
2791 }
2792 /* Fixup for WE-19 and later : pointer no longer in the stream */
2793 /* Beware of alignement. Dest has local alignement, not packed */
2794 if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
2795 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2796 pointer, event_len);
2797 else
2798 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2799  
2800 /* Skip event in the stream */
2801 pointer += event_len;
2802  
2803 /* Special processing for iw_point events */
2804 if(event_type == IW_HEADER_TYPE_POINT)
2805 {
2806 /* Check the length of the payload */
2807 unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);
2808 if(extra_len > 0)
2809 {
2810 /* Set pointer on variable part (warning : non aligned) */
2811 iwe->u.data.pointer = pointer;
2812  
2813 /* Check that we have a descriptor for the command */
2814 if(descr == NULL)
2815 /* Can't check payload -> unsafe... */
2816 iwe->u.data.pointer = NULL; /* Discard paylod */
2817 else
2818 {
2819 /* Those checks are actually pretty hard to trigger,
2820 * because of the checks done in the kernel... */
2821  
2822 unsigned int token_len = iwe->u.data.length * descr->token_size;
2823  
2824 /* Ugly fixup for alignement issues.
2825 * If the kernel is 64 bits and userspace 32 bits,
2826 * we have an extra 4+4 bytes.
2827 * Fixing that in the kernel would break 64 bits userspace. */
2828 if((token_len != extra_len) && (extra_len >= 4))
2829 {
2830 __u16 alt_dlen = *((__u16 *) pointer);
2831 unsigned int alt_token_len = alt_dlen * descr->token_size;
2832 if((alt_token_len + 8) == extra_len)
2833 {
2834 #ifdef DEBUG
2835 printf("DBG - alt_token_len = %d\n", alt_token_len);
2836 #endif
2837 /* Ok, let's redo everything */
2838 pointer -= event_len;
2839 pointer += 4;
2840 /* Dest has local alignement, not packed */
2841 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2842 pointer, event_len);
2843 pointer += event_len + 4;
2844 iwe->u.data.pointer = pointer;
2845 token_len = alt_token_len;
2846 }
2847 }
2848  
2849 /* Discard bogus events which advertise more tokens than
2850 * what they carry... */
2851 if(token_len > extra_len)
2852 iwe->u.data.pointer = NULL; /* Discard paylod */
2853 /* Check that the advertised token size is not going to
2854 * produce buffer overflow to our caller... */
2855 if((iwe->u.data.length > descr->max_tokens)
2856 && !(descr->flags & IW_DESCR_FLAG_NOMAX))
2857 iwe->u.data.pointer = NULL; /* Discard paylod */
2858 /* Same for underflows... */
2859 if(iwe->u.data.length < descr->min_tokens)
2860 iwe->u.data.pointer = NULL; /* Discard paylod */
2861 #ifdef DEBUG
2862 printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",
2863 extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
2864 #endif
2865 }
2866 }
2867 else
2868 /* No data */
2869 iwe->u.data.pointer = NULL;
2870  
2871 /* Go to next event */
2872 stream->current += iwe->len;
2873 }
2874 else
2875 {
2876 /* Ugly fixup for alignement issues.
2877 * If the kernel is 64 bits and userspace 32 bits,
2878 * we have an extra 4 bytes.
2879 * Fixing that in the kernel would break 64 bits userspace. */
2880 if((stream->value == NULL)
2881 && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
2882 || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
2883 (event_type == IW_HEADER_TYPE_QUAL))) ))
2884 {
2885 #ifdef DEBUG
2886 printf("DBG - alt iwe->len = %d\n", iwe->len - 4);
2887 #endif
2888 pointer -= event_len;
2889 pointer += 4;
2890 /* Beware of alignement. Dest has local alignement, not packed */
2891 memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2892 pointer += event_len;
2893 }
2894  
2895 /* Is there more value in the event ? */
2896 if((pointer + event_len) <= (stream->current + iwe->len))
2897 /* Go to next value */
2898 stream->value = pointer;
2899 else
2900 {
2901 /* Go to next event */
2902 stream->value = NULL;
2903 stream->current += iwe->len;
2904 }
2905 }
2906 return(1);
2907 }
2908  
2909 /*********************** SCANNING SUBROUTINES ***********************/
2910 /*
2911 * The Wireless Extension API 14 and greater define Wireless Scanning.
2912 * The normal API is complex, this is an easy API that return
2913 * a subset of the scanning results. This should be enough for most
2914 * applications that want to use Scanning.
2915 * If you want to have use the full/normal API, check iwlist.c...
2916 *
2917 * Precaution when using scanning :
2918 * The scanning operation disable normal network traffic, and therefore
2919 * you should not abuse of scan.
2920 * The scan need to check the presence of network on other frequencies.
2921 * While you are checking those other frequencies, you can *NOT* be on
2922 * your normal frequency to listen to normal traffic in the cell.
2923 * You need typically in the order of one second to actively probe all
2924 * 802.11b channels (do the maths). Some cards may do that in background,
2925 * to reply to scan commands faster, but they still have to do it.
2926 * Leaving the cell for such an extended period of time is pretty bad.
2927 * Any kind of streaming/low latency traffic will be impacted, and the
2928 * user will perceive it (easily checked with telnet). People trying to
2929 * send traffic to you will retry packets and waste bandwidth. Some
2930 * applications may be sensitive to those packet losses in weird ways,
2931 * and tracing those weird behavior back to scanning may take time.
2932 * If you are in ad-hoc mode, if two nodes scan approx at the same
2933 * time, they won't see each other, which may create associations issues.
2934 * For those reasons, the scanning activity should be limited to
2935 * what's really needed, and continuous scanning is a bad idea.
2936 * Jean II
2937 */
2938  
2939 /*------------------------------------------------------------------*/
2940 /*
2941 * Process/store one element from the scanning results in wireless_scan
2942 */
2943 static inline struct wireless_scan *
2944 iw_process_scanning_token(struct iw_event * event,
2945 struct wireless_scan * wscan)
2946 {
2947 struct wireless_scan * oldwscan;
2948  
2949 /* Now, let's decode the event */
2950 switch(event->cmd)
2951 {
2952 case SIOCGIWAP:
2953 /* New cell description. Allocate new cell descriptor, zero it. */
2954 oldwscan = wscan;
2955 wscan = (struct wireless_scan *) malloc(sizeof(struct wireless_scan));
2956 if(wscan == NULL)
2957 return(wscan);
2958 /* Link at the end of the list */
2959 if(oldwscan != NULL)
2960 oldwscan->next = wscan;
2961  
2962 /* Reset it */
2963 bzero(wscan, sizeof(struct wireless_scan));
2964  
2965 /* Save cell identifier */
2966 wscan->has_ap_addr = 1;
2967 memcpy(&(wscan->ap_addr), &(event->u.ap_addr), sizeof (sockaddr));
2968 break;
2969 case SIOCGIWNWID:
2970 wscan->b.has_nwid = 1;
2971 memcpy(&(wscan->b.nwid), &(event->u.nwid), sizeof(iwparam));
2972 break;
2973 case SIOCGIWFREQ:
2974 wscan->b.has_freq = 1;
2975 wscan->b.freq = iw_freq2float(&(event->u.freq));
2976 wscan->b.freq_flags = event->u.freq.flags;
2977 break;
2978 case SIOCGIWMODE:
2979 wscan->b.mode = event->u.mode;
2980 if((wscan->b.mode < IW_NUM_OPER_MODE) && (wscan->b.mode >= 0))
2981 wscan->b.has_mode = 1;
2982 break;
2983 case SIOCGIWESSID:
2984 wscan->b.has_essid = 1;
2985 wscan->b.essid_on = event->u.data.flags;
2986 memset(wscan->b.essid, '\0', IW_ESSID_MAX_SIZE+1);
2987 if((event->u.essid.pointer) && (event->u.essid.length))
2988 memcpy(wscan->b.essid, event->u.essid.pointer, event->u.essid.length);
2989 break;
2990 case SIOCGIWENCODE:
2991 wscan->b.has_key = 1;
2992 wscan->b.key_size = event->u.data.length;
2993 wscan->b.key_flags = event->u.data.flags;
2994 if(event->u.data.pointer)
2995 memcpy(wscan->b.key, event->u.essid.pointer, event->u.data.length);
2996 else
2997 wscan->b.key_flags |= IW_ENCODE_NOKEY;
2998 break;
2999 case IWEVQUAL:
3000 /* We don't get complete stats, only qual */
3001 wscan->has_stats = 1;
3002 memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality));
3003 break;
3004 case SIOCGIWRATE:
3005 /* Scan may return a list of bitrates. As we have space for only
3006 * a single bitrate, we only keep the largest one. */
3007 if((!wscan->has_maxbitrate) ||
3008 (event->u.bitrate.value > wscan->maxbitrate.value))
3009 {
3010 wscan->has_maxbitrate = 1;
3011 memcpy(&(wscan->maxbitrate), &(event->u.bitrate), sizeof(iwparam));
3012 }
3013 case IWEVCUSTOM:
3014 /* How can we deal with those sanely ? Jean II */
3015 default:
3016 break;
3017 } /* switch(event->cmd) */
3018  
3019 return(wscan);
3020 }
3021  
3022 /*------------------------------------------------------------------*/
3023 /*
3024 * Initiate the scan procedure, and process results.
3025 * This is a non-blocking procedure and it will return each time
3026 * it would block, returning the amount of time the caller should wait
3027 * before calling again.
3028 * Return -1 for error, delay to wait for (in ms), or 0 for success.
3029 * Error code is in errno
3030 */
3031 int
3032 iw_process_scan(int skfd,
3033 char * ifname,
3034 int we_version,
3035 wireless_scan_head * context)
3036 {
3037 struct iwreq wrq;
3038 unsigned char * buffer = NULL; /* Results */
3039 int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
3040 unsigned char * newbuf;
3041  
3042 /* Don't waste too much time on interfaces (150 * 100 = 15s) */
3043 context->retry++;
3044 if(context->retry > 150)
3045 {
3046 errno = ETIME;
3047 return(-1);
3048 }
3049  
3050 /* If we have not yet initiated scanning on the interface */
3051 if(context->retry == 1)
3052 {
3053 /* Initiate Scan */
3054 wrq.u.data.pointer = NULL; /* Later */
3055 wrq.u.data.flags = 0;
3056 wrq.u.data.length = 0;
3057 /* Remember that as non-root, we will get an EPERM here */
3058 if((iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
3059 && (errno != EPERM))
3060 return(-1);
3061 /* Success : now, just wait for event or results */
3062 return(250); /* Wait 250 ms */
3063 }
3064  
3065 realloc:
3066 /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
3067 newbuf = realloc(buffer, buflen);
3068 if(newbuf == NULL)
3069 {
3070 /* man says : If realloc() fails the original block is left untouched */
3071 if(buffer)
3072 free(buffer);
3073 errno = ENOMEM;
3074 return(-1);
3075 }
3076 buffer = newbuf;
3077  
3078 /* Try to read the results */
3079 wrq.u.data.pointer = buffer;
3080 wrq.u.data.flags = 0;
3081 wrq.u.data.length = buflen;
3082 if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
3083 {
3084 /* Check if buffer was too small (WE-17 only) */
3085 if((errno == E2BIG) && (we_version > 16))
3086 {
3087 /* Some driver may return very large scan results, either
3088 * because there are many cells, or because they have many
3089 * large elements in cells (like IWEVCUSTOM). Most will
3090 * only need the regular sized buffer. We now use a dynamic
3091 * allocation of the buffer to satisfy everybody. Of course,
3092 * as we don't know in advance the size of the array, we try
3093 * various increasing sizes. Jean II */
3094  
3095 /* Check if the driver gave us any hints. */
3096 if(wrq.u.data.length > buflen)
3097 buflen = wrq.u.data.length;
3098 else
3099 buflen *= 2;
3100  
3101 /* Try again */
3102 goto realloc;
3103 }
3104  
3105 /* Check if results not available yet */
3106 if(errno == EAGAIN)
3107 {
3108 free(buffer);
3109 /* Wait for only 100ms from now on */
3110 return(100); /* Wait 100 ms */
3111 }
3112  
3113 free(buffer);
3114 /* Bad error, please don't come back... */
3115 return(-1);
3116 }
3117  
3118 /* We have the results, process them */
3119 if(wrq.u.data.length)
3120 {
3121 struct iw_event iwe;
3122 struct stream_descr stream;
3123 struct wireless_scan * wscan = NULL;
3124 int ret;
3125 #ifdef DEBUG
3126 /* Debugging code. In theory useless, because it's debugged ;-) */
3127 int i;
3128 printf("Scan result [%02X", buffer[0]);
3129 for(i = 1; i < wrq.u.data.length; i++)
3130 printf(":%02X", buffer[i]);
3131 printf("]\n");
3132 #endif
3133  
3134 /* Init */
3135 iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
3136 /* This is dangerous, we may leak user data... */
3137 context->result = NULL;
3138  
3139 /* Look every token */
3140 do
3141 {
3142 /* Extract an event and print it */
3143 ret = iw_extract_event_stream(&stream, &iwe, we_version);
3144 if(ret > 0)
3145 {
3146 /* Convert to wireless_scan struct */
3147 wscan = iw_process_scanning_token(&iwe, wscan);
3148 /* Check problems */
3149 if(wscan == NULL)
3150 {
3151 free(buffer);
3152 errno = ENOMEM;
3153 return(-1);
3154 }
3155 /* Save head of list */
3156 if(context->result == NULL)
3157 context->result = wscan;
3158 }
3159 }
3160 while(ret > 0);
3161 }
3162  
3163 /* Done with this interface - return success */
3164 free(buffer);
3165 return(0);
3166 }
3167  
3168 /*------------------------------------------------------------------*/
3169 /*
3170 * Perform a wireless scan on the specified interface.
3171 * This is a blocking procedure and it will when the scan is completed
3172 * or when an error occur.
3173 *
3174 * The scan results are given in a linked list of wireless_scan objects.
3175 * The caller *must* free the result himself (by walking the list).
3176 * If there is an error, -1 is returned and the error code is available
3177 * in errno.
3178 *
3179 * The parameter we_version can be extracted from the range structure
3180 * (range.we_version_compiled - see iw_get_range_info()), or using
3181 * iw_get_kernel_we_version(). For performance reason, you should
3182 * cache this parameter when possible rather than querying it every time.
3183 *
3184 * Return -1 for error and 0 for success.
3185 */
3186 int
3187 iw_scan(int skfd,
3188 char * ifname,
3189 int we_version,
3190 wireless_scan_head * context)
3191 {
3192 int delay; /* in ms */
3193  
3194 /* Clean up context. Potential memory leak if(context.result != NULL) */
3195 context->result = NULL;
3196 context->retry = 0;
3197  
3198 /* Wait until we get results or error */
3199 while(1)
3200 {
3201 /* Try to get scan results */
3202 delay = iw_process_scan(skfd, ifname, we_version, context);
3203  
3204 /* Check termination */
3205 if(delay <= 0)
3206 break;
3207  
3208 /* Wait a bit */
3209 usleep(delay * 1000);
3210 }
3211  
3212 /* End - return -1 or 0 */
3213 return(delay);
3214 }