static int ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb, u8 pipe_id) { int status = 0; struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_hdr *hdr; struct ath10k_htc_ep *ep; u16 payload_len; u32 trailer_len = 0; size_t min_len; u8 eid; bool trailer_present; hdr = (struct ath10k_htc_hdr *)skb->data; skb_pull(skb, sizeof(*hdr)); eid = hdr->eid; if (eid >= ATH10K_HTC_EP_COUNT) { ath10k_warn("HTC Rx: invalid eid %d\n", eid); ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "", hdr, sizeof(*hdr)); status = -EINVAL; goto out; } ep = &htc->endpoint[eid]; /* * If this endpoint that received a message from the target has * a to-target HIF pipe whose send completions are polled rather * than interrupt-driven, this is a good point to ask HIF to check * whether it has any completed sends to handle. */ if (ep->ul_is_polled) ath10k_htc_send_complete_check(ep, 1); payload_len = __le16_to_cpu(hdr->len); if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) { ath10k_warn("HTC rx frame too long, len: %zu\n", payload_len + sizeof(*hdr)); ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "", hdr, sizeof(*hdr)); status = -EINVAL; goto out; } if (skb->len < payload_len) { ath10k_dbg(ATH10K_DBG_HTC, "HTC Rx: insufficient length, got %d, expected %d\n", skb->len, payload_len); ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "", hdr, sizeof(*hdr)); status = -EINVAL; goto out; } /* get flags to check for trailer */ trailer_present = hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT; if (trailer_present) { u8 *trailer; trailer_len = hdr->trailer_len; min_len = sizeof(struct ath10k_ath10k_htc_record_hdr); if ((trailer_len < min_len) || (trailer_len > payload_len)) { ath10k_warn("Invalid trailer length: %d\n", trailer_len); status = -EPROTO; goto out; } trailer = (u8 *)hdr; trailer += sizeof(*hdr); trailer += payload_len; trailer -= trailer_len; status = ath10k_htc_process_trailer(htc, trailer, trailer_len, hdr->eid); if (status) goto out; skb_trim(skb, skb->len - trailer_len); } if (((int)payload_len - (int)trailer_len) <= 0) /* zero length packet with trailer data, just drop these */ goto out; if (eid == ATH10K_HTC_EP_0) { struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data; switch (__le16_to_cpu(msg->hdr.message_id)) { default: /* handle HTC control message */ if (completion_done(&htc->ctl_resp)) { /* * this is a fatal error, target should not be * sending unsolicited messages on the ep 0 */ ath10k_warn("HTC rx ctrl still processing\n"); status = -EINVAL; complete(&htc->ctl_resp); goto out; } htc->control_resp_len = min_t(int, skb->len, ATH10K_HTC_MAX_CTRL_MSG_LEN); memcpy(htc->control_resp_buffer, skb->data, htc->control_resp_len); complete(&htc->ctl_resp); break; case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE: htc->htc_ops.target_send_suspend_complete(ar); } goto out; } ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n", eid, skb); ep->ep_ops.ep_rx_complete(ar, skb); /* skb is now owned by the rx completion handler */ skb = NULL; out: kfree_skb(skb); return status; }
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) { int status = 0; struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_hdr *hdr; struct ath10k_htc_ep *ep; u16 payload_len; u32 trailer_len = 0; size_t min_len; u8 eid; bool trailer_present; hdr = (struct ath10k_htc_hdr *)skb->data; skb_pull(skb, sizeof(*hdr)); eid = hdr->eid; if (eid >= ATH10K_HTC_EP_COUNT) { ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid); ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "", hdr, sizeof(*hdr)); goto out; } ep = &htc->endpoint[eid]; payload_len = __le16_to_cpu(hdr->len); if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) { ath10k_warn(ar, "HTC rx frame too long, len: %zu\n", payload_len + sizeof(*hdr)); ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", hdr, sizeof(*hdr)); goto out; } if (skb->len < payload_len) { ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC Rx: insufficient length, got %d, expected %d\n", skb->len, payload_len); ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", hdr, sizeof(*hdr)); goto out; } /* get flags to check for trailer */ trailer_present = hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT; if (trailer_present) { u8 *trailer; trailer_len = hdr->trailer_len; min_len = sizeof(struct ath10k_ath10k_htc_record_hdr); if ((trailer_len < min_len) || (trailer_len > payload_len)) { ath10k_warn(ar, "Invalid trailer length: %d\n", trailer_len); goto out; } trailer = (u8 *)hdr; trailer += sizeof(*hdr); trailer += payload_len; trailer -= trailer_len; status = ath10k_htc_process_trailer(htc, trailer, trailer_len, hdr->eid); if (status) goto out; skb_trim(skb, skb->len - trailer_len); } if (((int)payload_len - (int)trailer_len) <= 0) /* zero length packet with trailer data, just drop these */ goto out; if (eid == ATH10K_HTC_EP_0) { struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data; switch (__le16_to_cpu(msg->hdr.message_id)) { case ATH10K_HTC_MSG_READY_ID: case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID: /* handle HTC control message */ if (completion_done(&htc->ctl_resp)) { /* * this is a fatal error, target should not be * sending unsolicited messages on the ep 0 */ ath10k_warn(ar, "HTC rx ctrl still processing\n"); complete(&htc->ctl_resp); goto out; } htc->control_resp_len = min_t(int, skb->len, ATH10K_HTC_MAX_CTRL_MSG_LEN); memcpy(htc->control_resp_buffer, skb->data, htc->control_resp_len); complete(&htc->ctl_resp); break; case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE: htc->htc_ops.target_send_suspend_complete(ar); break; default: ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n"); break; } goto out; } ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %pK\n", eid, skb); ep->ep_ops.ep_rx_complete(ar, skb); /* skb is now owned by the rx completion handler */ skb = NULL; out: kfree_skb(skb); }
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) { int status = 0; struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_hdr *hdr; struct ath10k_htc_ep *ep; u16 payload_len; u32 trailer_len = 0; size_t min_len; u8 eid; bool trailer_present; hdr = (struct ath10k_htc_hdr *)skb->data; skb_pull(skb, sizeof(*hdr)); eid = hdr->eid; if (eid >= ATH10K_HTC_EP_COUNT) { ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid); ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "", hdr, sizeof(*hdr)); goto out; } ep = &htc->endpoint[eid]; payload_len = __le16_to_cpu(hdr->len); if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) { ath10k_warn(ar, "HTC rx frame too long, len: %zu\n", payload_len + sizeof(*hdr)); ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", hdr, sizeof(*hdr)); goto out; } if (skb->len < payload_len) { ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC Rx: insufficient length, got %d, expected %d\n", skb->len, payload_len); ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "", hdr, sizeof(*hdr)); goto out; } /* get flags to check for trailer */ trailer_present = hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT; if (trailer_present) { u8 *trailer; trailer_len = hdr->trailer_len; min_len = sizeof(struct ath10k_ath10k_htc_record_hdr); if ((trailer_len < min_len) || (trailer_len > payload_len)) { ath10k_warn(ar, "Invalid trailer length: %d\n", trailer_len); goto out; } trailer = (u8 *)hdr; trailer += sizeof(*hdr); trailer += payload_len; trailer -= trailer_len; status = ath10k_htc_process_trailer(htc, trailer, trailer_len, hdr->eid, NULL, NULL); if (status) goto out; skb_trim(skb, skb->len - trailer_len); } if (((int)payload_len - (int)trailer_len) <= 0) /* zero length packet with trailer data, just drop these */ goto out; ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %pK\n", eid, skb); ep->ep_ops.ep_rx_complete(ar, skb); /* skb is now owned by the rx completion handler */ skb = NULL; out: kfree_skb(skb); }