1 /* 2 * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "htc_debug.h" 20 #include "htc_internal.h" 21 #include "htc_credit_history.h" 22 #include <qdf_nbuf.h> /* qdf_nbuf_t */ 23 24 /* HTC Control message receive timeout msec */ 25 #define HTC_CONTROL_RX_TIMEOUT 6000 26 27 #if defined(WLAN_DEBUG) || defined(DEBUG) 28 void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription) 29 { 30 int8_t stream[60]; 31 int8_t byteOffsetStr[10]; 32 uint32_t i; 33 uint16_t offset, count, byteOffset; 34 35 A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length, 36 pDescription); 37 38 count = 0; 39 offset = 0; 40 byteOffset = 0; 41 for (i = 0; i < length; i++) { 42 A_SNPRINTF(stream + offset, (sizeof(stream) - offset), 43 "%02X ", buffer[i]); 44 count++; 45 offset += 3; 46 47 if (count == 16) { 48 count = 0; 49 offset = 0; 50 A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X", 51 byteOffset); 52 A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); 53 qdf_mem_zero(stream, 60); 54 byteOffset += 16; 55 } 56 } 57 58 if (offset != 0) { 59 A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X", 60 byteOffset); 61 A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); 62 } 63 64 A_PRINTF("<------------------------------------------------->\n"); 65 } 66 #else 67 void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription) 68 { 69 } 70 #endif 71 72 static A_STATUS htc_process_trailer(HTC_TARGET *target, 73 uint8_t *pBuffer, 74 int Length, HTC_ENDPOINT_ID FromEndpoint); 75 76 static void do_recv_completion_pkt(HTC_ENDPOINT *pEndpoint, 77 HTC_PACKET *pPacket) 78 { 79 if (pEndpoint->EpCallBacks.EpRecv == NULL) { 80 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 81 ("HTC ep %d has NULL recv callback on packet %pK\n", 82 pEndpoint->Id, 83 pPacket)); 84 if (pPacket) 85 qdf_nbuf_free(pPacket->pPktContext); 86 } else { 87 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, 88 ("HTC calling ep %d recv callback on packet %pK\n", 89 pEndpoint->Id, pPacket)); 90 pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, 91 pPacket); 92 } 93 } 94 95 static void do_recv_completion(HTC_ENDPOINT *pEndpoint, 96 HTC_PACKET_QUEUE *pQueueToIndicate) 97 { 98 HTC_PACKET *pPacket; 99 100 if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { 101 /* nothing to indicate */ 102 return; 103 } 104 105 while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) { 106 pPacket = htc_packet_dequeue(pQueueToIndicate); 107 do_recv_completion_pkt(pEndpoint, pPacket); 108 } 109 } 110 111 void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket) 112 { 113 /* TODO, can't really receive HTC control messages yet.... */ 114 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 115 ("Invalid call to htc_control_rx_complete\n")); 116 } 117 118 void htc_unblock_recv(HTC_HANDLE HTCHandle) 119 { 120 /* TODO find the Need in new model */ 121 } 122 123 void htc_enable_recv(HTC_HANDLE HTCHandle) 124 { 125 126 /* TODO find the Need in new model */ 127 } 128 129 void htc_disable_recv(HTC_HANDLE HTCHandle) 130 { 131 132 /* TODO find the Need in new model */ 133 } 134 135 int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint) 136 { 137 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 138 139 HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint]; 140 return HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBufferHoldQueue); 141 } 142 143 HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target) 144 { 145 HTC_PACKET *pPacket; 146 147 LOCK_HTC_RX(target); 148 149 if (NULL == target->pHTCPacketStructPool) { 150 UNLOCK_HTC_RX(target); 151 return NULL; 152 } 153 154 pPacket = target->pHTCPacketStructPool; 155 target->pHTCPacketStructPool = (HTC_PACKET *) pPacket->ListLink.pNext; 156 157 UNLOCK_HTC_RX(target); 158 159 pPacket->ListLink.pNext = NULL; 160 return pPacket; 161 } 162 163 void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket) 164 { 165 pPacket->ListLink.pPrev = NULL; 166 167 LOCK_HTC_RX(target); 168 if (NULL == target->pHTCPacketStructPool) { 169 target->pHTCPacketStructPool = pPacket; 170 pPacket->ListLink.pNext = NULL; 171 } else { 172 pPacket->ListLink.pNext = 173 (DL_LIST *) target->pHTCPacketStructPool; 174 target->pHTCPacketStructPool = pPacket; 175 } 176 177 UNLOCK_HTC_RX(target); 178 } 179 180 #ifdef RX_SG_SUPPORT 181 qdf_nbuf_t rx_sg_to_single_netbuf(HTC_TARGET *target) 182 { 183 qdf_nbuf_t skb; 184 uint8_t *anbdata; 185 uint8_t *anbdata_new; 186 uint32_t anblen; 187 qdf_nbuf_t new_skb = NULL; 188 uint32_t sg_queue_len; 189 qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; 190 191 sg_queue_len = qdf_nbuf_queue_len(rx_sg_queue); 192 193 if (sg_queue_len <= 1) { 194 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 195 ("rx_sg_to_single_netbuf: invalid sg queue len %u\n")); 196 goto _failed; 197 } 198 199 new_skb = qdf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, false); 200 if (new_skb == NULL) { 201 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 202 ("rx_sg_to_single_netbuf: can't allocate %u size netbuf\n", 203 target->ExpRxSgTotalLen)); 204 goto _failed; 205 } 206 207 qdf_nbuf_peek_header(new_skb, &anbdata_new, &anblen); 208 209 skb = qdf_nbuf_queue_remove(rx_sg_queue); 210 do { 211 qdf_nbuf_peek_header(skb, &anbdata, &anblen); 212 qdf_mem_copy(anbdata_new, anbdata, qdf_nbuf_len(skb)); 213 qdf_nbuf_put_tail(new_skb, qdf_nbuf_len(skb)); 214 anbdata_new += qdf_nbuf_len(skb); 215 qdf_nbuf_free(skb); 216 skb = qdf_nbuf_queue_remove(rx_sg_queue); 217 } while (skb != NULL); 218 219 RESET_RX_SG_CONFIG(target); 220 return new_skb; 221 222 _failed: 223 224 while ((skb = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL) 225 qdf_nbuf_free(skb); 226 227 RESET_RX_SG_CONFIG(target); 228 return NULL; 229 } 230 #endif 231 232 #ifdef CONFIG_WIN 233 #define HTC_MSG_NACK_SUSPEND 7 234 #endif 235 236 QDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf, 237 uint8_t pipeID) 238 { 239 QDF_STATUS status = QDF_STATUS_SUCCESS; 240 HTC_FRAME_HDR *HtcHdr; 241 HTC_TARGET *target = (HTC_TARGET *) Context; 242 uint8_t *netdata; 243 uint32_t netlen; 244 HTC_ENDPOINT *pEndpoint; 245 HTC_PACKET *pPacket; 246 uint16_t payloadLen; 247 uint32_t trailerlen = 0; 248 uint8_t htc_ep_id; 249 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID 250 struct htc_init_info *info; 251 #endif 252 253 #ifdef RX_SG_SUPPORT 254 LOCK_HTC_RX(target); 255 if (target->IsRxSgInprogress) { 256 target->CurRxSgTotalLen += qdf_nbuf_len(netbuf); 257 qdf_nbuf_queue_add(&target->RxSgQueue, netbuf); 258 if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) { 259 netbuf = rx_sg_to_single_netbuf(target); 260 if (netbuf == NULL) { 261 UNLOCK_HTC_RX(target); 262 goto _out; 263 } 264 } else { 265 netbuf = NULL; 266 UNLOCK_HTC_RX(target); 267 goto _out; 268 } 269 } 270 UNLOCK_HTC_RX(target); 271 #endif 272 273 netdata = qdf_nbuf_data(netbuf); 274 netlen = qdf_nbuf_len(netbuf); 275 276 HtcHdr = (HTC_FRAME_HDR *) netdata; 277 278 do { 279 280 htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID); 281 282 if (htc_ep_id >= ENDPOINT_MAX) { 283 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 284 ("HTC Rx: invalid EndpointID=%d\n", 285 htc_ep_id)); 286 debug_dump_bytes((uint8_t *) HtcHdr, 287 sizeof(HTC_FRAME_HDR), 288 "BAD HTC Header"); 289 status = QDF_STATUS_E_FAILURE; 290 QDF_BUG(0); 291 break; 292 } 293 294 pEndpoint = &target->endpoint[htc_ep_id]; 295 296 /* 297 * If this endpoint that received a message from the target has 298 * a to-target HIF pipe whose send completions are polled rather 299 * than interrupt driven, this is a good point to ask HIF to 300 * check whether it has any completed sends to handle. 301 */ 302 if (pEndpoint->ul_is_polled) 303 htc_send_complete_check(pEndpoint, 1); 304 305 payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN); 306 307 if (netlen < (payloadLen + HTC_HDR_LENGTH)) { 308 #ifdef RX_SG_SUPPORT 309 LOCK_HTC_RX(target); 310 target->IsRxSgInprogress = true; 311 qdf_nbuf_queue_init(&target->RxSgQueue); 312 qdf_nbuf_queue_add(&target->RxSgQueue, netbuf); 313 target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH); 314 target->CurRxSgTotalLen += netlen; 315 UNLOCK_HTC_RX(target); 316 netbuf = NULL; 317 break; 318 #else 319 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 320 ("HTC Rx: insufficient length, got:%d expected =%zu\n", 321 netlen, payloadLen + HTC_HDR_LENGTH)); 322 debug_dump_bytes((uint8_t *) HtcHdr, 323 sizeof(HTC_FRAME_HDR), 324 "BAD RX packet length"); 325 status = QDF_STATUS_E_FAILURE; 326 QDF_BUG(0); 327 break; 328 #endif 329 } 330 #ifdef HTC_EP_STAT_PROFILING 331 LOCK_HTC_RX(target); 332 INC_HTC_EP_STAT(pEndpoint, RxReceived, 1); 333 UNLOCK_HTC_RX(target); 334 #endif 335 336 /* if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { */ 337 { 338 uint8_t temp; 339 A_STATUS temp_status; 340 /* get flags to check for trailer */ 341 temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS); 342 if (temp & HTC_FLAGS_RECV_TRAILER) { 343 /* extract the trailer length */ 344 temp = 345 HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, 346 CONTROLBYTES0); 347 if ((temp < sizeof(HTC_RECORD_HDR)) 348 || (temp > payloadLen)) { 349 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 350 ("htc_rx_completion_handler, invalid header (payloadlength should be :%d, CB[0] is:%d)\n", 351 payloadLen, temp)); 352 status = QDF_STATUS_E_INVAL; 353 break; 354 } 355 356 trailerlen = temp; 357 /* process trailer data that follows HDR + 358 * application payload 359 */ 360 temp_status = htc_process_trailer(target, 361 ((uint8_t *) HtcHdr + 362 HTC_HDR_LENGTH + 363 payloadLen - temp), 364 temp, htc_ep_id); 365 if (A_FAILED(temp_status)) { 366 status = QDF_STATUS_E_FAILURE; 367 break; 368 } 369 370 } 371 } 372 373 if (((int)payloadLen - (int)trailerlen) <= 0) { 374 /* 0 length packet with trailer data, just drop these */ 375 break; 376 } 377 378 if (htc_ep_id == ENDPOINT_0) { 379 uint16_t message_id; 380 HTC_UNKNOWN_MSG *htc_msg; 381 bool wow_nack; 382 383 /* remove HTC header */ 384 qdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH); 385 netdata = qdf_nbuf_data(netbuf); 386 netlen = qdf_nbuf_len(netbuf); 387 388 htc_msg = (HTC_UNKNOWN_MSG *) netdata; 389 message_id = HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, 390 MESSAGEID); 391 392 switch (message_id) { 393 default: 394 /* handle HTC control message */ 395 if (target->CtrlResponseProcessing) { 396 /* this is a fatal error, target should 397 * not be sending unsolicited messages 398 * on the endpoint 0 399 */ 400 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 401 ("HTC Rx Ctrl still processing\n")); 402 status = QDF_STATUS_E_FAILURE; 403 QDF_BUG(false); 404 break; 405 } 406 407 LOCK_HTC_RX(target); 408 target->CtrlResponseLength = 409 min((int)netlen, 410 HTC_MAX_CONTROL_MESSAGE_LENGTH); 411 qdf_mem_copy(target->CtrlResponseBuffer, 412 netdata, 413 target->CtrlResponseLength); 414 415 /* Requester will clear this flag */ 416 target->CtrlResponseProcessing = true; 417 UNLOCK_HTC_RX(target); 418 419 qdf_event_set(&target->ctrl_response_valid); 420 break; 421 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID 422 case HTC_MSG_WAKEUP_FROM_SUSPEND_ID: 423 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 424 ("Received initial wake up")); 425 htc_credit_record(HTC_INITIAL_WAKE_UP, 426 pEndpoint->TxCredits, 427 HTC_PACKET_QUEUE_DEPTH( 428 &pEndpoint->TxQueue)); 429 info = &target->HTCInitInfo; 430 if (info && info->target_initial_wakeup_cb) 431 info->target_initial_wakeup_cb( 432 info->target_psoc); 433 else 434 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 435 ("No initial wake up cb")); 436 break; 437 #endif 438 case HTC_MSG_SEND_SUSPEND_COMPLETE: 439 wow_nack = false; 440 htc_credit_record(HTC_SUSPEND_ACK, 441 pEndpoint->TxCredits, 442 HTC_PACKET_QUEUE_DEPTH( 443 &pEndpoint->TxQueue)); 444 target->HTCInitInfo.TargetSendSuspendComplete( 445 target->HTCInitInfo.target_psoc, 446 wow_nack); 447 448 break; 449 case HTC_MSG_NACK_SUSPEND: 450 wow_nack = true; 451 htc_credit_record(HTC_SUSPEND_ACK, 452 pEndpoint->TxCredits, 453 HTC_PACKET_QUEUE_DEPTH( 454 &pEndpoint->TxQueue)); 455 target->HTCInitInfo.TargetSendSuspendComplete( 456 target->HTCInitInfo.target_psoc, 457 wow_nack); 458 break; 459 } 460 461 qdf_nbuf_free(netbuf); 462 netbuf = NULL; 463 break; 464 } 465 466 /* the current message based HIF architecture allocates net bufs 467 * for recv packets since this layer bridges that HIF to upper 468 * layers , which expects HTC packets, we form the packets here 469 * TODO_FIXME 470 */ 471 pPacket = allocate_htc_packet_container(target); 472 if (NULL == pPacket) { 473 status = QDF_STATUS_E_RESOURCES; 474 break; 475 } 476 pPacket->Status = QDF_STATUS_SUCCESS; 477 pPacket->Endpoint = htc_ep_id; 478 pPacket->pPktContext = netbuf; 479 pPacket->pBuffer = qdf_nbuf_data(netbuf) + HTC_HDR_LENGTH; 480 pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen; 481 482 qdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN); 483 qdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength); 484 485 do_recv_completion_pkt(pEndpoint, pPacket); 486 487 /* recover the packet container */ 488 free_htc_packet_container(target, pPacket); 489 490 netbuf = NULL; 491 492 } while (false); 493 494 #ifdef RX_SG_SUPPORT 495 _out: 496 #endif 497 498 if (netbuf != NULL) 499 qdf_nbuf_free(netbuf); 500 501 return status; 502 503 } 504 505 A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle, 506 HTC_PACKET_QUEUE *pPktQueue) 507 { 508 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 509 HTC_ENDPOINT *pEndpoint; 510 HTC_PACKET *pFirstPacket; 511 A_STATUS status = A_OK; 512 HTC_PACKET *pPacket; 513 514 pFirstPacket = htc_get_pkt_at_head(pPktQueue); 515 516 if (NULL == pFirstPacket) { 517 A_ASSERT(false); 518 return A_EINVAL; 519 } 520 521 AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX); 522 523 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, 524 ("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n", 525 pFirstPacket->Endpoint, 526 HTC_PACKET_QUEUE_DEPTH(pPktQueue), 527 pFirstPacket->BufferLength)); 528 529 pEndpoint = &target->endpoint[pFirstPacket->Endpoint]; 530 531 LOCK_HTC_RX(target); 532 533 do { 534 535 if (HTC_STOPPING(target)) { 536 status = A_ERROR; 537 break; 538 } 539 540 /* store receive packets */ 541 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue, 542 pPktQueue); 543 544 } while (false); 545 546 UNLOCK_HTC_RX(target); 547 548 if (A_FAILED(status)) { 549 /* walk through queue and mark each one canceled */ 550 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) { 551 pPacket->Status = QDF_STATUS_E_CANCELED; 552 } 553 HTC_PACKET_QUEUE_ITERATE_END; 554 555 do_recv_completion(pEndpoint, pPktQueue); 556 } 557 558 return status; 559 } 560 561 A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket) 562 { 563 HTC_PACKET_QUEUE queue; 564 565 INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket); 566 return htc_add_receive_pkt_multiple(HTCHandle, &queue); 567 } 568 569 void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) 570 { 571 HTC_PACKET *pPacket; 572 573 LOCK_HTC_RX(target); 574 575 while (1) { 576 pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue); 577 if (pPacket == NULL) 578 break; 579 UNLOCK_HTC_RX(target); 580 pPacket->Status = QDF_STATUS_E_CANCELED; 581 pPacket->ActualLength = 0; 582 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, 583 ("Flushing RX packet:%pK, length:%d, ep:%d\n", 584 pPacket, pPacket->BufferLength, 585 pPacket->Endpoint)); 586 /* give the packet back */ 587 do_recv_completion_pkt(pEndpoint, pPacket); 588 LOCK_HTC_RX(target); 589 } 590 591 UNLOCK_HTC_RX(target); 592 } 593 594 void htc_recv_init(HTC_TARGET *target) 595 { 596 /* Initialize ctrl_response_valid to block */ 597 qdf_event_create(&target->ctrl_response_valid); 598 } 599 600 /* polling routine to wait for a control packet to be received */ 601 QDF_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target) 602 { 603 /* int count = HTC_TARGET_MAX_RESPONSE_POLL; */ 604 605 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCWaitCtrlMessageRecv\n")); 606 607 /* Wait for BMI request/response transaction to complete */ 608 if (qdf_wait_single_event(&target->ctrl_response_valid, 609 HTC_CONTROL_RX_TIMEOUT)) { 610 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 611 ("Failed to receive control message\n")); 612 return QDF_STATUS_E_FAILURE; 613 } 614 615 LOCK_HTC_RX(target); 616 /* caller will clear this flag */ 617 target->CtrlResponseProcessing = true; 618 619 UNLOCK_HTC_RX(target); 620 621 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCWaitCtrlMessageRecv success\n")); 622 return QDF_STATUS_SUCCESS; 623 } 624 625 static A_STATUS htc_process_trailer(HTC_TARGET *target, 626 uint8_t *pBuffer, 627 int Length, HTC_ENDPOINT_ID FromEndpoint) 628 { 629 HTC_RECORD_HDR *pRecord; 630 uint8_t htc_rec_id; 631 uint8_t htc_rec_len; 632 uint8_t *pRecordBuf; 633 uint8_t *pOrigBuffer; 634 int origLength; 635 A_STATUS status; 636 637 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, 638 ("+htc_process_trailer (length:%d)\n", Length)); 639 640 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) 641 AR_DEBUG_PRINTBUF(pBuffer, Length, "Recv Trailer"); 642 643 pOrigBuffer = pBuffer; 644 origLength = Length; 645 status = A_OK; 646 647 while (Length > 0) { 648 649 if (Length < sizeof(HTC_RECORD_HDR)) { 650 status = A_EPROTO; 651 break; 652 } 653 /* these are byte aligned structs */ 654 pRecord = (HTC_RECORD_HDR *) pBuffer; 655 Length -= sizeof(HTC_RECORD_HDR); 656 pBuffer += sizeof(HTC_RECORD_HDR); 657 658 htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH); 659 htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID); 660 661 if (htc_rec_len > Length) { 662 /* no room left in buffer for record */ 663 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 664 ("invalid record length: %d (id:%d) buffer has: %d bytes left\n", 665 htc_rec_len, htc_rec_id, Length)); 666 status = A_EPROTO; 667 break; 668 } 669 /* start of record follows the header */ 670 pRecordBuf = pBuffer; 671 672 switch (htc_rec_id) { 673 case HTC_RECORD_CREDITS: 674 AR_DEBUG_ASSERT(htc_rec_len >= 675 sizeof(HTC_CREDIT_REPORT)); 676 htc_process_credit_rpt(target, 677 (HTC_CREDIT_REPORT *) pRecordBuf, 678 htc_rec_len / 679 (sizeof(HTC_CREDIT_REPORT)), 680 FromEndpoint); 681 break; 682 683 #ifdef HIF_SDIO 684 case HTC_RECORD_LOOKAHEAD: 685 /* Process in HIF layer */ 686 break; 687 688 case HTC_RECORD_LOOKAHEAD_BUNDLE: 689 /* Process in HIF layer */ 690 break; 691 #endif /* HIF_SDIO */ 692 693 default: 694 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 695 ("HTC unhandled record: id:%d length:%d\n", 696 htc_rec_id, htc_rec_len)); 697 break; 698 } 699 700 if (A_FAILED(status)) { 701 break; 702 } 703 704 /* advance buffer past this record for next time around */ 705 pBuffer += htc_rec_len; 706 Length -= htc_rec_len; 707 } 708 709 if (A_FAILED(status)) 710 debug_dump_bytes(pOrigBuffer, origLength, "BAD Recv Trailer"); 711 712 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer\n")); 713 return status; 714 715 } 716