static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) { struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); u16 qindex = skb_get_queue_mapping(skb); if (Adapter->device_removed || !Adapter->LinkUpStatus) goto drop; if (Adapter->TransferMode != IP_PACKET_ONLY_MODE) goto drop; if (INVALID_QUEUE_INDEX == qindex) goto drop; if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) return NETDEV_TX_BUSY; /* Now Enqueue the packet */ if (netif_msg_tx_queued(Adapter)) pr_info(PFX "%s: enqueueing packet to queue %d\n", dev->name, qindex); spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; *((B_UINT32 *) skb->cb + SKB_CB_LATENCY_OFFSET) = jiffies; ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, Adapter->PackInfo[qindex].LastTxQueue, skb); atomic_inc(&Adapter->TotalPacketCount); spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); /* FIXME - this is racy and incorrect, replace with work queue */ if (!atomic_read(&Adapter->TxPktAvail)) { atomic_set(&Adapter->TxPktAvail, 1); wake_up(&Adapter->tx_packet_wait_queue); } return NETDEV_TX_OK; drop: dev_kfree_skb(skb); return NETDEV_TX_OK; }
static VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, struct sk_buff *skb) { PPER_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: 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: case STATUS_RSP: 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: HighPriorityMessage = TRUE; StatisticsResponse(Adapter, (skb->data + sizeof(USHORT))); break; case IDLE_MODE_STATUS: 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"); break; } down(&Adapter->RxAppControlQueuelock); for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) { if (Adapter->device_removed) break; drop_pkt_flag = TRUE; cntrl_msg_mask_bit = (usStatus & 0x1F); 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))) { 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"); }
static void read_bulk_callback(struct urb *urb) { struct sk_buff *skb = NULL; BOOLEAN bHeaderSupressionEnabled = FALSE; int QueueIndex = NO_OF_QUEUES + 1; UINT uiIndex=0; int process_done = 1; PUSB_RCB pRcb = (PUSB_RCB)urb->context; PS_INTERFACE_ADAPTER psIntfAdapter = pRcb->psIntfAdapter; PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter; PLEADER pLeader = urb->transfer_buffer; if (unlikely(netif_msg_rx_status(Adapter))) pr_info(PFX "%s: rx urb status %d length %d\n", Adapter->dev->name, urb->status, urb->actual_length); if((Adapter->device_removed == TRUE) || (TRUE == Adapter->bEndPointHalted) || (0 == urb->actual_length) ) { pRcb->bUsed = FALSE; atomic_dec(&psIntfAdapter->uNumRcbUsed); return; } if(urb->status != STATUS_SUCCESS) { if(urb->status == -EPIPE) { Adapter->bEndPointHalted = TRUE ; wake_up(&Adapter->tx_packet_wait_queue); } else { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,"Rx URB has got cancelled. status :%d", urb->status); } pRcb->bUsed = FALSE; atomic_dec(&psIntfAdapter->uNumRcbUsed); urb->status = STATUS_SUCCESS ; return ; } if(Adapter->bDoSuspend && (Adapter->bPreparingForLowPowerMode)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,"device is going in low power mode while PMU option selected..hence rx packet should not be process"); return ; } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Read back done len %d\n", pLeader->PLength); if(!pLeader->PLength) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Length 0"); atomic_dec(&psIntfAdapter->uNumRcbUsed); return; } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Status:0x%hX, Length:0x%hX, VCID:0x%hX", pLeader->Status,pLeader->PLength,pLeader->Vcid); if(MAX_CNTL_PKT_SIZE < pLeader->PLength) { if (netif_msg_rx_err(Adapter)) pr_info(PFX "%s: corrupted leader length...%d\n", Adapter->dev->name, pLeader->PLength); ++Adapter->dev->stats.rx_dropped; atomic_dec(&psIntfAdapter->uNumRcbUsed); return; } QueueIndex = SearchVcid( Adapter,pLeader->Vcid); if(QueueIndex < NO_OF_QUEUES) { bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled; bHeaderSupressionEnabled = bHeaderSupressionEnabled & Adapter->bPHSEnabled; } skb = dev_alloc_skb (pLeader->PLength + SKB_RESERVE_PHS_BYTES + SKB_RESERVE_ETHERNET_HEADER); if(!skb) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "NO SKBUFF!!! Dropping the Packet"); atomic_dec(&psIntfAdapter->uNumRcbUsed); return; } if((ntohs(pLeader->Vcid) == VCID_CONTROL_PACKET) || (!(pLeader->Status >= 0x20 && pLeader->Status <= 0x3F))) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL, "Received control pkt..."); *(PUSHORT)skb->data = pLeader->Status; memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer + (sizeof(LEADER)), pLeader->PLength); skb->len = pLeader->PLength + sizeof(USHORT); spin_lock(&Adapter->control_queue_lock); ENQUEUEPACKET(Adapter->RxControlHead,Adapter->RxControlTail,skb); spin_unlock(&Adapter->control_queue_lock); atomic_inc(&Adapter->cntrlpktCnt); wake_up(&Adapter->process_rx_cntrlpkt); } else { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt..."); skb_reserve(skb, 2 + SKB_RESERVE_PHS_BYTES); memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer + sizeof(LEADER), pLeader->PLength); skb->dev = Adapter->dev; skb_put (skb, pLeader->PLength + ETH_HLEN); Adapter->PackInfo[QueueIndex].uiTotalRxBytes+=pLeader->PLength; Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes+= pLeader->PLength; BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt of len :0x%X", pLeader->PLength); if(netif_running(Adapter->dev)) { skb_pull(skb, ETH_HLEN); PHSReceive(Adapter, pLeader->Vcid, skb, &skb->len, NULL,bHeaderSupressionEnabled); if(!Adapter->PackInfo[QueueIndex].bEthCSSupport) { skb_push(skb, ETH_HLEN); memcpy(skb->data, skb->dev->dev_addr, 6); memcpy(skb->data+6, skb->dev->dev_addr, 6); (*(skb->data+11))++; *(skb->data+12) = 0x08; *(skb->data+13) = 0x00; pLeader->PLength+=ETH_HLEN; } skb->protocol = eth_type_trans(skb, Adapter->dev); process_done = netif_rx(skb); } else { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB..."); dev_kfree_skb(skb); } ++Adapter->dev->stats.rx_packets; Adapter->dev->stats.rx_bytes += pLeader->PLength; for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++) { if((pLeader->PLength <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) && (pLeader->PLength > MIBS_PKTSIZEHIST_RANGE*(uiIndex))) Adapter->aRxPktSizeHist[uiIndex]++; } } Adapter->PrevNumRecvDescs++; pRcb->bUsed = FALSE; atomic_dec(&psIntfAdapter->uNumRcbUsed); }
/** * 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"); }
INT bcm_transmit(struct sk_buff *skb, /**< skb */ struct net_device *dev /**< net device pointer */ ) { PMINI_ADAPTER Adapter = NULL; USHORT qindex=0; struct timeval tv; UINT pkt_type = 0; UINT calltransmit = 0; INT status = STATUS_SUCCESS; BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "\n%s====>\n",__FUNCTION__); memset(&tv, 0, sizeof(tv)); /* Check for valid parameters */ if(skb == NULL || dev==NULL) { BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n"); return -EINVAL; } Adapter = GET_BCM_ADAPTER(dev); if(!Adapter) { BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Got Invalid Adapter\n"); status = -EINVAL; goto exit_path; } if(Adapter->device_removed == TRUE || !Adapter->LinkUpStatus) { if(!netif_queue_stopped(dev)) { netif_carrier_off(dev); netif_stop_queue(dev); } status = STATUS_FAILURE; goto exit_path; } BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Packet size : %d\n", skb->len); /*Add Ethernet CS check here*/ if(Adapter->TransferMode == IP_PACKET_ONLY_MODE ) { pkt_type = ntohs(*(PUSHORT)(skb->data + 12)); /* Get the queue index where the packet is to be queued */ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Getting the Queue Index....."); qindex = GetPacketQueueIndex(Adapter,skb); if((SHORT)INVALID_QUEUE_INDEX==(SHORT)qindex) { if(pkt_type == ETH_ARP_FRAME) { /* Reply directly to ARP request packet ARP Spoofing only if NO ETH CS rule matches for it */ BCM_DEBUG_PRINT (Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ARP OPCODE = %02x", (*(PUCHAR)(skb->data + 21))); reply_to_arp_request(skb); BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL,"After reply_to_arp_request \n"); } else { BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Invalid queue index, dropping pkt\n"); status = STATUS_FAILURE; } goto exit_path; } if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) { atomic_inc(&Adapter->TxDroppedPacketCount); status = STATUS_FAILURE; goto exit_path; } /* Now Enqueue the packet */ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit Enqueueing the Packet To Queue %d",qindex); spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies; ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, Adapter->PackInfo[qindex].LastTxQueue, skb); atomic_inc(&Adapter->TotalPacketCount); spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); do_gettimeofday(&tv); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n"); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Pkt Len = %d, sec: %ld, usec: %ld\n", (skb->len-ETH_HLEN), tv.tv_sec, tv.tv_usec); #ifdef BCM_SHM_INTERFACE spin_lock(&Adapter->txtransmitlock); if(Adapter->txtransmit_running == 0) { Adapter->txtransmit_running = 1; calltransmit = 1; } else calltransmit = 0; spin_unlock(&Adapter->txtransmitlock); #endif if(calltransmit == 1) transmit_packets(Adapter); else { if(!atomic_read(&Adapter->TxPktAvail)) { atomic_set(&Adapter->TxPktAvail, 1); #ifdef BCM_SHM_INTERFACE virtual_mail_box_interrupt(); #endif wake_up(&Adapter->tx_packet_wait_queue); } } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<===="); } else status = STATUS_FAILURE; exit_path: if(status != STATUS_SUCCESS) bcm_kfree_skb(skb); /* It is expected to return the correct status if running in cut-through mode */ if(Adapter->bNetworkInterfaceRegistered == FALSE) return status; /* It is expected to return as Success for Network Stack - This will ensure that the packet is owned by the driver which shall free the same*/ else return STATUS_SUCCESS; }