mwifiex: disable TDLS link upon tear down event
authorAvinash Patil <patila@marvell.com>
Wed, 7 May 2014 05:02:44 +0000 (22:02 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 7 May 2014 20:08:08 +0000 (16:08 -0400)
This patch adds code to disable TDLS link upon reception of TDLS
teardown event from peer. Teardown event can happen either
because of TDLS teardown packet from peer or internal timeout
configured during TDLS setup. Event is propogated to cfg80211
so that userspace application can take appropriate action.

Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/sta_event.c

index 28994ab46e15cee9f9875ae7f700fcfa93390294..f0730bdba190189784a5ab0dd31f4241de5c8841 100644 (file)
@@ -488,6 +488,7 @@ enum P2P_MODES {
 #define EVENT_UAP_MIC_COUNTERMEASURES   0x0000004c
 #define EVENT_HOSTWAKE_STAIE           0x0000004d
 #define EVENT_CHANNEL_SWITCH_ANN        0x00000050
+#define EVENT_TDLS_GENERIC_EVENT        0x00000052
 #define EVENT_EXT_SCAN_REPORT           0x00000058
 #define EVENT_REMAIN_ON_CHAN_EXPIRED    0x0000005f
 
@@ -520,6 +521,7 @@ enum P2P_MODES {
 #define ACT_TDLS_DELETE            0x00
 #define ACT_TDLS_CREATE            0x01
 #define ACT_TDLS_CONFIG            0x02
+#define TDLS_EVENT_LINK_TEAR_DOWN  3
 
 #define MWIFIEX_FW_V15            15
 
@@ -1753,6 +1755,15 @@ struct host_cmd_ds_802_11_subsc_evt {
        __le16 events;
 } __packed;
 
+struct mwifiex_tdls_generic_event {
+       __le16 type;
+       u8 peer_mac[ETH_ALEN];
+       union {
+               __le16 reason_code;
+               __le16 reserved;
+       } u;
+} __packed;
+
 struct mwifiex_ie {
        __le16 ie_index;
        __le16 mgmt_subtype_mask;
index 368450cc56c7d9e19b8c2a74c47d43a9c5c91b1f..5aea719219a3194cd8c39d3f46879437b7ab0af0 100644 (file)
@@ -134,6 +134,42 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
                netif_carrier_off(priv->netdev);
 }
 
+static int mwifiex_parse_tdls_event(struct mwifiex_private *priv,
+                                   struct sk_buff *event_skb)
+{
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct mwifiex_sta_node *sta_ptr;
+       struct mwifiex_tdls_generic_event *tdls_evt =
+                       (void *)event_skb->data + sizeof(adapter->event_cause);
+
+       /* reserved 2 bytes are not mandatory in tdls event */
+       if (event_skb->len < (sizeof(struct mwifiex_tdls_generic_event) -
+                             sizeof(u16) - sizeof(adapter->event_cause))) {
+               dev_err(adapter->dev, "Invalid event length!\n");
+               return -1;
+       }
+
+       sta_ptr = mwifiex_get_sta_entry(priv, tdls_evt->peer_mac);
+       if (!sta_ptr) {
+               dev_err(adapter->dev, "cannot get sta entry!\n");
+               return -1;
+       }
+
+       switch (le16_to_cpu(tdls_evt->type)) {
+       case TDLS_EVENT_LINK_TEAR_DOWN:
+               cfg80211_tdls_oper_request(priv->netdev,
+                                          tdls_evt->peer_mac,
+                                          NL80211_TDLS_TEARDOWN,
+                                          le16_to_cpu(tdls_evt->u.reason_code),
+                                          GFP_KERNEL);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 /*
  * This function handles events generated by firmware.
  *
@@ -459,6 +495,10 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                        false);
                break;
 
+       case EVENT_TDLS_GENERIC_EVENT:
+               ret = mwifiex_parse_tdls_event(priv, adapter->event_skb);
+               break;
+
        default:
                dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
                        eventcause);