static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb, u32 upld_typ) { u8 *cmd_buf; skb_pull(skb, INTF_HEADER_LEN); switch (upld_typ) { case MWIFIEX_TYPE_DATA: dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); mwifiex_handle_rx_packet(adapter, skb); break; case MWIFIEX_TYPE_CMD: dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n"); if (!adapter->curr_cmd) { cmd_buf = adapter->upld_buf; if (adapter->ps_state == PS_STATE_SLEEP_CFM) mwifiex_process_sleep_confirm_resp(adapter, skb->data, skb->len); memcpy(cmd_buf, skb->data, min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); dev_kfree_skb_any(skb); } else { adapter->cmd_resp_received = true; adapter->curr_cmd->resp_skb = skb; } break; case MWIFIEX_TYPE_EVENT: dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); adapter->event_cause = *(u32 *) skb->data; skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN); if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) memcpy(adapter->event_body, skb->data, skb->len); adapter->event_received = true; adapter->event_skb = skb; break; default: dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ); dev_kfree_skb_any(skb); break; } return 0; }
/* This function handles received packet. Necessary action is taken based on * cmd/event/data. */ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, struct sk_buff *skb, u8 ep) { struct device *dev = adapter->dev; u32 recv_type; __le32 tmp; int ret; if (adapter->hs_activated) mwifiex_process_hs_config(adapter); if (skb->len < INTF_HEADER_LEN) { dev_err(dev, "%s: invalid skb->len\n", __func__); return -1; } switch (ep) { case MWIFIEX_USB_EP_CMD_EVENT: dev_dbg(dev, "%s: EP_CMD_EVENT\n", __func__); skb_copy_from_linear_data(skb, &tmp, INTF_HEADER_LEN); recv_type = le32_to_cpu(tmp); skb_pull(skb, INTF_HEADER_LEN); switch (recv_type) { case MWIFIEX_USB_TYPE_CMD: if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) { dev_err(dev, "CMD: skb->len too large\n"); ret = -1; goto exit_restore_skb; } else if (!adapter->curr_cmd) { dev_dbg(dev, "CMD: no curr_cmd\n"); if (adapter->ps_state == PS_STATE_SLEEP_CFM) { mwifiex_process_sleep_confirm_resp( adapter, skb->data, skb->len); ret = 0; goto exit_restore_skb; } ret = -1; goto exit_restore_skb; } adapter->curr_cmd->resp_skb = skb; adapter->cmd_resp_received = true; break; case MWIFIEX_USB_TYPE_EVENT: if (skb->len < sizeof(u32)) { dev_err(dev, "EVENT: skb->len too small\n"); ret = -1; goto exit_restore_skb; } skb_copy_from_linear_data(skb, &tmp, sizeof(u32)); adapter->event_cause = le32_to_cpu(tmp); dev_dbg(dev, "event_cause %#x\n", adapter->event_cause); if (skb->len > MAX_EVENT_SIZE) { dev_err(dev, "EVENT: event body too large\n"); ret = -1; goto exit_restore_skb; } memcpy(adapter->event_body, skb->data + MWIFIEX_EVENT_HEADER_LEN, skb->len); adapter->event_received = true; adapter->event_skb = skb; break; default: dev_err(dev, "unknown recv_type %#x\n", recv_type); return -1; } break; case MWIFIEX_USB_EP_DATA: dev_dbg(dev, "%s: EP_DATA\n", __func__); if (skb->len > MWIFIEX_RX_DATA_BUF_SIZE) { dev_err(dev, "DATA: skb->len too large\n"); return -1; } skb_queue_tail(&adapter->usb_rx_data_q, skb); adapter->data_received = true; break; default: dev_err(dev, "%s: unknown endport %#x\n", __func__, ep); return -1; } return -EINPROGRESS; exit_restore_skb: /* The buffer will be reused for further cmds/events */ skb_push(skb, INTF_HEADER_LEN); return ret; }