static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, bool unaligned) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = unaligned ? NET_IP_ALIGN : 0; /* * In PLT mode we seem to get frames and mac80211 warns about them, * workaround this by not retrieving them at all. */ if (unlikely(wl->state == WL1271_STATE_PLT)) return -EINVAL; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { /* discard corrupted packets */ case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: case WL1271_RX_DESC_DECRYPT_FAIL: wl1271_warning("corrupted packet in RX with status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; case WL1271_RX_DESC_SUCCESS: case WL1271_RX_DESC_MIC_FAIL: break; default: wl1271_error("invalid RX descriptor status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; } /* skb length not included rx descriptor */ skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); buf = skb_put(skb, length - sizeof(*desc)); /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len - desc->pad_len, beacon ? "beacon" : ""); skb_trim(skb, skb->len - desc->pad_len); skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); #ifdef CONFIG_HAS_WAKELOCK /* let the frame some time to propagate to user-space */ wake_lock_timeout(&wl->rx_wake, HZ); #endif return is_data; }
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, bool unaligned, u8 *hlid) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = unaligned ? NET_IP_ALIGN : 0; u16 seq_num; /* */ if (unlikely(wl->plt)) return -EINVAL; /* */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { /* */ case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: case WL1271_RX_DESC_DECRYPT_FAIL: wl1271_warning("corrupted packet in RX with status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; case WL1271_RX_DESC_SUCCESS: case WL1271_RX_DESC_MIC_FAIL: break; default: wl1271_error("invalid RX descriptor status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; } /* */ skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* */ skb_reserve(skb, reserved); buf = skb_put(skb, length - sizeof(*desc)); /* */ memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); *hlid = desc->hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, skb->len - desc->pad_len, beacon ? "beacon" : "", seq_num, *hlid); skb_trim(skb, skb->len - desc->pad_len); skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); return is_data; }
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, enum wl_rx_buf_align rx_align, u8 *hlid) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = 0, offset_to_data = 0; u16 seq_num; u32 pkt_data_len; /* * In PLT mode we seem to get frames and mac80211 warns about them, * workaround this by not retrieving them at all. */ if (unlikely(wl->plt)) return -EINVAL; pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length); if (!pkt_data_len) { wl1271_error("Invalid packet arrived from HW. length %d", length); return -EINVAL; } if (rx_align == WLCORE_RX_BUF_UNALIGNED) reserved = RX_BUF_ALIGN; else if (rx_align == WLCORE_RX_BUF_PADDED) offset_to_data = RX_BUF_ALIGN; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } /* discard corrupted packets */ if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) { hdr = (void *)(data + sizeof(*desc) + offset_to_data); wl1271_warning("corrupted packet in RX: status: 0x%x len: %d", desc->status & WL1271_RX_DESC_STATUS_MASK, pkt_data_len); wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc), min(pkt_data_len, ieee80211_hdrlen(hdr->frame_control))); return -EINVAL; } /* skb length not including rx descriptor */ skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); buf = skb_put(skb, pkt_data_len); /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ memcpy(buf, data + sizeof(*desc), pkt_data_len); if (rx_align == WLCORE_RX_BUF_PADDED) skb_pull(skb, RX_BUF_ALIGN); *hlid = desc->hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); wlcore_hw_set_rx_csum(wl, desc, skb); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, skb->len - desc->pad_len, beacon ? "beacon" : "", seq_num, *hlid); skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); #ifdef CONFIG_HAS_WAKELOCK /* let the frame some time to propagate to user-space */ wake_lock_timeout(&wl->rx_wake, HZ); #endif return is_data; }