OSDN Git Service

v21
[android-x86/external-wireless-tools.git] / wireless_tools / iwlib.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB 97->99 - HPL 99->01
5  *
6  * Common subroutines to all the wireless tools...
7  *
8  * This file is released under the GPL license.
9  */
10
11 #include "iwlib.h"              /* Header */
12
13 /**************************** VARIABLES ****************************/
14
15 const char *    iw_operation_mode[] = { "Auto",
16                                         "Ad-Hoc",
17                                         "Managed",
18                                         "Master",
19                                         "Repeater",
20                                         "Secondary" };
21
22 /************************ SOCKET SUBROUTINES *************************/
23
24 /*------------------------------------------------------------------*/
25 /*
26  * Open a socket.
27  * Depending on the protocol present, open the right socket. The socket
28  * will allow us to talk to the driver.
29  */
30 int
31 iw_sockets_open(void)
32 {
33         int ipx_sock = -1;              /* IPX socket                   */
34         int ax25_sock = -1;             /* AX.25 socket                 */
35         int inet_sock = -1;             /* INET socket                  */
36         int ddp_sock = -1;              /* Appletalk DDP socket         */
37
38         /*
39          * Now pick any (exisiting) useful socket family for generic queries
40          * Note : don't open all the socket, only returns when one matches,
41          * all protocols might not be valid.
42          * Workaround by Jim Kaba <jkaba@sarnoff.com>
43          * Note : in 99% of the case, we will just open the inet_sock.
44          * The remaining 1% case are not fully correct...
45          */
46         inet_sock=socket(AF_INET, SOCK_DGRAM, 0);
47         if(inet_sock!=-1)
48                 return inet_sock;
49         ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0);
50         if(ipx_sock!=-1)
51                 return ipx_sock;
52         ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0);
53         if(ax25_sock!=-1)
54                 return ax25_sock;
55         ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0);
56         /*
57          * If this is -1 we have no known network layers and its time to jump.
58          */
59         return ddp_sock;
60 }
61
62 /*********************** WIRELESS SUBROUTINES ************************/
63
64 /*------------------------------------------------------------------*/
65 /*
66  * Get the range information out of the driver
67  */
68 int
69 iw_get_range_info(int           skfd,
70                   char *        ifname,
71                   iwrange *     range)
72 {
73   struct iwreq          wrq;
74   char                  buffer[sizeof(iwrange) * 2];    /* Large enough */
75
76   /* Cleanup */
77   memset(buffer, 0, sizeof(range));
78
79   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
80   wrq.u.data.pointer = (caddr_t) buffer;
81   wrq.u.data.length = 0;
82   wrq.u.data.flags = 0;
83   if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
84     return(-1);
85
86   /* Copy stuff at the right place, ignore extra */
87   memcpy((char *) range, buffer, sizeof(iwrange));
88
89   /* Lot's of people have driver and tools out of sync as far as Wireless
90    * Extensions are concerned. It's because /usr/include/linux/wireless.h
91    * and /usr/src/linux/include/linux/wireless.h are different.
92    * We try to catch this stuff here... */
93
94   /* For new versions, we can check the version directly, for old versions
95    * we use magic. 300 bytes is a also magic number, don't touch... */
96   if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
97     {
98 #if WIRELESS_EXT > 10
99       /* Version verification - for new versions */
100       if(range->we_version_compiled != WIRELESS_EXT)
101         {
102           fprintf(stderr, "Warning : Device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
103           fprintf(stderr, "of Wireless Extension, while we are using version %d.\n", WIRELESS_EXT);
104           fprintf(stderr, "Some things may be broken...\n\n");
105         }
106 #endif /* WIRELESS_EXT > 10 */
107     }
108   else
109     {
110       /* Version verification - for old versions */
111       if(wrq.u.data.length != sizeof(iwrange))
112         {
113           fprintf(stderr, "Warning : Device %s has been compiled with a different version\n", ifname);
114           fprintf(stderr, "of Wireless Extension than ours (we are using version %d).\n", WIRELESS_EXT);
115           fprintf(stderr, "Some things may be broken...\n\n");
116         }
117     }
118
119   /* Note : we are only trying to catch compile difference, not source.
120    * If the driver source has not been updated to the latest, it doesn't
121    * matter because the new fields are set to zero */
122
123   return(0);
124 }
125
126 /*------------------------------------------------------------------*/
127 /*
128  * Get information about what private ioctls are supported by the driver
129  */
130 int
131 iw_get_priv_info(int            skfd,
132                  char *         ifname,
133                  iwprivargs *   priv)
134 {
135   struct iwreq          wrq;
136
137   /* Ask the driver */
138   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
139   wrq.u.data.pointer = (caddr_t) priv;
140   wrq.u.data.length = 0;
141   wrq.u.data.flags = 0;
142   if(ioctl(skfd, SIOCGIWPRIV, &wrq) < 0)
143     return(-1);
144
145   /* Return the number of ioctls */
146   return(wrq.u.data.length);
147 }
148
149 /*------------------------------------------------------------------*/
150 /*
151  * Get essential wireless config from the device driver
152  * We will call all the classical wireless ioctl on the driver through
153  * the socket to know what is supported and to get the settings...
154  * Note : compare to the version in iwconfig, we extract only
155  * what's *really* needed to configure a device...
156  */
157 int
158 iw_get_basic_config(int                 skfd,
159                     char *              ifname,
160                     wireless_config *   info)
161 {
162   struct iwreq          wrq;
163
164   memset((char *) info, 0, sizeof(struct wireless_config));
165
166   /* Get wireless name */
167   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
168   if(ioctl(skfd, SIOCGIWNAME, &wrq) < 0)
169     /* If no wireless name : no wireless extensions */
170     return(-1);
171   else
172     strcpy(info->name, wrq.u.name);
173
174   /* Get network ID */
175   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
176   if(ioctl(skfd, SIOCGIWNWID, &wrq) >= 0)
177     {
178       info->has_nwid = 1;
179       memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
180     }
181
182   /* Get frequency / channel */
183   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
184   if(ioctl(skfd, SIOCGIWFREQ, &wrq) >= 0)
185     {
186       info->has_freq = 1;
187       info->freq = iw_freq2float(&(wrq.u.freq));
188     }
189
190   /* Get encryption information */
191   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
192   wrq.u.data.pointer = (caddr_t) info->key;
193   wrq.u.data.length = 0;
194   wrq.u.data.flags = 0;
195   if(ioctl(skfd, SIOCGIWENCODE, &wrq) >= 0)
196     {
197       info->has_key = 1;
198       info->key_size = wrq.u.data.length;
199       info->key_flags = wrq.u.data.flags;
200     }
201
202   /* Get ESSID */
203   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
204   wrq.u.essid.pointer = (caddr_t) info->essid;
205   wrq.u.essid.length = 0;
206   wrq.u.essid.flags = 0;
207   if(ioctl(skfd, SIOCGIWESSID, &wrq) >= 0)
208     {
209       info->has_essid = 1;
210       info->essid_on = wrq.u.data.flags;
211     }
212
213   /* Get operation mode */
214   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
215   if(ioctl(skfd, SIOCGIWMODE, &wrq) >= 0)
216     {
217       if((wrq.u.mode < 6) && (wrq.u.mode >= 0))
218         info->has_mode = 1;
219       info->mode = wrq.u.mode;
220     }
221
222   return(0);
223 }
224
225 /*------------------------------------------------------------------*/
226 /*
227  * Set essential wireless config in the device driver
228  * We will call all the classical wireless ioctl on the driver through
229  * the socket to know what is supported and to set the settings...
230  * We support only the restricted set as above...
231  */
232 int
233 iw_set_basic_config(int                 skfd,
234                     char *              ifname,
235                     wireless_config *   info)
236 {
237   struct iwreq          wrq;
238   int                   ret = 0;
239
240   /* Get wireless name (check if interface is valid) */
241   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
242   if(ioctl(skfd, SIOCGIWNAME, &wrq) < 0)
243     /* If no wireless name : no wireless extensions */
244     return(-2);
245
246   /* Set Network ID, if available (this is for non-802.11 cards) */
247   if(info->has_nwid)
248     {
249       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
250       memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
251       wrq.u.nwid.fixed = 1;     /* Hum... When in Rome... */
252
253       if(ioctl(skfd, SIOCSIWNWID, &wrq) < 0)
254         {
255           fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
256           ret = -1;
257         }
258     }
259
260   /* Set frequency / channel */
261   if(info->has_freq)
262     {
263       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
264       iw_float2freq(info->freq, &(wrq.u.freq));
265
266       if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0)
267         {
268           fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
269           ret = -1;
270         }
271     }
272
273   /* Set encryption information */
274   if(info->has_key)
275     {
276       int               flags = info->key_flags;
277
278       /* Check if there is a key index */
279       if((flags & IW_ENCODE_INDEX) > 0)
280         {
281           /* Set the index */
282           strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
283           wrq.u.data.pointer = (caddr_t) NULL;
284           wrq.u.data.flags = flags & (IW_ENCODE_INDEX);
285           wrq.u.data.length = 0;
286
287           if(ioctl(skfd, SIOCSIWENCODE, &wrq) < 0)
288             {
289               fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
290                       errno, strerror(errno));
291               ret = -1;
292             }
293         }
294
295       /* Mask out index to minimise probability of reject when setting key */
296       flags = flags & (~IW_ENCODE_INDEX);
297
298       /* Set the key itself (set current key in this case) */
299       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
300       wrq.u.data.pointer = (caddr_t) info->key;
301       wrq.u.data.length = info->key_size;
302       wrq.u.data.flags = flags;
303
304       if(ioctl(skfd, SIOCSIWENCODE, &wrq) < 0)
305         {
306           fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
307                   errno, strerror(errno));
308           ret = -1;
309         }
310     }
311
312   /* Set ESSID (extended network), if available */
313   if(info->has_essid)
314     {
315       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
316       wrq.u.essid.pointer = (caddr_t) info->essid;
317       wrq.u.essid.length = strlen(info->essid) + 1;
318       wrq.u.data.flags = info->essid_on;
319
320       if(ioctl(skfd, SIOCSIWESSID, &wrq) < 0)
321         {
322           fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
323           ret = -1;
324         }
325     }
326
327   /* Set the current mode of operation */
328   if(info->has_mode)
329     {
330       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
331       wrq.u.mode = info->mode;
332
333       if(ioctl(skfd, SIOCSIWMODE, &wrq) < 0)
334         {
335           fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
336           ret = -1;
337         }
338     }
339
340   return(ret);
341 }
342
343 /********************** FREQUENCY SUBROUTINES ***********************/
344
345 /*------------------------------------------------------------------*/
346 /*
347  * Convert a floating point the our internal representation of
348  * frequencies.
349  * The kernel doesn't want to hear about floating point, so we use
350  * this custom format instead.
351  */
352 void
353 iw_float2freq(double    in,
354               iwfreq *  out)
355 {
356   out->e = (short) (floor(log10(in)));
357   if(out->e > 8)
358     {
359       out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
360       out->e -= 8;
361     }
362   else
363     {
364       out->m = in;
365       out->e = 0;
366     }
367 }
368
369 /*------------------------------------------------------------------*/
370 /*
371  * Convert our internal representation of frequencies to a floating point.
372  */
373 double
374 iw_freq2float(iwfreq *  in)
375 {
376   return ((double) in->m) * pow(10,in->e);
377 }
378
379 /************************ POWER SUBROUTINES *************************/
380
381 /*------------------------------------------------------------------*/
382 /*
383  * Convert a value in dBm to a value in milliWatt.
384  */
385 int
386 iw_dbm2mwatt(int        in)
387 {
388   return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
389 }
390
391 /*------------------------------------------------------------------*/
392 /*
393  * Convert a value in milliWatt to a value in dBm.
394  */
395 int
396 iw_mwatt2dbm(int        in)
397 {
398   return((int) (ceil(10.0 * log10((double) in))));
399 }
400
401 /********************** STATISTICS SUBROUTINES **********************/
402
403 /*------------------------------------------------------------------*/
404 /*
405  * Read /proc/net/wireless to get the latest statistics
406  */
407 int
408 iw_get_stats(int        skfd,
409              char *     ifname,
410              iwstats *  stats)
411 {
412 #if WIRELESS_EXT > 11
413   struct iwreq          wrq;
414   wrq.u.data.pointer = (caddr_t) stats;
415   wrq.u.data.length = 0;
416   wrq.u.data.flags = 1;         /* Clear updated flag */
417   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
418   if(ioctl(skfd, SIOCGIWSTATS, &wrq) < 0)
419     return(-1);
420
421   return(0);
422 #else /* WIRELESS_EXT > 11 */
423   FILE *        f=fopen("/proc/net/wireless","r");
424   char          buf[256];
425   char *        bp;
426   int           t;
427   if(f==NULL)
428     return -1;
429   /* Loop on all devices */
430   while(fgets(buf,255,f))
431     {
432       bp=buf;
433       while(*bp&&isspace(*bp))
434         bp++;
435       /* Is it the good device ? */
436       if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
437         {
438           /* Skip ethX: */
439           bp=strchr(bp,':');
440           bp++;
441           /* -- status -- */
442           bp = strtok(bp, " ");
443           sscanf(bp, "%X", &t);
444           stats->status = (unsigned short) t;
445           /* -- link quality -- */
446           bp = strtok(NULL, " ");
447           if(strchr(bp,'.') != NULL)
448             stats->qual.updated |= 1;
449           sscanf(bp, "%d", &t);
450           stats->qual.qual = (unsigned char) t;
451           /* -- signal level -- */
452           bp = strtok(NULL, " ");
453           if(strchr(bp,'.') != NULL)
454             stats->qual.updated |= 2;
455           sscanf(bp, "%d", &t);
456           stats->qual.level = (unsigned char) t;
457           /* -- noise level -- */
458           bp = strtok(NULL, " ");
459           if(strchr(bp,'.') != NULL)
460             stats->qual.updated += 4;
461           sscanf(bp, "%d", &t);
462           stats->qual.noise = (unsigned char) t;
463           /* -- discarded packets -- */
464           bp = strtok(NULL, " ");
465           sscanf(bp, "%d", &stats->discard.nwid);
466           bp = strtok(NULL, " ");
467           sscanf(bp, "%d", &stats->discard.code);
468           bp = strtok(NULL, " ");
469           sscanf(bp, "%d", &stats->discard.misc);
470           fclose(f);
471           return 0;
472         }
473     }
474   fclose(f);
475   return -1;
476 #endif /* WIRELESS_EXT > 11 */
477 }
478
479 /*------------------------------------------------------------------*/
480 /*
481  * Output the link statistics, taking care of formating
482  */
483 void
484 iw_print_stats(char *           buffer,
485                iwqual *         qual,
486                iwrange *        range,
487                int              has_range)
488 {
489   /* Just do it */
490   if(has_range && (qual->level != 0))
491     {
492       /* If the statistics are in dBm */
493       if(qual->level > range->max_qual.level)
494         {
495           /* Statistics are in dBm (absolute power measurement) */
496           sprintf(buffer,
497                   "Quality:%d/%d  Signal level:%d dBm  Noise level:%d dBm%s",
498                   qual->qual, range->max_qual.qual,
499                   qual->level - 0x100, qual->noise - 0x100,
500                   (qual->updated & 0x7) ? " (updated)" : "");
501         }
502       else
503         {
504           /* Statistics are relative values (0 -> max) */
505           sprintf(buffer,
506                   "Quality:%d/%d  Signal level:%d/%d  Noise level:%d/%d%s",
507                   qual->qual, range->max_qual.qual,
508                   qual->level, range->max_qual.level,
509                   qual->noise, range->max_qual.noise,
510                   (qual->updated & 0x7) ? " (updated)" : "");
511         }
512     }
513   else
514     {
515       /* We can't read the range, so we don't know... */
516       sprintf(buffer, "Quality:%d  Signal level:%d  Noise level:%d%s",
517               qual->qual, qual->level, qual->noise,
518               (qual->updated & 0x7) ? " (updated)" : "");
519     }
520 }
521
522 /*********************** ENCODING SUBROUTINES ***********************/
523
524 /*------------------------------------------------------------------*/
525 /*
526  * Output the encoding key, with a nice formating
527  */
528 void
529 iw_print_key(char *             buffer,
530              unsigned char *    key,
531              int                key_size,
532              int                key_flags)
533 {
534   int   i;
535
536   /* Is the key present ??? */
537   if(key_flags & IW_ENCODE_NOKEY)
538     {
539       /* Nope : print dummy */
540       strcpy(buffer, "**");
541       buffer +=2;
542       for(i = 1; i < key_size; i++)
543         {
544           if((i & 0x1) == 0)
545             strcpy(buffer++, "-");
546           strcpy(buffer, "**");
547           buffer +=2;
548         }
549     }
550   else
551     {
552       /* Yes : print the key */
553       sprintf(buffer, "%.2X", key[0]);
554       buffer +=2;
555       for(i = 1; i < key_size; i++)
556         {
557           if((i & 0x1) == 0)
558             strcpy(buffer++, "-");
559           sprintf(buffer, "%.2X", key[i]);
560           buffer +=2;
561         }
562     }
563 }
564
565
566 /******************* POWER MANAGEMENT SUBROUTINES *******************/
567
568 /*------------------------------------------------------------------*/
569 /*
570  * Output a power management value with all attributes...
571  */
572 void
573 iw_print_pm_value(char *        buffer,
574                   int           value,
575                   int           flags)
576 {
577   /* Modifiers */
578   if(flags & IW_POWER_MIN)
579     {
580       strcpy(buffer, " min");
581       buffer += 4;
582     }
583   if(flags & IW_POWER_MAX)
584     {
585       strcpy(buffer, " max");
586       buffer += 4;
587     }
588
589   /* Type */
590   if(flags & IW_POWER_TIMEOUT)
591     {
592       strcpy(buffer, " timeout:");
593       buffer += 9;
594     }
595   else
596     {
597       strcpy(buffer, " period:");
598       buffer += 8;
599     }
600
601   /* Display value without units */
602   if(flags & IW_POWER_RELATIVE)
603     sprintf(buffer, "%g  ", ((double) value) / MEGA);
604   else
605     {
606       /* Display value with units */
607       if(value >= (int) MEGA)
608         sprintf(buffer, "%gs  ", ((double) value) / MEGA);
609       else
610         if(value >= (int) KILO)
611           sprintf(buffer, "%gms  ", ((double) value) / KILO);
612         else
613           sprintf(buffer, "%dus  ", value);
614     }
615 }
616
617 /*------------------------------------------------------------------*/
618 /*
619  * Output a power management mode
620  */
621 void
622 iw_print_pm_mode(char * buffer,
623                  int    flags)
624 {
625   /* Print the proper mode... */
626   switch(flags & IW_POWER_MODE)
627     {
628     case IW_POWER_UNICAST_R:
629       strcpy(buffer, " mode:Unicast only received");
630       break;
631     case IW_POWER_MULTICAST_R:
632       strcpy(buffer, " mode:Multicast only received");
633       break;
634     case IW_POWER_ALL_R:
635       strcpy(buffer, " mode:All packets received");
636       break;
637     case IW_POWER_FORCE_S:
638       strcpy(buffer, " mode:Force sending");
639       break;
640     case IW_POWER_REPEATER:
641       strcpy(buffer, " mode:Repeat multicasts");
642       break;
643     default:
644     }
645 }
646
647 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
648
649 #if WIRELESS_EXT > 10
650 /*------------------------------------------------------------------*/
651 /*
652  * Output a retry value with all attributes...
653  */
654 void
655 iw_print_retry_value(char *     buffer,
656                      int        value,
657                      int        flags)
658 {
659   /* Modifiers */
660   if(flags & IW_RETRY_MIN)
661     {
662       strcpy(buffer, " min");
663       buffer += 4;
664     }
665   if(flags & IW_RETRY_MAX)
666     {
667       strcpy(buffer, " max");
668       buffer += 4;
669     }
670
671   /* Type lifetime of limit */
672   if(flags & IW_RETRY_LIFETIME)
673     {
674       strcpy(buffer, " lifetime:");
675       buffer += 10;
676
677       /* Display value without units */
678       if(flags & IW_POWER_RELATIVE)
679         sprintf(buffer, "%g", ((double) value) / MEGA);
680       else
681         {
682           /* Display value with units */
683           if(value >= (int) MEGA)
684             sprintf(buffer, "%gs", ((double) value) / MEGA);
685           else
686             if(value >= (int) KILO)
687               sprintf(buffer, "%gms", ((double) value) / KILO);
688             else
689               sprintf(buffer, "%dus", value);
690         }
691     }
692   else
693     sprintf(buffer, " limit:%d", value);
694 }
695 #endif  /* WIRELESS_EXT > 10 */
696
697 /*********************** ADDRESS SUBROUTINES ************************/
698 /*
699  * This section is mostly a cut & past from net-tools-1.2.0
700  * manage address display and input...
701  */
702
703 /*------------------------------------------------------------------*/
704 /*
705  * Check if interface support the right address types...
706  */
707 int
708 iw_check_addr_type(int          skfd,
709                    char *       ifname)
710 {
711   struct ifreq          ifr;
712
713   /* Get the type of interface address */
714   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
715   if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
716      (ifr.ifr_addr.sa_family !=  AF_INET))
717     {
718       /* Deep trouble... */
719       fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
720       return(-1);
721     }
722
723 #ifdef DEBUG
724   printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
725          *((unsigned long *) ifr.ifr_addr.sa_data));
726 #endif
727
728   /* Get the type of hardware address */
729   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
730   if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
731      (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER))
732     {
733       /* Deep trouble... */
734       fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
735              ifname);
736       return(-1);
737     }
738
739 #ifdef DEBUG
740   printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
741          pr_ether(ifr.ifr_hwaddr.sa_data));
742 #endif
743
744   return(0);
745 }
746
747
748 /*------------------------------------------------------------------*/
749 /*
750  * Display an Ethernet address in readable format.
751  */
752 char *
753 iw_pr_ether(char *              buffer,
754             unsigned char *     ptr)
755 {
756   sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X",
757           (ptr[0] & 0xFF), (ptr[1] & 0xFF), (ptr[2] & 0xFF),
758           (ptr[3] & 0xFF), (ptr[4] & 0xFF), (ptr[5] & 0xFF)
759   );
760   return(buffer);
761 }
762
763 /*------------------------------------------------------------------*/
764 /*
765  * Input an Ethernet address and convert to binary.
766  */
767 int
768 iw_in_ether(char *bufp, struct sockaddr *sap)
769 {
770   unsigned char *ptr;
771   char c, *orig;
772   int i, val;
773
774   sap->sa_family = ARPHRD_ETHER;
775   ptr = sap->sa_data;
776
777   i = 0;
778   orig = bufp;
779   while((*bufp != '\0') && (i < ETH_ALEN)) {
780         val = 0;
781         c = *bufp++;
782         if (isdigit(c)) val = c - '0';
783           else if (c >= 'a' && c <= 'f') val = c - 'a' + 10;
784           else if (c >= 'A' && c <= 'F') val = c - 'A' + 10;
785           else {
786 #ifdef DEBUG
787                 fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
788 #endif
789                 errno = EINVAL;
790                 return(-1);
791         }
792         val <<= 4;
793         c = *bufp++;
794         if (isdigit(c)) val |= c - '0';
795           else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10;
796           else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10;
797           else {
798 #ifdef DEBUG
799                 fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
800 #endif
801                 errno = EINVAL;
802                 return(-1);
803         }
804         *ptr++ = (unsigned char) (val & 0377);
805         i++;
806
807         /* We might get a semicolon here - not required. */
808         if (*bufp == ':') {
809                 if (i == ETH_ALEN) {
810 #ifdef DEBUG
811                         fprintf(stderr, "in_ether(%s): trailing : ignored!\n",
812                                 orig)
813 #endif
814                                                 ; /* nothing */
815                 }
816                 bufp++;
817         }
818   }
819
820   /* That's it.  Any trailing junk? */
821   if ((i == ETH_ALEN) && (*bufp != '\0')) {
822 #ifdef DEBUG
823         fprintf(stderr, "in_ether(%s): trailing junk!\n", orig);
824         errno = EINVAL;
825         return(-1);
826 #endif
827   }
828
829 #ifdef DEBUG
830   fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data));
831 #endif
832
833   return(0);
834 }
835
836 /*------------------------------------------------------------------*/
837 /*
838  * Input an Internet address and convert to binary.
839  */
840 int
841 iw_in_inet(char *bufp, struct sockaddr *sap)
842 {
843   struct hostent *hp;
844   struct netent *np;
845   char *name = bufp;
846   struct sockaddr_in *sin = (struct sockaddr_in *) sap;
847
848   /* Grmpf. -FvK */
849   sin->sin_family = AF_INET;
850   sin->sin_port = 0;
851
852   /* Default is special, meaning 0.0.0.0. */
853   if (!strcmp(name, "default")) {
854         sin->sin_addr.s_addr = INADDR_ANY;
855         return(1);
856   }
857
858   /* Try the NETWORKS database to see if this is a known network. */
859   if ((np = getnetbyname(name)) != (struct netent *)NULL) {
860         sin->sin_addr.s_addr = htonl(np->n_net);
861         strcpy(name, np->n_name);
862         return(1);
863   }
864
865   if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
866         errno = h_errno;
867         return(-1);
868   }
869   memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
870   strcpy(name, hp->h_name);
871   return(0);
872 }
873
874 /*------------------------------------------------------------------*/
875 /*
876  * Input an address and convert to binary.
877  */
878 int
879 iw_in_addr(int          skfd,
880            char *       ifname,
881            char *       bufp,
882            struct sockaddr *sap)
883 {
884   /* Check if it is a hardware or IP address */
885   if(index(bufp, ':') == NULL)
886     {
887       struct sockaddr   if_address;
888       struct arpreq     arp_query;
889
890       /* Read interface address */
891       if(iw_in_inet(bufp, &if_address) < 0)
892         {
893           fprintf(stderr, "Invalid interface address %s\n", bufp);
894           return(-1);
895         }
896
897       /* Translate IP addresses to MAC addresses */
898       memcpy((char *) &(arp_query.arp_pa),
899              (char *) &if_address,
900              sizeof(struct sockaddr));
901       arp_query.arp_ha.sa_family = 0;
902       arp_query.arp_flags = 0;
903       /* The following restrict the search to the interface only */
904       /* For old kernels which complain, just comment it... */
905       strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
906       if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
907          !(arp_query.arp_flags & ATF_COM))
908         {
909           fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
910                   bufp, ifname, errno);
911           return(-1);
912         }
913
914       /* Store new MAC address */
915       memcpy((char *) sap,
916              (char *) &(arp_query.arp_ha),
917              sizeof(struct sockaddr));
918
919 #ifdef DEBUG
920       printf("IP Address %s => Hw Address = %s\n",
921              bufp, pr_ether(sap->sa_data));
922 #endif
923     }
924   else  /* If it's an hardware address */
925     /* Get the hardware address */
926     if(iw_in_ether(bufp, sap) < 0)
927       {
928         fprintf(stderr, "Invalid hardware address %s\n", bufp);
929         return(-1);
930       }
931
932 #ifdef DEBUG
933   printf("Hw Address = %s\n", pr_ether(sap->sa_data));
934 #endif
935
936   return(0);
937 }
938
939 /************************* MISC SUBROUTINES **************************/
940
941 /*------------------------------------------------------------------*/
942 /*
943  */
944 int
945 iw_byte_size(int        args)
946 {
947   int   ret = args & IW_PRIV_SIZE_MASK;
948
949   if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) ||
950      ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT))
951     ret <<= 2;
952
953   if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE)
954     return 0;
955
956   return ret;
957 }
958