/*
 * Reaver - Transmit functions
 * Copyright (c) 2011, Tactical Network Solutions, Craig Heffner <cheffner@tacnetsol.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU General Public License in all respects
 *  for all of the code used other than OpenSSL. *  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so. *  If you
 *  do not wish to do so, delete this exception statement from your
 *  version. *  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 */

#include "send.h"

/* Initiate the WPS session with an EAPOL START packet */
int send_eapol_start()
{
	const void *packet = NULL;
	size_t packet_len = 0;
	int ret_val = 0;

	packet = build_eapol_start_packet(&packet_len);

	if(packet)
	{
		cprintf(VERBOSE, "[+] Sending EAPOL START request\n");
		ret_val = send_packet(packet, packet_len, 1);
		free((void *) packet);
	}

	/* 
	 * This is used to track how many times an EAPOL START request is sent
	 * in a row.
	 *  
	 * It is cleared by the process_packets() function when an EAP identity
	 * resquest is received.
	 * 
	 * If it reaches EAPOL_START_MAX_TRIES, do_wps_exchange() will notify
	 * the user.
	 */
	set_eapol_start_count(get_eapol_start_count() + 1);

	return ret_val;
}

/* Send an identity response packet */
int send_identity_response()
{
	const void *packet = NULL, *identity = NULL;
	size_t packet_len = 0;
	int ret_val = 0;

	identity = WFA_REGISTRAR;

	packet = build_eap_packet(identity, strlen(identity), &packet_len);

	if(packet)
	{
		cprintf(VERBOSE, "[+] Sending identity response\n");
		ret_val = send_packet(packet, packet_len, 1);
		free((void *) packet);
	}

	return ret_val;
}

/* Send the appropriate WPS message based on the current WPS state (globule->wps->state) */
int send_msg(int type)
{
	int ret_val = 0;
	const struct wpabuf *msg = NULL;
	unsigned char *payload = NULL;
        const void *packet = NULL;
        size_t packet_len = 0;
        uint16_t payload_len = 0;
	enum wsc_op_code opcode = 0;
	struct wps_data *wps = get_wps();

	/* 
	 * Get the next message we need to send based on the data retrieved 
	 * from wps_registrar_process_msg (see exchange.c).
	 */
        msg = wps_registrar_get_msg(wps, &opcode, type);
	set_opcode(opcode);
        if(msg)
        {
		/* Get a pointer to the actual data inside of the wpabuf */
                payload = (unsigned char *) wpabuf_head(msg);
                payload_len = (uint16_t) msg->used;

		/* Build and send an EAP packet with the message payload */
                packet = build_eap_packet(payload, payload_len, &packet_len);
		if(packet)
		{
			if(send_packet(packet, packet_len, 1))
			{
				ret_val = 1;
			} else {
				free((void *) packet);
			}
		}

		wpabuf_free((struct wpabuf *) msg);
        }

	return ret_val;
}

/* 
 * Send a WSC_NACK message followed by an EAP failure packet.
 * This is only called when completely terminating a cracking session.
 */
void send_termination()
{
	const void *data = NULL;
	size_t data_size = 0;

	data = build_eap_failure_packet(&data_size);
	if(data)
	{
		send_packet(data, data_size, 1);
		free((void*) data);
	}
}

/* Send a WSC_NACK message */
void send_wsc_nack()
{
	struct wps_data *wps = get_wps();

	wps->state = SEND_WSC_NACK;
	send_msg(SEND_WSC_NACK);
}

/* store last packet */
static size_t last_len;
static unsigned char last_packet[4096];

int resend_last_packet(void) {
	return send_packet(last_packet, last_len, 0);
}

/* 
 * All transmissions are handled here to ensure that the receive timer 
 * is always started immediately after a packet is transmitted.
 */
static int send_packet_real(const void *packet, size_t len, int use_timer) {
	int ret_val = 0;

	if(pcap_inject(get_handle(), packet, len) == len)
	{
		ret_val = 1;
	}

	if (use_timer) {
		if(len < sizeof last_packet) {
			memcpy(last_packet, packet, len);
			last_len = len;
		}
		start_timer();
	}

	return ret_val;

}

int send_packet_internal(const char* callerfunc, const char* file, int callerline,
		const void *packet, size_t len, int use_timer)
{
	cprintf(DEBUG, "send_packet called from %s() %s:%d\n", callerfunc, file, callerline);
	int i, ret;
	#define CNT 1
	for(i=0;i<CNT;i++) {
		ret = send_packet_real(packet, len, i==CNT-1 ? use_timer : 0);
	}
	return ret;
}
