/* process a received message (i.e. strip off header, process any trailer data) * note : locks must be released when this function is called */ static A_STATUS HTCProcessRecvHeader(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT32 *pNextLookAhead) { A_UINT8 temp; A_UINT8 *pBuf; A_STATUS status = A_OK; A_UINT16 payloadLen; A_UINT32 lookAhead; pBuf = pPacket->pBuffer; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n")); if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) { AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT"); } do { /* note, we cannot assume the alignment of pBuffer, so we use the safe macros to * retrieve 16 bit fields */ payloadLen = A_GET_UINT16_FIELD(pBuf, HTC_FRAME_HDR, PayloadLen); ((A_UINT8 *)&lookAhead)[0] = pBuf[0]; ((A_UINT8 *)&lookAhead)[1] = pBuf[1]; ((A_UINT8 *)&lookAhead)[2] = pBuf[2]; ((A_UINT8 *)&lookAhead)[3] = pBuf[3]; if (lookAhead != pPacket->HTCReserved) { /* somehow the lookahead that gave us the full read length did not * reflect the actual header in the pending message */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCProcessRecvHeader, lookahead mismatch! \n")); DebugDumpBytes((A_UINT8 *)&pPacket->HTCReserved,4,"Expected Message LookAhead"); DebugDumpBytes(pBuf,sizeof(HTC_FRAME_HDR),"Current Frame Header"); #ifdef HTC_CAPTURE_LAST_FRAME DebugDumpBytes((A_UINT8 *)&target->LastFrameHdr,sizeof(HTC_FRAME_HDR),"Last Frame Header"); if (target->LastTrailerLength != 0) { DebugDumpBytes(target->LastTrailer, target->LastTrailerLength, "Last trailer"); } #endif status = A_EPROTO; break; } /* get flags */ temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, Flags); if (temp & HTC_FLAGS_RECV_TRAILER) { /* this packet has a trailer */ /* extract the trailer length in control byte 0 */ temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, ControlBytes[0]); if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n", payloadLen, temp)); status = A_EPROTO; break; } /* process trailer data that follows HDR + application payload */ status = HTCProcessTrailer(target, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp, pNextLookAhead, pPacket->Endpoint); if (A_FAILED(status)) { break; } #ifdef HTC_CAPTURE_LAST_FRAME A_MEMCPY(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp); target->LastTrailerLength = temp; #endif /* trim length by trailer bytes */ pPacket->ActualLength -= temp; } #ifdef HTC_CAPTURE_LAST_FRAME else { target->LastTrailerLength = 0; } #endif /* if we get to this point, the packet is good */ /* remove header and adjust length */ pPacket->pBuffer += HTC_HDR_LENGTH; pPacket->ActualLength -= HTC_HDR_LENGTH; } while (FALSE); if (A_FAILED(status)) { /* dump the whole packet */ DebugDumpBytes(pBuf,pPacket->ActualLength,"BAD HTC Recv PKT"); } else { #ifdef HTC_CAPTURE_LAST_FRAME A_MEMCPY(&target->LastFrameHdr,pBuf,sizeof(HTC_FRAME_HDR)); #endif if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) { if (pPacket->ActualLength > 0) { AR_DEBUG_PRINTBUF(pPacket->pBuffer,pPacket->ActualLength,"HTC - Application Msg"); } } } AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n")); return status; }
static void usb_hif_usb_recv_bundle_complete(struct urb *urb) { HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context; A_STATUS status = A_OK; adf_nbuf_t buf = NULL; HIF_USB_PIPE *pipe = urb_context->pipe; A_UINT8 *netdata, *netdata_new; A_UINT32 netlen, netlen_new; HTC_FRAME_HDR *HtcHdr; A_UINT16 payloadLen; adf_nbuf_t new_skb = NULL; AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ( "+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p\n", __func__, pipe->logical_pipe_num, urb->status, urb->actual_length, urb)); /* this urb is not pending anymore */ usb_hif_remove_pending_transfer(urb_context); do { if (urb->status != 0) { status = A_ECOMM; switch (urb->status) { case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* NOTE: no need to spew these errors when * device is removed * or urb is killed due to driver shutdown */ status = A_ECANCELED; break; default: AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n", __func__, pipe->logical_pipe_num, pipe->ep_address, urb->status)); break; } break; } if (urb->actual_length == 0) break; buf = urb_context->buf; if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) { A_UINT8 *data; A_UINT32 len; adf_nbuf_peek_header(buf, &data, &len); DebugDumpBytes(data, len, "hif recv data"); } adf_nbuf_peek_header(buf, &netdata, &netlen); netlen = urb->actual_length; do { #if defined(AR6004_1_0_ALIGN_WAR) A_UINT8 extra_pad; A_UINT16 act_frame_len; #endif A_UINT16 frame_len; /* Hack into HTC header for bundle processing */ HtcHdr = (HTC_FRAME_HDR *) netdata; if (HtcHdr->EndpointID >= ENDPOINT_MAX) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb: Rx: invalid EndpointID=%d\n", HtcHdr->EndpointID)); break; } payloadLen = HtcHdr->PayloadLen; payloadLen = A_LE2CPU16(payloadLen); #if defined(AR6004_1_0_ALIGN_WAR) act_frame_len = (HTC_HDR_LENGTH + payloadLen); if (HtcHdr->EndpointID == 0 || HtcHdr->EndpointID == 1) { /* assumption: target won't pad on HTC endpoint * 0 & 1. */ extra_pad = 0; } else { extra_pad = A_GET_UINT8_FIELD((A_UINT8 *) HtcHdr, HTC_FRAME_HDR, ControlBytes[1]); } #endif if (payloadLen > HIF_USB_RX_BUFFER_SIZE) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb: payloadLen too long %u\n", payloadLen)); break; } #if defined(AR6004_1_0_ALIGN_WAR) frame_len = (act_frame_len + extra_pad); #else frame_len = (HTC_HDR_LENGTH + payloadLen); #endif if (netlen >= frame_len) { /* allocate a new skb and copy */ #if defined(AR6004_1_0_ALIGN_WAR) new_skb = adf_nbuf_alloc(NULL, act_frame_len, 0, 4, FALSE); if (new_skb == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "athusb: allocate skb (len=%u) failed\n", act_frame_len)); break; } adf_nbuf_peek_header(new_skb, &netdata_new, &netlen_new); adf_os_mem_copy(netdata_new, netdata, act_frame_len); adf_nbuf_put_tail(new_skb, act_frame_len); #else new_skb = adf_nbuf_alloc(NULL, frame_len, 0, 4, FALSE); if (new_skb == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "athusb: allocate skb (len=%u) failed\n", frame_len)); break; } adf_nbuf_peek_header(new_skb, &netdata_new, &netlen_new); adf_os_mem_copy(netdata_new, netdata, frame_len); adf_nbuf_put_tail(new_skb, frame_len); #endif skb_queue_tail(&pipe->io_comp_queue, new_skb); new_skb = NULL; netdata += frame_len; netlen -= frame_len; } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "athusb: subframe length %d not fitted into bundle packet length %d\n" , netlen, frame_len)); break; } } while (netlen); schedule_work(&pipe->io_complete_work); } while (FALSE); if (urb_context->buf == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb: buffer in urb_context is NULL\n")); } /* reset urb_context->buf ==> seems not necessary */ usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context); if (A_SUCCESS(status)) { if (pipe->urb_cnt >= pipe->urb_cnt_thresh) { /* our free urbs are piling up, post more transfers */ usb_hif_post_recv_bundle_transfers(pipe, 0 /* pass zero for not allocating urb-buffer again */ ); } } AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("-%s\n", __func__)); }