859bb1f1dab0976b90b01a00345c97bf47b3c951
[project/luci.git] / libs / iwinfo / src / iwinfo_wext.c
1 /*
2  * iwinfo - Wireless Information Library - Linux Wireless Extension Backend
3  *
4  *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5  *
6  * The iwinfo library is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation.
9  *
10  * The iwinfo library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
17  *
18  * Parts of this code are derived from the Linux wireless tools, iwlib.c,
19  * iwlist.c and iwconfig.c in particular.
20  */
21
22 #include "iwinfo.h"
23 #include "iwinfo_wext.h"
24
25 static int ioctl_socket = -1;
26
27 static double wext_freq2float(const struct iw_freq *in)
28 {
29         int             i;
30         double  res = (double) in->m;
31         for(i = 0; i < in->e; i++) res *= 10;
32         return res;
33 }
34
35 static int wext_freq2mhz(const struct iw_freq *in)
36 {
37         int i, mhz;
38
39         if( in->e == 6 )
40         {
41                 return in->m;
42         }
43         else
44         {
45                 mhz = in->m;
46                 for(i = 0; i < in->e; i++)
47                         mhz *= 10;
48
49                 return (int)(mhz / 100000);
50         }
51 }
52
53 static int wext_ioctl(const char *ifname, int cmd, struct iwreq *wrq)
54 {
55         /* prepare socket */
56         if( ioctl_socket == -1 )
57                 ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0);
58
59         strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
60         return ioctl(ioctl_socket, cmd, wrq);
61 }
62
63
64 int wext_probe(const char *ifname)
65 {
66         struct iwreq wrq;
67
68         if(wext_ioctl(ifname, SIOCGIWNAME, &wrq) >= 0)
69                 return 1;
70
71         return 0;
72 }
73
74 int wext_get_mode(const char *ifname, char *buf)
75 {
76         struct iwreq wrq;
77
78         if(wext_ioctl(ifname, SIOCGIWMODE, &wrq) >= 0)
79         {
80                 switch(wrq.u.mode)
81                 {
82                         case 0:
83                                 sprintf(buf, "Auto");
84                                 break;
85
86                         case 1:
87                                 sprintf(buf, "Ad-Hoc");
88                                 break;
89
90                         case 2:
91                                 sprintf(buf, "Client");
92                                 break;
93
94                         case 3:
95                                 sprintf(buf, "Master");
96                                 break;
97
98                         case 4:
99                                 sprintf(buf, "Repeater");
100                                 break;
101
102                         case 5:
103                                 sprintf(buf, "Secondary");
104                                 break;
105
106                         case 6:
107                                 sprintf(buf, "Monitor");
108                                 break;
109
110                         default:
111                                 sprintf(buf, "Unknown");
112                 }
113
114                 return 0;
115         }
116
117         return -1;
118 }
119
120 int wext_get_ssid(const char *ifname, char *buf)
121 {
122         struct iwreq wrq;
123
124         wrq.u.essid.pointer = (caddr_t) buf;
125         wrq.u.essid.length  = IW_ESSID_MAX_SIZE + 1;
126         wrq.u.essid.flags   = 0;
127
128         if(wext_ioctl(ifname, SIOCGIWESSID, &wrq) >= 0)
129                 return 0;
130
131         return -1;
132 }
133
134 int wext_get_bssid(const char *ifname, char *buf)
135 {
136         struct iwreq wrq;
137
138         if(wext_ioctl(ifname, SIOCGIWAP, &wrq) >= 0)
139         {
140                 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
141                         (uint8_t)wrq.u.ap_addr.sa_data[0], (uint8_t)wrq.u.ap_addr.sa_data[1],
142                         (uint8_t)wrq.u.ap_addr.sa_data[2], (uint8_t)wrq.u.ap_addr.sa_data[3],
143                         (uint8_t)wrq.u.ap_addr.sa_data[4], (uint8_t)wrq.u.ap_addr.sa_data[5]);
144
145                 return 0;
146         }
147
148         return -1;      
149 }
150
151 int wext_get_bitrate(const char *ifname, int *buf)
152 {
153         struct iwreq wrq;
154
155         if(wext_ioctl(ifname, SIOCGIWRATE, &wrq) >= 0)
156         {
157                 *buf = wrq.u.bitrate.value;
158                 return 0;
159         }
160
161         return -1;      
162 }
163
164 int wext_get_channel(const char *ifname, int *buf)
165 {
166         struct iwreq wrq;
167
168         if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
169         {
170                 /* FIXME: iwlib has some strange workarounds here, maybe we need them as well... */
171                 *buf = (int) wext_freq2float(&wrq.u.freq);
172                 return 0;
173         }
174
175         return -1;      
176 }
177
178 int wext_get_frequency(const char *ifname, int *buf)
179 {
180         struct iwreq wrq;
181         struct iw_range range;
182         int i, channel;
183
184         if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
185         {
186                 /* We got a channel number instead ... */
187                 if( wrq.u.freq.m < 1000 )
188                 {
189                         channel = wrq.u.freq.m;
190                         wrq.u.data.pointer = (caddr_t) &range;
191                         wrq.u.data.length  = sizeof(struct iw_range);
192                         wrq.u.data.flags   = 0;
193
194                         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
195                         {
196                                 for(i = 0; i < range.num_frequency; i++)
197                                 {
198                                         if( range.freq[i].i == channel )
199                                         {
200                                                 *buf = wext_freq2mhz(&range.freq[i]);
201                                                 return 0;
202                                         }
203                                 }
204                         }
205                 }
206                 else
207                 {
208                         *buf = wext_freq2mhz(&wrq.u.freq);
209                         return 0;
210                 }
211         }
212
213         return -1;      
214 }
215
216 int wext_get_signal(const char *ifname, int *buf)
217 {
218         struct iwreq wrq;
219         struct iw_statistics stats;
220
221         wrq.u.data.pointer = (caddr_t) &stats;
222         wrq.u.data.length  = sizeof(struct iw_statistics);
223         wrq.u.data.flags   = 1;
224
225         if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
226         {
227                 *buf = (stats.qual.level - 0x100);
228                 return 0;
229         }
230
231         return -1;
232 }
233
234 int wext_get_noise(const char *ifname, int *buf)
235 {
236         struct iwreq wrq;
237         struct iw_statistics stats;
238
239         wrq.u.data.pointer = (caddr_t) &stats;
240         wrq.u.data.length  = sizeof(struct iw_statistics);
241         wrq.u.data.flags   = 1;
242
243         if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
244         {
245                 *buf = (stats.qual.noise - 0x100);
246                 return 0;
247         }
248
249         return -1;
250 }
251
252 int wext_get_quality(const char *ifname, int *buf)
253 {
254         struct iwreq wrq;
255         struct iw_statistics stats;
256
257         wrq.u.data.pointer = (caddr_t) &stats;
258         wrq.u.data.length  = sizeof(struct iw_statistics);
259         wrq.u.data.flags   = 1;
260
261         if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
262         {
263                 *buf = stats.qual.qual;
264                 return 0;
265         }
266
267         return -1;
268 }
269
270 int wext_get_quality_max(const char *ifname, int *buf)
271 {
272         struct iwreq wrq;
273         struct iw_range range;
274
275         wrq.u.data.pointer = (caddr_t) &range;
276         wrq.u.data.length  = sizeof(struct iw_range);
277         wrq.u.data.flags   = 0;
278
279         if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
280         {
281                 *buf = range.max_qual.qual;
282                 return 0;
283         }
284
285         return -1;
286 }
287
288 int wext_get_enctype(const char *ifname, char *buf)
289 {
290         /* Stub */
291         return -1;
292 }
293
294 int wext_get_assoclist(const char *ifname, char *buf, int *len)
295 {
296         /* Stub */
297         return -1;
298 }
299
300 int wext_get_mbssid_support(const char *ifname, int *buf)
301 {
302         /* No multi bssid support atm */
303         return -1;
304 }
305