1 /*
2  * wmtop.c -- WindowMaker process view dock app
3  * Derived by Carsten Schuermann   carsten@schuermann.org
4  * http://www.schuermann.org/~carsten
5  * from
6  * Dan Piponi dan@tanelorn.demon.co.uk
7  * http://www.tanelorn.demon.co.uk
8  * who derived it
9  * from code originally contained in wmsysmon by Dave Clark (clarkd@skynet.ca)
10  * This software is licensed through the GNU General Public License.
11  * $Log: wmwave.c,v $
12  * Revision 1.7  1999/08/20 13:44:21  carsten
13  * version 0.4 complete
14  *
15  * Revision 1.6  1999/08/19 17:58:52  carsten
16  * Almost final version
17  *
18  * Revision 1.5  1999/08/19 13:54:30  carsten
19  * done
20  *
21  * Revision 1.4  1999/08/19 11:14:50  carsten
22  * hookup to /proc/net/wirless complete
23  *
24  * Revision 1.3  1999/08/19 02:39:07  carsten
25  * improved design and hooked it up
26  *
27  * Revision 1.2  1999/08/16 03:45:34  carsten
28  * Added dots
29  *
30  * Revision 1.1  1999/08/15 15:39:18  carsten
31  * Added wmwave project to repository
32  *
33  * Authors (in reverse chronological order):
34  * Benjamin Close <benjsc@freebsd.org>
35  * Hendrik Scholz <hscholz@raisdorf.net>
36  * Bruce M. Simpson <bms@spc.org>
37  * Carsten Schuermann <carsten@schuermann.org>
38  * Dan Piponi <dan@tanelorn.demon.co.uk>
39  * Dave Clark <clarkd@skynet.ca>
40  *
41  * The FreeBSD version of this software is released under the GNU GPL, and
42  * forms part of the Consume Project <URL: http://www.consume.net/>.
43  *
44  *
45  */
46 
47 
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <time.h>
51 #include <dirent.h>
52 #include <string.h>
53 #include <fcntl.h>
54 #include <unistd.h>
55 #include <ctype.h>
56 #include <math.h>
57 #include <limits.h>
58 #include <errno.h>
59 #include <signal.h>
60 
61 #include <sys/wait.h>
62 #include <sys/stat.h>
63 #include <sys/param.h>
64 #include <sys/types.h>
65 #include <sys/ioctl.h>
66 #include <sys/time.h>
67 
68 #include <X11/Xlib.h>
69 #include <X11/xpm.h>
70 #include <X11/extensions/shape.h>
71 
72 #include <sys/socket.h>
73 #include <sys/sockio.h>
74 #include <netdb.h>
75 #include <net/if.h>
76 #include <net/if_var.h>
77 #include <net/route.h>
78 #include <net/ethernet.h>
79 #include <netinet/in.h>
80 #include <netinet/in_systm.h>
81 #include <netinet/in_var.h>
82 #include <netinet/ip.h>
83 #include <netinet/ip_var.h>
84 #include <arpa/inet.h>
85 #include <netproto/802_11/_ieee80211.h>
86 #include <netproto/802_11/ieee80211.h>
87 #include <netproto/802_11/ieee80211_crypto.h>
88 #include <netproto/802_11/ieee80211_ioctl.h>
89 
90 #include "wmgeneral.h"
91 
92 #include "wmwave-master.xpm"
93 
94 char wmwave_mask_bits[64*64];
95 int wmwave_mask_width = 64;
96 int wmwave_mask_height = 64;
97 
98 #define WMWAVE_VERSION			"0.4_FreeBSD-2"
99 #define WMWAVE_DEFAULT_INTERFACE	"wi0"
100 char			*iface = WMWAVE_DEFAULT_INTERFACE;
101 
102 int update_rate=100000;
103 
104 char *ProgName;
105 
106 time_t curtime;
107 time_t prevtime;
108 
109 int mode = 0;    // default: no card detected
110 int screen = 0;  // default: Quality screen is displayed
111 
112 void usage(void);
113 void printversion(void);
114 void BlitString(char *name, int x, int y);
115 void BlitNum(int num, int x, int y);
116 void wmwave_routine(int, char **);
117 void DrawBar(float percent, int dx, int dy);
118 void DrawGreenBar(float percent, int dx, int dy);
119 
DrawBar(float percent,int dx,int dy)120 inline void DrawBar(float percent, int dx, int dy) {
121   int tx;
122 
123   tx = (float)((float)54 * ((float)percent / (float)100.0));
124   copyXPMArea(67, 36, tx, 4, dx, dy);
125   copyXPMArea(67, 43, 54-tx, 4, dx+tx, dy);
126 }
127 
128 
DrawGreenBar(float percent,int dx,int dy)129 inline void DrawGreenBar(float percent, int dx, int dy) {
130   int tx;
131 
132   tx = (float)((float)54 * ((float)percent / (float)100.0));
133   copyXPMArea(67, 58, tx, 4, dx, dy);
134   copyXPMArea(67, 43, 54-tx, 4, dx+tx, dy);
135 }
136 
DrawRedDot()137 inline void DrawRedDot() {
138   copyXPMArea(80, 65, 6, 6, 52, 5);
139 }
140 
DrawYellowDot()141 inline void DrawYellowDot() {
142   copyXPMArea(86, 65, 6, 6, 52, 5);
143 }
144 
DrawGreenDot()145 inline void DrawGreenDot() {
146   copyXPMArea(92, 65, 6, 6, 52, 5);
147 }
148 
DrawEmptyDot()149 inline void DrawEmptyDot() {
150   copyXPMArea(98, 65, 6, 6, 52, 5);
151 }
152 
min(float x,float y)153 float min (float x, float y) {
154   if (x < y) {return x;}
155   else {return y;}
156 }
157 
158 /*
159  * XXX: Fetch OS-specific wireless statistics.
160  *
161  * These are: quality, signal, noise. On NetBSD, the
162  * statistics kept on an AP-basis for the driver are valid.
163  * On FreeBSD, we make use of the net80211 layer to display the
164  * required stats.
165  */
DisplayWireless(void)166 void DisplayWireless(void)
167 {
168     struct ifreq             ifr;
169     struct ieee80211req      ireq;
170     union {
171 	struct ieee80211req_sta_req stareq;
172 	uint8_t buf[24*1024];
173     } u;
174     int                      s, mode, err;
175     float	                 link, level, noise;
176     enum {
177 	MODE_NO_CARD = 0,
178 	MODE_HAVE_CARD = 1
179     };
180 
181     s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
182     if (s == -1)
183 	errx(errno, "socket");
184     bzero(&ifr, sizeof(ifr));
185     strncpy(ifr.ifr_name, iface, strlen(iface));
186 
187     memset(&ireq, 0, sizeof(ireq));
188     strncpy(ireq.i_name, iface, sizeof(ireq.i_name));
189 
190     // Get the currently associated ap
191     ireq.i_type = IEEE80211_IOC_BSSID;
192     ireq.i_data = u.stareq.is_u.macaddr;
193     ireq.i_len = IEEE80211_ADDR_LEN;
194     err = ioctl(s, SIOCG80211, &ireq);
195     if ( err >= 0 ){
196 
197 	// Get the station info for the ap
198 	memset(&ireq, 0, sizeof(ireq));
199 	strncpy(ireq.i_name, iface, sizeof(ireq.i_name));
200 	ireq.i_type = IEEE80211_IOC_STA_INFO;
201 	ireq.i_data = &u;
202 	ireq.i_len  = sizeof(u);
203 	err = ioctl(s, SIOCG80211, &ireq);
204 	if ( err >= 0 ){
205 	    const struct ieee80211req_sta_info *si = u.stareq.info;
206 	    mode = MODE_HAVE_CARD;
207 	    // net80211 doesn't have a link quality field so we base it on the
208 	    // noise/signal level
209 	    link = (si->isi_rssi-si->isi_noise)/2;
210 	    level = si->isi_rssi/2;
211 	    noise = abs(si->isi_noise);
212 	}
213     }
214 
215     if (err < 0) {
216 	mode = MODE_NO_CARD;
217     }
218 
219 draw:
220     /*
221      * Print channel information, and signal ratio
222      */
223     switch (mode) {
224 	case MODE_HAVE_CARD:
225 	    BlitString("Quality", 4, 4);
226 	    if (link <= 10) {
227 		DrawRedDot();
228 	    } else if (link <= 20) {
229 		DrawYellowDot();
230 	    } else {
231 		DrawGreenDot();
232 	    };
233 	    BlitString("Quality  ", 4, 18);
234 	    DrawBar(min((int)(link * 1.8), 100.0), 4, 27);
235 	    BlitString("Signal   ", 4, 32);
236 	    DrawGreenBar(min((int)(level * 0.3), 100.0), 4, 41);
237 	    BlitString("Noise    ", 4, 46);
238 	    DrawGreenBar(min((int)(noise * 0.3), 100.0), 4, 55);
239 	    break;
240 	case MODE_NO_CARD:
241 	default:
242 	    BlitString("NO CARD", 4, 4);
243 	    DrawEmptyDot();
244 	    BlitString("         ", 4, 18);
245 	    DrawBar(0.0, 4, 27);
246 	    BlitString("         ", 4, 32);
247 	    DrawGreenBar(0.0, 4, 41);
248 	    BlitString("         ", 4, 46);
249 	    DrawGreenBar(0.0, 4, 55);
250 	    break;
251     };
252     close(s);
253 }
254 
255 /* SIGCHLD handler */
sig_chld(int signo)256 void sig_chld(int signo)
257 {
258   waitpid((pid_t) -1, NULL, WNOHANG);
259   signal(SIGCHLD, sig_chld);
260 }
261 
main(int argc,char * argv[])262 int main(int argc, char *argv[]) {
263   int i;
264 
265   /* Parse Command Line */
266 
267   signal(SIGCHLD, sig_chld);
268   ProgName = argv[0];
269   if (strlen(ProgName) >= 5)
270     ProgName += (strlen(ProgName) - 5);
271 
272   for (i=1; i<argc; i++) {
273     char *arg = argv[i];
274 
275     if (*arg=='-') {
276       switch (arg[1]) {
277       case 'i':
278 	  if (argc > (i + 1)) {
279 	      iface = argv[i+1];
280 	  }
281 	  break;
282       case 'd' :
283 	if (strcmp(arg+1, "display")) {
284 	  usage();
285 	  exit(1);
286 	}
287 	break;
288       case 'g' :
289 	if (strcmp(arg+1, "geometry")) {
290 	  usage();
291 	  exit(1);
292 	}
293 	break;
294       case 'v' :
295 	printversion();
296 	exit(0);
297 	break;
298       case 'r':
299 	if (argc > (i+1)) {
300 	  update_rate = (atoi(argv[i+1]) * 1000);
301 	  i++;
302 	}
303 	break;
304       default:
305 	usage();
306 	exit(0);
307 	break;
308       }
309     }
310   }
311 
312   wmwave_routine(argc, argv);
313 
314   return 0;
315 }
316 
317 /*
318  * Main loop
319  */
wmwave_routine(int argc,char ** argv)320 void wmwave_routine(int argc, char **argv) {
321   XEvent Event;
322   struct timeval tv={0,0};
323   struct timeval last={0,0};
324 
325   createXBMfromXPM(wmwave_mask_bits, wmwave_master_xpm, wmwave_mask_width, wmwave_mask_height);
326 
327   openXwindow(argc, argv, wmwave_master_xpm, wmwave_mask_bits, wmwave_mask_width, wmwave_mask_height);
328 
329   RedrawWindow();
330 
331 
332   while (1) {
333 
334     curtime = time(0);
335 
336     if (1) {
337       memcpy(&last, &tv, sizeof(tv));
338 
339       /*
340        * Update display
341        */
342       DisplayWireless();
343 
344       RedrawWindow();
345     }
346 
347     /*
348      * X Events
349      */
350     while (XPending(display)) {
351       XNextEvent(display, &Event);
352       switch (Event.type) {
353       case Expose:
354 	RedrawWindow();
355 	break;
356       case DestroyNotify:
357 	XCloseDisplay(display);
358 	exit(0);
359       case ButtonPress:
360 	switch (screen) {
361 	case 0: screen=1; break;
362 	case 1: screen=0; break;
363 	};
364 	break;
365       }
366     }
367 
368     usleep(update_rate);
369   }
370 }
371 
372 /*
373  * Blits a string at given co-ordinates
374  */
BlitString(char * name,int x,int y)375 void BlitString(char *name, int x, int y) {
376   int	i;
377   int	c;
378   int	k;
379 
380   k = x;
381   for (i=0; name[i]; i++)
382     {
383 
384       c = toupper(name[i]);
385       if (c >= 'A' && c <= 'Z')
386         {   // its a letter
387 		 c -= 'A';
388 	copyXPMArea(c * 6, 74, 6, 8, k, y);
389 	k += 6;
390 	} else
391 	  if (c>='0' && c<='9') {   // its a number or symbol
392 					 c -= '0';
393 	  copyXPMArea(c * 6, 64, 6, 8, k, y);
394 	  k += 6;
395 	  } else {
396 	    copyXPMArea(5, 84, 6, 8, k, y);
397 	    k += 6;
398 
399 	  }
400     }
401 }
402 
BlitNum(int num,int x,int y)403 void BlitNum(int num, int x, int y) {
404   char buf[1024];
405   int newx=x;
406 
407   sprintf(buf, "%03i", num);
408 
409   BlitString(buf, newx, y);
410 }
411 
412 /*
413  * Usage
414  */
usage(void)415 void usage(void) {
416   fprintf(stderr, "\nWmwave - Carsten Schuermann <carsten@schuermann.org>  http://www.schuermann.org/~dockapps\n\n");
417   fprintf(stderr, "usage:\n");
418   fprintf(stderr, "    -display <display name>\n");
419   fprintf(stderr, "    -i        		 interface to use (default to wi0)\n");
420   fprintf(stderr, "    -r                        update rate in milliseconds (default:100)\n");
421   fprintf(stderr, "\n");
422 }
423 
424 /*
425  * printversion
426  */
printversion(void)427 void printversion(void) {
428   fprintf(stderr, "wmwave v%s\n", WMWAVE_VERSION);
429 }
430