status = "connected";
                        break;
                }
-               seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
+               seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
+                          (p->data_port_open ? " data_port_open" : ""));
 
                if (p->status == wil_sta_connected) {
                        for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
 
        uint i;
        struct wil_sta_info *sta = &wil->sta[cid];
 
+       sta->data_port_open = false;
        if (sta->status != wil_sta_unused) {
                wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
                sta->status = wil_sta_unused;
 
        if (cid < 0)
                return NULL;
 
+       if (!wil->sta[cid].data_port_open &&
+           (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+               return NULL;
+
        /* TODO: fix for multiple TID */
        for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
                if (wil->vring2cid_tid[i][0] == cid) {
        struct vring *v, *v2;
        struct sk_buff *skb2;
        int i;
+       u8 cid;
 
-       /* find 1-st vring */
+       /* find 1-st vring eligible for data */
        for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
                v = &wil->vring_tx[i];
-               if (v->va)
-                       goto found;
+               if (!v->va)
+                       continue;
+
+               cid = wil->vring2cid_tid[i][0];
+               if (!wil->sta[cid].data_port_open)
+                       continue;
+
+               goto found;
        }
 
        wil_err(wil, "Tx while no vrings active?\n");
                v2 = &wil->vring_tx[i];
                if (!v2->va)
                        continue;
+               cid = wil->vring2cid_tid[i][0];
+               if (!wil->sta[cid].data_port_open)
+                       continue;
+
                skb2 = skb_copy(skb, GFP_ATOMIC);
                if (skb2) {
                        wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
 
        u8 addr[ETH_ALEN];
        enum wil_sta_status status;
        struct wil_net_stats stats;
+       bool data_port_open; /* can send any data, not only EAPOL */
        /* Rx BACK */
        struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
        unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
 
 {
        struct net_device *ndev = wil_to_ndev(wil);
        struct wmi_data_port_open_event *evt = d;
+       u8 cid = evt->cid;
 
-       wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid);
+       wil_dbg_wmi(wil, "Link UP for CID %d\n", cid);
 
+       if (cid >= ARRAY_SIZE(wil->sta)) {
+               wil_err(wil, "Link UP for invalid CID %d\n", cid);
+               return;
+       }
+
+       wil->sta[cid].data_port_open = true;
        netif_carrier_on(ndev);
 }
 
 {
        struct net_device *ndev = wil_to_ndev(wil);
        struct wmi_wbe_link_down_event *evt = d;
+       u8 cid = evt->cid;
 
        wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
-                   evt->cid, le32_to_cpu(evt->reason));
+                   cid, le32_to_cpu(evt->reason));
+
+       if (cid >= ARRAY_SIZE(wil->sta)) {
+               wil_err(wil, "Link DOWN for invalid CID %d\n", cid);
+               return;
+       }
 
+       wil->sta[cid].data_port_open = false;
        netif_carrier_off(ndev);
 }