/*
 * Marvell Wireless LAN device driver: AP event handling
 *
 * Copyright (C) 2012-2014, Marvell International Ltd.
 *
 * This software file (the "File") is distributed by Marvell International
 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
 * (the "License").  You may use, redistribute and/or modify this File in
 * accordance with the terms and conditions of the License, a copy of which
 * is available by writing to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
 * this warranty disclaimer.
 */

#include "decl.h"
#include "main.h"
#include "11n.h"




/*
 * This function handles AP interface specific events generated by firmware.
 *
 * Event specific routines are called by this function based
 * upon the generated event cause.
 *
 *
 * Events supported for AP -
 *      - EVENT_UAP_STA_ASSOC
 *      - EVENT_UAP_STA_DEAUTH
 *      - EVENT_UAP_BSS_ACTIVE
 *      - EVENT_UAP_BSS_START
 *      - EVENT_UAP_BSS_IDLE
 *      - EVENT_UAP_MIC_COUNTERMEASURES:
 */
int mwifiex_process_uap_event(struct mwifiex_private *priv)
{
	struct mwifiex_adapter *adapter = priv->adapter;
	int len, i;
	u32 eventcause = adapter->event_cause;
	struct station_info sinfo;
	struct mwifiex_assoc_event *event;
	struct mwifiex_sta_node *node;
	u8 *deauth_mac;
	struct host_cmd_ds_11n_batimeout *ba_timeout;
	u16 ctrl;

	switch (eventcause) {
	case EVENT_UAP_STA_ASSOC:
		memset(&sinfo, 0, sizeof(sinfo));
		event = (struct mwifiex_assoc_event *)
			(adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
		if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
			len = -1;

			if (ieee80211_is_assoc_req(event->frame_control))
				len = 0;
			else if (ieee80211_is_reassoc_req(event->frame_control))
				/* There will be ETH_ALEN bytes of
				 * current_ap_addr before the re-assoc ies.
				 */
				len = ETH_ALEN;

			if (len != -1) {
				sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
				sinfo.assoc_req_ies = &event->data[len];
				len = (u8 *)sinfo.assoc_req_ies -
				      (u8 *)&event->frame_control;
				sinfo.assoc_req_ies_len =
					le16_to_cpu(event->len) - (u16)len;
			}
		}
		cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
				 GFP_KERNEL);

		node = mwifiex_add_sta_entry(priv, event->sta_addr);
		if (!node) {
			dev_warn(adapter->dev,
				 "could not create station entry!\n");
			return -1;
		}

		if (!priv->ap_11n_enabled)
			break;

		mwifiex_set_sta_ht_cap(priv, sinfo.assoc_req_ies,
				       sinfo.assoc_req_ies_len, node);

		for (i = 0; i < MAX_NUM_TID; i++) {
			if (node->is_11n_enabled)
				node->ampdu_sta[i] =
					      priv->aggr_prio_tbl[i].ampdu_user;
			else
				node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
		}
		memset(node->rx_seq, 0xff, sizeof(node->rx_seq));
		break;
	case EVENT_UAP_STA_DEAUTH:
		deauth_mac = adapter->event_body +
			     MWIFIEX_UAP_EVENT_EXTRA_HEADER;
		cfg80211_del_sta(priv->netdev, deauth_mac, GFP_KERNEL);

		if (priv->ap_11n_enabled) {
			mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, deauth_mac);
			mwifiex_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac);
		}
		mwifiex_wmm_del_peer_ra_list(priv, deauth_mac);
		mwifiex_del_sta_entry(priv, deauth_mac);
		break;
	case EVENT_UAP_BSS_IDLE:
		priv->media_connected = false;
		if (netif_carrier_ok(priv->netdev))
			netif_carrier_off(priv->netdev);
		mwifiex_stop_net_dev_queue(priv->netdev, adapter);

		mwifiex_clean_txrx(priv);
		mwifiex_del_all_sta_list(priv);
		break;
	case EVENT_UAP_BSS_ACTIVE:
		priv->media_connected = true;
		if (!netif_carrier_ok(priv->netdev))
			netif_carrier_on(priv->netdev);
		mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
		break;
	case EVENT_UAP_BSS_START:
		dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
		memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
		       ETH_ALEN);
		break;
	case EVENT_UAP_MIC_COUNTERMEASURES:
		/* For future development */
		dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
		break;
	case EVENT_AMSDU_AGGR_CTRL:
		ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
		dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);

		if (priv->media_connected) {
			adapter->tx_buf_size =
				min_t(u16, adapter->curr_tx_buf_size, ctrl);
			dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
				adapter->tx_buf_size);
		}
		break;
	case EVENT_ADDBA:
		dev_dbg(adapter->dev, "event: ADDBA Request\n");
		if (priv->media_connected)
			mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
					 HostCmd_ACT_GEN_SET, 0,
					 adapter->event_body, false);
		break;
	case EVENT_DELBA:
		dev_dbg(adapter->dev, "event: DELBA Request\n");
		if (priv->media_connected)
			mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
		break;
	case EVENT_BA_STREAM_TIEMOUT:
		dev_dbg(adapter->dev, "event:  BA Stream timeout\n");
		if (priv->media_connected) {
			ba_timeout = (void *)adapter->event_body;
			mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
		}
		break;
	case EVENT_EXT_SCAN_REPORT:
		dev_dbg(adapter->dev, "event: EXT_SCAN Report\n");
		if (adapter->ext_scan)
			return mwifiex_handle_event_ext_scan_report(priv,
						adapter->event_skb->data);
		break;
	case EVENT_TX_STATUS_REPORT:
		dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
		mwifiex_parse_tx_status_event(priv, adapter->event_body);
		break;
	default:
		dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
			eventcause);
		break;
	}

	return 0;
}

/* This function deletes station entry from associated station list.
 * Also if both AP and STA are 11n enabled, RxReorder tables and TxBA stream
 * tables created for this station are deleted.
 */
void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
			      struct mwifiex_sta_node *node)
{
	if (priv->ap_11n_enabled && node->is_11n_enabled) {
		mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, node->mac_addr);
		mwifiex_del_tx_ba_stream_tbl_by_ra(priv, node->mac_addr);
	}
	mwifiex_del_sta_entry(priv, node->mac_addr);

	return;
}
