| /** | |
| * @file HandleControlPacket.c | |
| * This file contains the routines to deal with | |
| * sending and receiving of control packets. | |
| */ | |
| #include "headers.h" | |
| /** | |
| * When a control packet is received, analyze the | |
| * "status" and call appropriate response function. | |
| * Enqueue the control packet for Application. | |
| * @return None | |
| */ | |
| static VOID handle_rx_control_packet(struct bcm_mini_adapter *Adapter, struct sk_buff *skb) | |
| { | |
| struct bcm_tarang_data *pTarang = NULL; | |
| BOOLEAN HighPriorityMessage = FALSE; | |
| struct sk_buff *newPacket = NULL; | |
| CHAR cntrl_msg_mask_bit = 0; | |
| BOOLEAN drop_pkt_flag = TRUE; | |
| USHORT usStatus = *(PUSHORT)(skb->data); | |
| if (netif_msg_pktdata(Adapter)) | |
| print_hex_dump(KERN_DEBUG, PFX "rx control: ", DUMP_PREFIX_NONE, | |
| 16, 1, skb->data, skb->len, 0); | |
| switch (usStatus) { | |
| case CM_RESPONSES: /* 0xA0 */ | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, | |
| DBG_LVL_ALL, | |
| "MAC Version Seems to be Non Multi-Classifier, rejected by Driver"); | |
| HighPriorityMessage = TRUE; | |
| break; | |
| case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP: | |
| HighPriorityMessage = TRUE; | |
| if (Adapter->LinkStatus == LINKUP_DONE) | |
| CmControlResponseMessage(Adapter, | |
| (skb->data + sizeof(USHORT))); | |
| break; | |
| case LINK_CONTROL_RESP: /* 0xA2 */ | |
| case STATUS_RSP: /* 0xA1 */ | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, | |
| DBG_LVL_ALL, "LINK_CONTROL_RESP"); | |
| HighPriorityMessage = TRUE; | |
| LinkControlResponseMessage(Adapter, | |
| (skb->data + sizeof(USHORT))); | |
| break; | |
| case STATS_POINTER_RESP: /* 0xA6 */ | |
| HighPriorityMessage = TRUE; | |
| StatisticsResponse(Adapter, (skb->data + sizeof(USHORT))); | |
| break; | |
| case IDLE_MODE_STATUS: /* 0xA3 */ | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, | |
| DBG_LVL_ALL, | |
| "IDLE_MODE_STATUS Type Message Got from F/W"); | |
| InterfaceIdleModeRespond(Adapter, (PUINT)(skb->data + | |
| sizeof(USHORT))); | |
| HighPriorityMessage = TRUE; | |
| break; | |
| case AUTH_SS_HOST_MSG: | |
| HighPriorityMessage = TRUE; | |
| break; | |
| default: | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, | |
| DBG_LVL_ALL, "Got Default Response"); | |
| /* Let the Application Deal with This Packet */ | |
| break; | |
| } | |
| /* Queue The Control Packet to The Application Queues */ | |
| down(&Adapter->RxAppControlQueuelock); | |
| for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) { | |
| if (Adapter->device_removed) | |
| break; | |
| drop_pkt_flag = TRUE; | |
| /* | |
| * There are cntrl msg from A0 to AC. It has been mapped to 0 to | |
| * C bit in the cntrl mask. | |
| * Also, by default AD to BF has been masked to the rest of the | |
| * bits... which wil be ON by default. | |
| * if mask bit is enable to particular pkt status, send it out | |
| * to app else stop it. | |
| */ | |
| cntrl_msg_mask_bit = (usStatus & 0x1F); | |
| /* | |
| * printk("\ninew msg mask bit which is disable in mask:%X", | |
| * cntrl_msg_mask_bit); | |
| */ | |
| if (pTarang->RxCntrlMsgBitMask & (1 << cntrl_msg_mask_bit)) | |
| drop_pkt_flag = FALSE; | |
| if ((drop_pkt_flag == TRUE) || | |
| (pTarang->AppCtrlQueueLen > MAX_APP_QUEUE_LEN) | |
| || ((pTarang->AppCtrlQueueLen > | |
| MAX_APP_QUEUE_LEN / 2) && | |
| (HighPriorityMessage == FALSE))) { | |
| /* | |
| * Assumption:- | |
| * 1. every tarang manages it own dropped pkt | |
| * statitistics | |
| * 2. Total packet dropped per tarang will be equal to | |
| * the sum of all types of dropped pkt by that | |
| * tarang only. | |
| */ | |
| switch (*(PUSHORT)skb->data) { | |
| case CM_RESPONSES: | |
| pTarang->stDroppedAppCntrlMsgs.cm_responses++; | |
| break; | |
| case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP: | |
| pTarang->stDroppedAppCntrlMsgs.cm_control_newdsx_multiclassifier_resp++; | |
| break; | |
| case LINK_CONTROL_RESP: | |
| pTarang->stDroppedAppCntrlMsgs.link_control_resp++; | |
| break; | |
| case STATUS_RSP: | |
| pTarang->stDroppedAppCntrlMsgs.status_rsp++; | |
| break; | |
| case STATS_POINTER_RESP: | |
| pTarang->stDroppedAppCntrlMsgs.stats_pointer_resp++; | |
| break; | |
| case IDLE_MODE_STATUS: | |
| pTarang->stDroppedAppCntrlMsgs.idle_mode_status++; | |
| break; | |
| case AUTH_SS_HOST_MSG: | |
| pTarang->stDroppedAppCntrlMsgs.auth_ss_host_msg++; | |
| break; | |
| default: | |
| pTarang->stDroppedAppCntrlMsgs.low_priority_message++; | |
| break; | |
| } | |
| continue; | |
| } | |
| newPacket = skb_clone(skb, GFP_KERNEL); | |
| if (!newPacket) | |
| break; | |
| ENQUEUEPACKET(pTarang->RxAppControlHead, | |
| pTarang->RxAppControlTail, newPacket); | |
| pTarang->AppCtrlQueueLen++; | |
| } | |
| up(&Adapter->RxAppControlQueuelock); | |
| wake_up(&Adapter->process_read_wait_queue); | |
| dev_kfree_skb(skb); | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, | |
| "After wake_up_interruptible"); | |
| } | |
| /** | |
| * @ingroup ctrl_pkt_functions | |
| * Thread to handle control pkt reception | |
| */ | |
| int control_packet_handler(struct bcm_mini_adapter *Adapter /* pointer to adapter object*/) | |
| { | |
| struct sk_buff *ctrl_packet = NULL; | |
| unsigned long flags = 0; | |
| /* struct timeval tv; */ | |
| /* int *puiBuffer = NULL; */ | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, | |
| "Entering to make thread wait on control packet event!"); | |
| while (1) { | |
| wait_event_interruptible(Adapter->process_rx_cntrlpkt, | |
| atomic_read(&Adapter->cntrlpktCnt) || | |
| Adapter->bWakeUpDevice || | |
| kthread_should_stop()); | |
| if (kthread_should_stop()) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, | |
| DBG_LVL_ALL, "Exiting\n"); | |
| return 0; | |
| } | |
| if (TRUE == Adapter->bWakeUpDevice) { | |
| Adapter->bWakeUpDevice = FALSE; | |
| if ((FALSE == Adapter->bTriedToWakeUpFromlowPowerMode) | |
| && ((TRUE == Adapter->IdleMode) || | |
| (TRUE == Adapter->bShutStatus))) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, | |
| CP_CTRL_PKT, DBG_LVL_ALL, | |
| "Calling InterfaceAbortIdlemode\n"); | |
| /* | |
| * Adapter->bTriedToWakeUpFromlowPowerMode | |
| * = TRUE; | |
| */ | |
| InterfaceIdleModeWakeup(Adapter); | |
| } | |
| continue; | |
| } | |
| while (atomic_read(&Adapter->cntrlpktCnt)) { | |
| spin_lock_irqsave(&Adapter->control_queue_lock, flags); | |
| ctrl_packet = Adapter->RxControlHead; | |
| if (ctrl_packet) { | |
| DEQUEUEPACKET(Adapter->RxControlHead, | |
| Adapter->RxControlTail); | |
| /* Adapter->RxControlHead=ctrl_packet->next; */ | |
| } | |
| spin_unlock_irqrestore(&Adapter->control_queue_lock, | |
| flags); | |
| handle_rx_control_packet(Adapter, ctrl_packet); | |
| atomic_dec(&Adapter->cntrlpktCnt); | |
| } | |
| SetUpTargetDsxBuffers(Adapter); | |
| } | |
| return STATUS_SUCCESS; | |
| } | |
| INT flushAllAppQ(void) | |
| { | |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); | |
| struct bcm_tarang_data *pTarang = NULL; | |
| struct sk_buff *PacketToDrop = NULL; | |
| for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) { | |
| while (pTarang->RxAppControlHead != NULL) { | |
| PacketToDrop = pTarang->RxAppControlHead; | |
| DEQUEUEPACKET(pTarang->RxAppControlHead, | |
| pTarang->RxAppControlTail); | |
| dev_kfree_skb(PacketToDrop); | |
| } | |
| pTarang->AppCtrlQueueLen = 0; | |
| /* dropped contrl packet statistics also should be reset. */ | |
| memset((PVOID)&pTarang->stDroppedAppCntrlMsgs, 0, | |
| sizeof(struct bcm_mibs_dropped_cntrl_msg)); | |
| } | |
| return STATUS_SUCCESS; | |
| } | |