1160996Ssam/*- 2160996Ssam * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk> 3160996Ssam * All rights reserved. 4160996Ssam * 5160996Ssam * Redistribution and use in source and binary forms, with or without 6160996Ssam * modification, are permitted provided that the following conditions 7160996Ssam * are met: 8160996Ssam * 1. Redistributions of source code must retain the above copyright 9160996Ssam * notice, this list of conditions and the following disclaimer. 10160996Ssam * 2. Redistributions in binary form must reproduce the above copyright 11160996Ssam * notice, this list of conditions and the following disclaimer in the 12160996Ssam * documentation and/or other materials provided with the distribution. 13160996Ssam * 14160996Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15160996Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16160996Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17160996Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18160996Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19160996Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20160996Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21160996Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22160996Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23160996Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24160996Ssam * SUCH DAMAGE. 25160996Ssam * 26160996Ssam * $FreeBSD$ 27160996Ssam */ 28160996Ssam#include <sys/time.h> 29160996Ssam#include <stdlib.h> 30160996Ssam#include <stdio.h> 31160996Ssam#include <unistd.h> 32160996Ssam#include <string.h> 33160996Ssam#include <errno.h> 34160996Ssam#include <err.h> 35160996Ssam#include <net80211/ieee80211.h> 36160996Ssam#include <sys/endian.h> 37160996Ssam#include "w00t.h" 38160996Ssam 39160996Ssamenum { 40160996Ssam S_START = 0, 41160996Ssam S_SEND_PROBE_REQ, 42160996Ssam S_WAIT_PROBE_RES, 43160996Ssam S_SEND_AUTH, 44160996Ssam S_WAIT_AUTH, 45160996Ssam S_SEND_ASSOC, 46160996Ssam S_WAIT_ASSOC, 47160996Ssam S_ASSOCIATED, 48160996Ssam S_SEND_DATA, 49160996Ssam S_WAIT_ACK 50160996Ssam}; 51160996Ssam 52160996Ssamstruct params { 53160996Ssam int seq; 54160996Ssam int seq_rx; 55160996Ssam char *mac; 56160996Ssam char *ssid; 57160996Ssam char bssid[6]; 58160996Ssam char ap[6]; 59160996Ssam int tx; 60160996Ssam int rx; 61160996Ssam int tap; 62160996Ssam int aid; 63160996Ssam char packet[4096]; 64160996Ssam int packet_len; 65160996Ssam int state; 66160996Ssam char wep_key[13]; 67160996Ssam int wep_iv; 68160996Ssam int wep_len; 69160996Ssam}; 70160996Ssam 71160996Ssamvoid usage(char *pname) 72160996Ssam{ 73160996Ssam printf("Usage: %s <opts>\n" 74160996Ssam "-m\t<source mac>\n" 75160996Ssam "-s\t<ssid>\n" 76160996Ssam "-h\tusage\n" 77160996Ssam "-i\t<iface>\n" 78160996Ssam "-w\t<wep key>\n" 79160996Ssam "-t\t<tap>\n" 80160996Ssam "-b\t<bssid>\n" 81160996Ssam , pname); 82160996Ssam exit(0); 83160996Ssam} 84160996Ssam 85160996Ssamvoid fill_basic(struct ieee80211_frame *wh, struct params *p) 86160996Ssam{ 87160996Ssam short *seq; 88160996Ssam 89160996Ssam wh->i_dur[0] = 0x69; 90160996Ssam wh->i_dur[1] = 0x00; 91160996Ssam 92160996Ssam memcpy(wh->i_addr1, p->ap, 6); 93160996Ssam memcpy(wh->i_addr2, p->mac, 6); 94160996Ssam memcpy(wh->i_addr3, p->bssid, 6); 95160996Ssam 96160996Ssam seq = (short*)wh->i_seq; 97160996Ssam *seq = seqfn(p->seq, 0); 98160996Ssam} 99160996Ssam 100160996Ssamvoid send_frame(struct params *p, void *buf, int len) 101160996Ssam{ 102160996Ssam int rc; 103160996Ssam 104160996Ssam rc = inject(p->tx, buf, len); 105160996Ssam if (rc == -1) { 106160996Ssam if (errno == EMSGSIZE) 107160996Ssam warnx("inject(len %d)", len); 108160996Ssam else 109160996Ssam err(1, "inject(len %d)", len); 110160996Ssam } else if (rc != len) 111160996Ssam errx(1, "injected %d but only %d sent", rc, len); 112160996Ssam p->seq++; 113160996Ssam} 114160996Ssam 115160996Ssamvoid send_probe_request(struct params *p) 116160996Ssam{ 117160996Ssam char buf[2048]; 118160996Ssam struct ieee80211_frame *wh; 119160996Ssam char *data; 120160996Ssam int len; 121160996Ssam 122160996Ssam memset(buf, 0, sizeof(buf)); 123160996Ssam 124160996Ssam wh = (struct ieee80211_frame*) buf; 125160996Ssam fill_basic(wh, p); 126160996Ssam wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; 127160996Ssam 128160996Ssam memset(wh->i_addr1, 0xFF, 6); 129160996Ssam memset(wh->i_addr3, 0xFF, 6); 130160996Ssam 131160996Ssam data = (char*) (wh + 1); 132160996Ssam *data++ = 0; /* SSID */ 133160996Ssam *data++ = strlen(p->ssid); 134160996Ssam strcpy(data, p->ssid); 135160996Ssam data += strlen(p->ssid); 136160996Ssam 137160996Ssam *data++ = 1; /* rates */ 138160996Ssam *data++ = 4; 139160996Ssam *data++ = 2 | 0x80; 140160996Ssam *data++ = 4 | 0x80; 141160996Ssam *data++ = 11; 142160996Ssam *data++ = 22; 143160996Ssam 144160996Ssam len = data - (char*)wh; 145160996Ssam 146160996Ssam send_frame(p, buf, len); 147160996Ssam} 148160996Ssam 149160996Ssamvoid send_auth(struct params *p) 150160996Ssam{ 151160996Ssam char buf[2048]; 152160996Ssam struct ieee80211_frame *wh; 153160996Ssam char *data; 154160996Ssam int len; 155160996Ssam 156160996Ssam memset(buf, 0, sizeof(buf)); 157160996Ssam 158160996Ssam wh = (struct ieee80211_frame*) buf; 159160996Ssam fill_basic(wh, p); 160160996Ssam wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH; 161160996Ssam 162160996Ssam data = (char*) (wh + 1); 163160996Ssam 164160996Ssam /* algo */ 165160996Ssam *data++ = 0; 166160996Ssam *data++ = 0; 167160996Ssam 168160996Ssam /* transaction no. */ 169160996Ssam *data++ = 1; 170160996Ssam *data++ = 0; 171160996Ssam 172160996Ssam /* status code */ 173160996Ssam *data++ = 0; 174160996Ssam *data++ = 0; 175160996Ssam 176160996Ssam len = data - (char*)wh; 177160996Ssam 178160996Ssam send_frame(p, buf, len); 179160996Ssam} 180160996Ssam 181160996Ssam/* 182160996Ssam * Add an ssid element to a frame. 183160996Ssam */ 184160996Ssamstatic u_int8_t * 185160996Ssamieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) 186160996Ssam{ 187160996Ssam *frm++ = IEEE80211_ELEMID_SSID; 188160996Ssam *frm++ = len; 189160996Ssam memcpy(frm, ssid, len); 190160996Ssam return frm + len; 191160996Ssam} 192160996Ssam 193160996Ssamvoid send_assoc(struct params *p) 194160996Ssam{ 195160996Ssam union { 196160996Ssam struct ieee80211_frame w; 197160996Ssam char buf[2048]; 198160996Ssam } u; 199160996Ssam struct ieee80211_frame *wh; 200160996Ssam char *data; 201160996Ssam int len, capinfo, lintval; 202160996Ssam 203160996Ssam memset(&u, 0, sizeof(u)); 204160996Ssam 205160996Ssam wh = (struct ieee80211_frame*) &u.w; 206160996Ssam fill_basic(wh, p); 207160996Ssam wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ; 208160996Ssam 209160996Ssam data = (char*) (wh + 1); 210160996Ssam 211160996Ssam /* capability */ 212160996Ssam capinfo = IEEE80211_CAPINFO_ESS; 213160996Ssam if (p->wep_len) 214160996Ssam capinfo |= IEEE80211_CAPINFO_PRIVACY; 215160996Ssam *(uint16_t *)data = htole16(capinfo); 216160996Ssam data += 2; 217160996Ssam 218160996Ssam /* listen interval */ 219160996Ssam *(uint16_t *)data = htole16(100); 220160996Ssam data += 2; 221160996Ssam 222160996Ssam data = ieee80211_add_ssid(data, p->ssid, strlen(p->ssid)); 223160996Ssam 224160996Ssam *data++ = 1; /* rates */ 225160996Ssam *data++ = 4; 226160996Ssam *data++ = 2 | 0x80; 227160996Ssam *data++ = 4 | 0x80; 228160996Ssam *data++ = 11; 229160996Ssam *data++ = 22; 230160996Ssam 231160996Ssam len = data - (char*)wh; 232160996Ssam 233160996Ssam send_frame(p, u.buf, len); 234160996Ssam} 235160996Ssam 236160996Ssamint for_me(struct ieee80211_frame *wh, char *mac) 237160996Ssam{ 238160996Ssam return memcmp(wh->i_addr1, mac, 6) == 0; 239160996Ssam} 240160996Ssam 241160996Ssamint from_ap(struct ieee80211_frame *wh, char *mac) 242160996Ssam{ 243160996Ssam return memcmp(wh->i_addr2, mac, 6) == 0; 244160996Ssam} 245160996Ssam 246160996Ssamvoid ack(struct params *p, struct ieee80211_frame *wh) 247160996Ssam{ 248160996Ssam if (memcmp(wh->i_addr1, p->mac, 6) != 0) 249160996Ssam return; 250160996Ssam 251160996Ssam if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 252160996Ssam return; 253160996Ssam 254160996Ssam send_ack(p->tx, wh->i_addr2); 255160996Ssam} 256160996Ssam 257160996Ssamvoid generic_process(struct ieee80211_frame *wh, struct params *p, int len) 258160996Ssam{ 259160996Ssam int type, stype; 260160996Ssam int dup = 0; 261160996Ssam 262160996Ssam#if 0 263160996Ssam ack(p, wh); 264160996Ssam#endif 265160996Ssam 266160996Ssam#if 0 267160996Ssam if (!for_me(wh, p->mac)) 268160996Ssam return; 269160996Ssam#endif 270160996Ssam /* ignore my own shit */ 271160996Ssam if (memcmp(wh->i_addr2, p->mac, 6) == 0) { 272160996Ssam return; 273160996Ssam } 274160996Ssam 275160996Ssam type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 276160996Ssam stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 277160996Ssam 278160996Ssam if (for_me(wh, p->mac) && type == IEEE80211_FC0_TYPE_DATA) { 279160996Ssam /* sequence number & dups */ 280160996Ssam if (p->seq_rx == -1) 281160996Ssam p->seq_rx = seqno(wh); 282160996Ssam else { 283160996Ssam int s = seqno(wh); 284160996Ssam 285160996Ssam if (s > p->seq_rx) { 286160996Ssam /* normal case */ 287160996Ssam if (p->seq_rx + 1 == s) { 288160996Ssam#if 0 289160996Ssam printf("S=%d\n", s); 290160996Ssam#endif 291160996Ssam p->seq_rx = s; 292160996Ssam } 293160996Ssam else { /* future */ 294160996Ssam#if 0 295160996Ssam printf("Got seq %d, prev %d\n", 296160996Ssam s, p->seq_rx); 297160996Ssam#endif 298160996Ssam p->seq_rx = s; 299160996Ssam } 300160996Ssam } else { /* we got pas stuff... */ 301160996Ssam if (p->seq_rx - s > 1000) { 302160996Ssam#if 0 303160996Ssam printf("Seqno wrap seq %d, last %d\n", 304160996Ssam s, p->seq_rx); 305160996Ssam#endif 306160996Ssam /* seqno wrapping ? */ 307160996Ssam p->seq_rx = 0; 308160996Ssam } 309160996Ssam else { /* dup */ 310160996Ssam dup = 1; 311160996Ssam#if 0 312160996Ssam printf("Got dup seq %d, last %d\n", 313160996Ssam s, p->seq_rx); 314160996Ssam#endif 315160996Ssam } 316160996Ssam } 317160996Ssam } 318160996Ssam } 319160996Ssam#if 0 320160996Ssam if (wh->i_fc[1] & IEEE80211_FC1_RETRY) { 321160996Ssam printf("Got retry\n"); 322160996Ssam } 323160996Ssam#endif 324160996Ssam#if 0 325160996Ssam if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) { 326160996Ssam int rc = send_ack(p->tx, wh->i_addr2); 327160996Ssam if (rc == -1) 328160996Ssam err(1, "send_ack()"); 329160996Ssam if (rc != 10) { 330160996Ssam printf("Wrote ACK %d/%d\n", rc, 10); 331160996Ssam exit(1); 332160996Ssam } 333160996Ssam } 334160996Ssam#endif 335160996Ssam 336160996Ssam /* data frames */ 337160996Ssam if (type == IEEE80211_FC0_TYPE_DATA && !dup) { 338160996Ssam char *ptr; 339160996Ssam char src[6], dst[6]; 340160996Ssam int rc; 341160996Ssam 342160996Ssam if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) { 343160996Ssam if (memcmp(wh->i_addr2, p->ap, 6) != 0) 344160996Ssam return; 345160996Ssam } else { 346160996Ssam if (memcmp(wh->i_addr1, p->ap, 6) != 0) 347160996Ssam return; 348160996Ssam } 349160996Ssam 350160996Ssam 351160996Ssam if (p->state < S_ASSOCIATED) { 352160996Ssam printf("Got data when not associated!\n"); 353160996Ssam return; 354160996Ssam } 355160996Ssam if (stype != IEEE80211_FC0_SUBTYPE_DATA) { 356160996Ssam printf("Got weird data frame stype=%d\n", 357160996Ssam stype >> IEEE80211_FC0_SUBTYPE_SHIFT); 358160996Ssam return; 359160996Ssam } 360160996Ssam 361160996Ssam if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) { 362160996Ssam memcpy(src, wh->i_addr3, 6); 363160996Ssam memcpy(dst, wh->i_addr1, 6); 364160996Ssam } else { 365160996Ssam memcpy(src, wh->i_addr2, 6); 366160996Ssam memcpy(dst, wh->i_addr3, 6); 367160996Ssam } 368160996Ssam 369160996Ssam ptr = (char*) (wh + 1); 370160996Ssam 371262007Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 372160996Ssam if (!p->wep_len) { 373160996Ssam char srca[3*6]; 374160996Ssam char dsta[3*6]; 375160996Ssam 376160996Ssam mac2str(srca, src); 377160996Ssam mac2str(dsta, dst); 378160996Ssam printf("Got wep but i aint wep %s->%s %d\n", 379160996Ssam srca, dsta, len-sizeof(*wh)-8); 380160996Ssam return; 381160996Ssam } 382160996Ssam 383160996Ssam if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){ 384160996Ssam char srca[3*6]; 385160996Ssam char dsta[3*6]; 386160996Ssam 387160996Ssam mac2str(srca, src); 388160996Ssam mac2str(dsta, dst); 389160996Ssam printf("Can't decrypt %s->%s %d\n", srca, dsta, 390160996Ssam len-sizeof(*wh)-8); 391160996Ssam return; 392160996Ssam } 393160996Ssam 394160996Ssam ptr += 4; 395160996Ssam len -= 8; 396160996Ssam } 397160996Ssam 398160996Ssam /* ether header */ 399160996Ssam ptr += 8 - 2; 400160996Ssam ptr -= 6; 401160996Ssam memcpy(ptr, src, 6); 402160996Ssam ptr -= 6; 403160996Ssam memcpy(ptr, dst, 6); 404160996Ssam 405160996Ssam len -= sizeof(*wh); 406160996Ssam len -= 8; 407160996Ssam len += 14; 408160996Ssam 409160996Ssam /* send to tap */ 410160996Ssam rc = write(p->tap, ptr, len); 411160996Ssam if (rc == -1) 412160996Ssam err(1, "write()"); 413160996Ssam if (rc != len) { 414160996Ssam printf("Wrote %d/%d\n", rc, len); 415160996Ssam exit(1); 416160996Ssam } 417160996Ssam } 418160996Ssam} 419160996Ssam 420160996Ssamint get_probe_response(struct params *p) 421160996Ssam{ 422160996Ssam char buf[4096]; 423160996Ssam int rc; 424160996Ssam struct ieee80211_frame *wh; 425160996Ssam char *data; 426160996Ssam int ess; 427160996Ssam int wep; 428160996Ssam char *ssid; 429160996Ssam char from[18]; 430160996Ssam char bssid[18]; 431160996Ssam 432160996Ssam rc = sniff(p->rx, buf, sizeof(buf)); 433160996Ssam if (rc == -1) 434160996Ssam err(1, "sniff()"); 435160996Ssam 436160996Ssam wh = get_wifi(buf, &rc); 437160996Ssam if (!wh) 438160996Ssam return 0; 439160996Ssam 440160996Ssam generic_process(wh, p, rc); 441160996Ssam 442160996Ssam if (!for_me(wh, p->mac)) 443160996Ssam return 0; 444160996Ssam 445160996Ssam if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT, 446160996Ssam IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 447160996Ssam return 0; 448160996Ssam 449160996Ssam data = (char*) (wh+1); 450160996Ssam data += 8; /* Timestamp */ 451160996Ssam data += 2; /* Beacon Interval */ 452160996Ssam ess = *data & 1; 453160996Ssam wep = (*data & IEEE80211_CAPINFO_PRIVACY) ? 1 : 0; 454160996Ssam data += 2; /* capability */ 455160996Ssam 456160996Ssam /* ssid */ 457160996Ssam if (*data != 0) { 458160996Ssam printf("Warning, expecting SSID got %x\n", *data); 459160996Ssam return 0; 460160996Ssam } 461160996Ssam data++; 462160996Ssam ssid = data+1; 463160996Ssam data += 1 + *data; 464160996Ssam if (*data != 1) { 465160996Ssam printf("Warning, expected rates got %x\n", *data); 466160996Ssam return 0; 467160996Ssam } 468160996Ssam *data = 0; 469160996Ssam 470160996Ssam /* rates */ 471160996Ssam data++; 472160996Ssam 473160996Ssam mac2str(from, wh->i_addr2); 474160996Ssam mac2str(bssid, wh->i_addr3); 475160996Ssam printf("Got response from %s [%s] [%s] ESS=%d WEP=%d\n", 476160996Ssam from, bssid, ssid, ess, wep); 477160996Ssam 478160996Ssam if (strcmp(ssid, p->ssid) != 0) 479160996Ssam return 0; 480160996Ssam 481160996Ssam memcpy(p->ap, wh->i_addr2, 6); 482160996Ssam memcpy(p->bssid, wh->i_addr3, 6); 483160996Ssam return 1; 484160996Ssam} 485160996Ssam 486160996Ssamint get_auth(struct params *p) 487160996Ssam{ 488160996Ssam char buf[4096]; 489160996Ssam int rc; 490160996Ssam struct ieee80211_frame *wh; 491160996Ssam short *data; 492160996Ssam 493160996Ssam rc = sniff(p->rx, buf, sizeof(buf)); 494160996Ssam if (rc == -1) 495160996Ssam err(1, "sniff()"); 496160996Ssam 497160996Ssam wh = get_wifi(buf, &rc); 498160996Ssam if (!wh) 499160996Ssam return 0; 500160996Ssam 501160996Ssam generic_process(wh, p, rc); 502160996Ssam 503160996Ssam if (!for_me(wh, p->mac)) 504160996Ssam return 0; 505160996Ssam 506160996Ssam if (!from_ap(wh, p->ap)) 507160996Ssam return 0; 508160996Ssam 509160996Ssam if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT, 510160996Ssam IEEE80211_FC0_SUBTYPE_AUTH)) 511160996Ssam return 0; 512160996Ssam 513160996Ssam data = (short*) (wh+1); 514160996Ssam 515160996Ssam /* algo */ 516160996Ssam if (le16toh(*data) != 0) { 517160996Ssam printf("Not open-system %d!\n", le16toh(*data)); 518160996Ssam return 0; 519160996Ssam } 520160996Ssam data++; 521160996Ssam 522160996Ssam /* transaction no. */ 523160996Ssam if (le16toh(*data) != 2) { 524160996Ssam printf("Got transaction %d!\n", le16toh(*data)); 525160996Ssam return 0; 526160996Ssam } 527160996Ssam data++; 528160996Ssam 529160996Ssam /* status code */ 530160996Ssam rc = le16toh(*data); 531160996Ssam if (rc == 0) { 532160996Ssam printf("Authenticated\n"); 533160996Ssam return 1; 534160996Ssam } 535160996Ssam 536160996Ssam printf("Authentication failed code=%d\n", rc); 537160996Ssam return 0; 538160996Ssam} 539160996Ssam 540160996Ssamint get_assoc(struct params *p) 541160996Ssam{ 542160996Ssam char buf[4096]; 543160996Ssam int rc; 544160996Ssam struct ieee80211_frame *wh; 545160996Ssam unsigned short *data; 546160996Ssam 547160996Ssam rc = sniff(p->rx, buf, sizeof(buf)); 548160996Ssam if (rc == -1) 549160996Ssam err(1, "sniff()"); 550160996Ssam 551160996Ssam wh = get_wifi(buf, &rc); 552160996Ssam if (!wh) 553160996Ssam return 0; 554160996Ssam 555160996Ssam generic_process(wh, p, rc); 556160996Ssam 557160996Ssam if (!for_me(wh, p->mac)) 558160996Ssam return 0; 559160996Ssam 560160996Ssam if (!from_ap(wh, p->ap)) 561160996Ssam return 0; 562160996Ssam 563160996Ssam if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT, 564160996Ssam IEEE80211_FC0_SUBTYPE_ASSOC_RESP)) 565160996Ssam return 0; 566160996Ssam 567160996Ssam 568160996Ssam data = (unsigned short*) (wh+1); 569160996Ssam 570160996Ssam data++; /* caps */ 571160996Ssam 572160996Ssam /* status */ 573160996Ssam rc = le16toh(*data++); 574160996Ssam if (rc != 0) { 575160996Ssam printf("Assoc failed code %d\n", rc); 576160996Ssam return 0; 577160996Ssam } 578160996Ssam 579160996Ssam /* aid */ 580160996Ssam p->aid = le16toh(*data & ~( (1 << 15) | (1 << 14))); 581160996Ssam printf("Association ID=%d\n", p->aid); 582160996Ssam 583160996Ssam return 1; 584160996Ssam} 585160996Ssam 586160996Ssamvoid read_wifi(struct params *p) 587160996Ssam{ 588160996Ssam char buf[4096]; 589160996Ssam int rc; 590160996Ssam struct ieee80211_frame *wh; 591160996Ssam int type, stype; 592160996Ssam 593160996Ssam rc = sniff(p->rx, buf, sizeof(buf)); 594160996Ssam if (rc == -1) 595160996Ssam err(1, "sniff()"); 596160996Ssam 597160996Ssam wh = get_wifi(buf, &rc); 598160996Ssam if (!wh) 599160996Ssam return; 600160996Ssam 601160996Ssam generic_process(wh, p, rc); 602160996Ssam 603160996Ssam if (!for_me(wh, p->mac)) 604160996Ssam return; 605160996Ssam 606160996Ssam type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 607160996Ssam stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 608160996Ssam 609160996Ssam /* control frames */ 610160996Ssam if (type == IEEE80211_FC0_TYPE_CTL) { 611160996Ssam switch (stype) { 612160996Ssam case IEEE80211_FC0_SUBTYPE_ACK: 613160996Ssam if (p->state == S_WAIT_ACK) 614160996Ssam p->state = S_ASSOCIATED; 615160996Ssam break; 616160996Ssam 617160996Ssam case IEEE80211_FC0_SUBTYPE_RTS: 618160996Ssam#if 0 619160996Ssam printf("Got RTS\n"); 620160996Ssam#endif 621160996Ssam break; 622160996Ssam 623160996Ssam default: 624160996Ssam printf("Unknown CTL frame %d\n", 625160996Ssam stype >> IEEE80211_FC0_SUBTYPE_SHIFT); 626160996Ssam abort(); 627160996Ssam break; 628160996Ssam } 629160996Ssam return; 630160996Ssam } 631160996Ssam 632160996Ssam if (!from_ap(wh, p->ap)) 633160996Ssam return; 634160996Ssam 635160996Ssam if (type != IEEE80211_FC0_TYPE_MGT) 636160996Ssam return; 637160996Ssam 638160996Ssam if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH || 639160996Ssam stype == IEEE80211_FC0_SUBTYPE_DISASSOC) { 640160996Ssam printf("Got management! %d\n", 641160996Ssam stype >> IEEE80211_FC0_SUBTYPE_SHIFT); 642160996Ssam p->seq_rx = -1; 643160996Ssam p->state = S_START; 644160996Ssam } 645160996Ssam 646160996Ssam return; 647160996Ssam} 648160996Ssam 649160996Ssamvoid read_tap(struct params *p) 650160996Ssam{ 651160996Ssam char *ptr; 652160996Ssam int len = sizeof(p->packet); 653160996Ssam int offset; 654160996Ssam char mac[6]; 655160996Ssam struct ieee80211_frame *wh; 656160996Ssam 657160996Ssam ptr = p->packet; 658160996Ssam offset = sizeof(struct ieee80211_frame) + 8 - 14; 659160996Ssam if (p->wep_len) 660160996Ssam offset += 4; 661160996Ssam 662160996Ssam ptr += offset; 663160996Ssam len -= offset; 664160996Ssam 665160996Ssam /* read packet */ 666160996Ssam memset(p->packet, 0, sizeof(p->packet)); 667160996Ssam p->packet_len = read(p->tap, ptr, len); 668160996Ssam if (p->packet_len == -1) 669160996Ssam err(1, "read()"); 670160996Ssam 671160996Ssam /* 802.11 header */ 672160996Ssam wh = (struct ieee80211_frame*) p->packet; 673160996Ssam memcpy(mac, ptr, sizeof(mac)); 674160996Ssam fill_basic(wh, p); 675160996Ssam memcpy(wh->i_addr3, mac, sizeof(wh->i_addr3)); 676160996Ssam wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; 677160996Ssam wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS; 678160996Ssam if (p->wep_len) 679262007Skevlo wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; 680160996Ssam 681160996Ssam /* LLC & SNAP */ 682160996Ssam ptr = (char*) (wh+1); 683160996Ssam if (p->wep_len) 684160996Ssam ptr += 4; 685160996Ssam *ptr++ = 0xAA; 686160996Ssam *ptr++ = 0xAA; 687160996Ssam *ptr++ = 0x03; 688160996Ssam *ptr++ = 0x00; 689160996Ssam *ptr++ = 0x00; 690160996Ssam *ptr++ = 0x00; 691160996Ssam /* ether type overlaps w00t */ 692160996Ssam 693160996Ssam p->packet_len += offset; 694160996Ssam 695160996Ssam /* WEP */ 696160996Ssam if (p->wep_len) { 697160996Ssam ptr = (char*) (wh+1); 698160996Ssam memcpy(ptr, &p->wep_iv, 3); 699160996Ssam ptr[3] = 0; 700160996Ssam p->wep_iv++; 701160996Ssam 702160996Ssam wep_encrypt(wh, p->packet_len, p->wep_key, p->wep_len); 703160996Ssam p->packet_len += 4; /* ICV */ 704160996Ssam } 705160996Ssam} 706160996Ssam 707160996Ssamint main(int argc, char *argv[]) 708160996Ssam{ 709160996Ssam char* ssid = 0; 710160996Ssam char mac[] = { 0x00, 0x00, 0xde, 0xfa, 0xce, 0xd }; 711160996Ssam int ch; 712160996Ssam struct params p; 713195848Ssam char *iface = "wlan0"; 714160996Ssam char *tap = "tap0"; 715160996Ssam int timeout = 50*1000; 716160996Ssam struct timeval start; 717160996Ssam 718160996Ssam memset(&p, 0, sizeof(p)); 719160996Ssam p.wep_len = 0; 720160996Ssam p.wep_iv = 0; 721160996Ssam p.state = S_START; 722160996Ssam 723160996Ssam while ((ch = getopt(argc, argv, "hm:s:i:w:t:b:")) != -1) { 724160996Ssam switch (ch) { 725160996Ssam case 'b': 726160996Ssam if (str2mac(p.bssid, optarg)) { 727160996Ssam printf("Error parsing BSSID\n"); 728160996Ssam exit(1); 729160996Ssam } 730160996Ssam memcpy(p.ap, p.bssid, sizeof(p.ap)); 731160996Ssam p.state = S_SEND_AUTH; 732160996Ssam break; 733160996Ssam 734160996Ssam case 's': 735160996Ssam ssid = optarg; 736160996Ssam break; 737160996Ssam 738160996Ssam case 'm': 739160996Ssam if (str2mac(mac, optarg)) { 740160996Ssam printf("Error parsing MAC\n"); 741160996Ssam exit(1); 742160996Ssam } 743160996Ssam break; 744160996Ssam 745160996Ssam case 'i': 746160996Ssam iface = optarg; 747160996Ssam break; 748160996Ssam 749160996Ssam case 'w': 750160996Ssam if (str2wep(p.wep_key, &p.wep_len, optarg)) { 751160996Ssam printf("Error parsing WEP key\n"); 752160996Ssam exit(1); 753160996Ssam } 754160996Ssam break; 755160996Ssam 756160996Ssam case 't': 757160996Ssam tap = optarg; 758160996Ssam break; 759160996Ssam 760160996Ssam case 'h': 761160996Ssam default: 762160996Ssam usage(argv[0]); 763160996Ssam break; 764160996Ssam } 765160996Ssam } 766160996Ssam 767160996Ssam if (!ssid) 768160996Ssam usage(argv[0]); 769160996Ssam 770160996Ssam p.mac = mac; 771160996Ssam p.ssid = ssid; 772160996Ssam p.seq = getpid(); 773160996Ssam p.seq_rx = -1; 774160996Ssam if (open_rxtx(iface, &p.rx, &p.tx) == -1) 775160996Ssam err(1, "open_rxtx()"); 776160996Ssam p.tap = open_tap(tap); 777160996Ssam if (p.tap == -1) 778160996Ssam err(1, "open_tap()"); 779160996Ssam if (set_iface_mac(tap, mac) == -1) 780160996Ssam err(1, "set_iface_mac()"); 781160996Ssam 782160996Ssam while (1) { 783160996Ssam /* check for timeouts */ 784160996Ssam switch (p.state) { 785160996Ssam case S_WAIT_PROBE_RES: 786160996Ssam case S_WAIT_AUTH: 787160996Ssam case S_WAIT_ASSOC: 788160996Ssam case S_WAIT_ACK: 789160996Ssam do { 790160996Ssam int rc; 791160996Ssam struct timeval tv; 792160996Ssam int elapsed = 0; 793160996Ssam 794160996Ssam /* check timeout */ 795160996Ssam if (gettimeofday(&tv, NULL) == -1) 796160996Ssam err(1, "gettimeofday()"); 797160996Ssam elapsed = tv.tv_sec - start.tv_sec; 798160996Ssam if (elapsed == 0) { 799160996Ssam elapsed = tv.tv_usec - start.tv_usec; 800160996Ssam } else { 801160996Ssam elapsed *= (elapsed-1)*1000*1000; 802160996Ssam elapsed += 1000*1000 - start.tv_usec; 803160996Ssam elapsed += tv.tv_usec; 804160996Ssam } 805160996Ssam if (elapsed >= timeout) 806160996Ssam rc = 0; 807160996Ssam else { 808160996Ssam fd_set fds; 809160996Ssam 810160996Ssam FD_ZERO(&fds); 811160996Ssam FD_SET(p.rx, &fds); 812160996Ssam 813160996Ssam elapsed = timeout - elapsed; 814160996Ssam tv.tv_sec = elapsed/1000/1000; 815160996Ssam elapsed -= tv.tv_sec*1000*1000; 816160996Ssam tv.tv_usec = elapsed; 817160996Ssam 818160996Ssam rc = select(p.rx+1, &fds, NULL, 819160996Ssam NULL, &tv); 820160996Ssam if (rc == -1) 821160996Ssam err(1, "select()"); 822160996Ssam } 823160996Ssam 824160996Ssam /* timeout */ 825160996Ssam if (!rc) { 826160996Ssam#if 0 827160996Ssam printf("Timeout\n"); 828160996Ssam#endif 829160996Ssam p.state--; 830160996Ssam } 831160996Ssam 832160996Ssam } while(0); 833160996Ssam break; 834160996Ssam } 835160996Ssam 836160996Ssam switch (p.state) { 837160996Ssam case S_START: 838160996Ssam p.state = S_SEND_PROBE_REQ; 839160996Ssam break; 840160996Ssam 841160996Ssam case S_SEND_PROBE_REQ: 842160996Ssam printf("Sending probe request for %s\n", ssid); 843160996Ssam send_probe_request(&p); 844160996Ssam p.state = S_WAIT_PROBE_RES; 845160996Ssam if (gettimeofday(&start, NULL) == -1) 846160996Ssam err(1, "gettimeofday()"); 847160996Ssam break; 848160996Ssam 849160996Ssam case S_WAIT_PROBE_RES: 850160996Ssam if (get_probe_response(&p)) { 851160996Ssam p.state = S_SEND_AUTH; 852160996Ssam } 853160996Ssam break; 854160996Ssam 855160996Ssam case S_SEND_AUTH: 856160996Ssam do { 857160996Ssam char apmac[18]; 858160996Ssam 859160996Ssam mac2str(apmac, p.ap); 860160996Ssam printf("Sending auth to %s\n", apmac); 861160996Ssam send_auth(&p); 862160996Ssam p.state = S_WAIT_AUTH; 863160996Ssam if (gettimeofday(&start, NULL) == -1) 864160996Ssam err(1, "gettimeofday()"); 865160996Ssam } while(0); 866160996Ssam break; 867160996Ssam 868160996Ssam case S_WAIT_AUTH: 869160996Ssam if (get_auth(&p)) { 870160996Ssam p.state = S_SEND_ASSOC; 871160996Ssam } 872160996Ssam break; 873160996Ssam 874160996Ssam case S_SEND_ASSOC: 875160996Ssam printf("Sending assoc\n"); 876160996Ssam send_assoc(&p); 877160996Ssam p.state = S_WAIT_ASSOC; 878160996Ssam if (gettimeofday(&start, NULL) == -1) 879160996Ssam err(1, "gettimeofday()"); 880160996Ssam break; 881160996Ssam 882160996Ssam case S_WAIT_ASSOC: 883160996Ssam if (get_assoc(&p)) { 884160996Ssam printf("Associated\n"); 885160996Ssam p.state = S_ASSOCIATED; 886160996Ssam } 887160996Ssam break; 888160996Ssam 889160996Ssam case S_ASSOCIATED: 890160996Ssam do { 891160996Ssam fd_set fds; 892160996Ssam int max; 893160996Ssam 894160996Ssam FD_ZERO(&fds); 895160996Ssam FD_SET(p.rx, &fds); 896160996Ssam FD_SET(p.tap, &fds); 897160996Ssam max = (p.rx > p.tap) ? p.rx : p.tap; 898160996Ssam 899160996Ssam max = select(max+1, &fds, NULL, NULL, NULL); 900160996Ssam if (max == -1) 901160996Ssam err(1, "select()"); 902160996Ssam 903160996Ssam if (FD_ISSET(p.tap, &fds)) { 904160996Ssam read_tap(&p); 905160996Ssam p.state = S_SEND_DATA; 906160996Ssam } 907160996Ssam if (FD_ISSET(p.rx, &fds)) { 908160996Ssam read_wifi(&p); 909160996Ssam } 910160996Ssam } while(0); 911160996Ssam break; 912160996Ssam 913160996Ssam case S_SEND_DATA: 914160996Ssam send_frame(&p, p.packet, p.packet_len); 915160996Ssam do { 916160996Ssam struct ieee80211_frame *wh; 917160996Ssam 918160996Ssam wh = (struct ieee80211_frame*) p.packet; 919160996Ssam wh->i_fc[1] |= IEEE80211_FC1_RETRY; 920160996Ssam } while (0); 921160996Ssam p.state = S_WAIT_ACK; 922160996Ssam if (gettimeofday(&start, NULL) == -1) 923160996Ssam err(1, "gettimeofday()"); 924160996Ssam break; 925160996Ssam 926160996Ssam case S_WAIT_ACK: 927160996Ssam read_wifi(&p); 928160996Ssam break; 929160996Ssam 930160996Ssam default: 931160996Ssam printf("Unknown state %d\n", p.state); 932160996Ssam abort(); 933160996Ssam break; 934160996Ssam } 935160996Ssam } 936160996Ssam 937160996Ssam exit(0); 938160996Ssam} 939