OSDN Git Service

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