/** * @brief This function converts Tx/Rx rates from the Marvell WLAN format * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) * * @param rate Input rate * @return Output Rate (0 if invalid) */ static u8 convert_mv_rate_to_radiotap(u8 rate) { switch (rate) { case 0: /* 1 Mbps */ return 2; case 1: /* 2 Mbps */ return 4; case 2: /* 5.5 Mbps */ return 11; case 3: /* 11 Mbps */ return 22; /* case 4: reserved */ case 5: /* 6 Mbps */ return 12; case 6: /* 9 Mbps */ return 18; case 7: /* 12 Mbps */ return 24; case 8: /* 18 Mbps */ return 36; case 9: /* 24 Mbps */ return 48; case 10: /* 36 Mbps */ return 72; case 11: /* 48 Mbps */ return 96; case 12: /* 54 Mbps */ return 108; } lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate); return 0; }
/*********************************************************************************************** ****函数名:lbs_send_confirmsleep ****描述:网卡进入低功耗模式 ****参数:priv:全局驱动变量 ****返回:无 ***********************************************************************************************/ void lbs_send_confirmsleep(struct lbs_private *priv) { int ret; lbs_deb_enter(LBS_DEB_HOST); lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep, sizeof(confirm_sleep)); ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep, sizeof(confirm_sleep)); if (ret) { lbs_pr_alert("confirm_sleep failed\n"); goto out; } /* We don't get a response on the sleep-confirmation */ priv->dnld_sent = DNLD_RES_RECEIVED; out: lbs_deb_leave(LBS_DEB_HOST); }
static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) { unsigned long flags; wlan_adapter *adapter = priv->adapter; int ret = 0; lbs_deb_enter(LBS_DEB_HOST); lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n", size); lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size); ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size); priv->dnld_sent = DNLD_RES_RECEIVED; spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->intcounter || adapter->currenttxskb) lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n", adapter->intcounter, adapter->currenttxskb); spin_unlock_irqrestore(&adapter->driver_lock, flags); if (ret) { lbs_pr_alert( "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n"); } else { spin_lock_irqsave(&adapter->driver_lock, flags); if (!adapter->intcounter) { adapter->psstate = PS_STATE_SLEEP; } else { lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n", adapter->intcounter); } spin_unlock_irqrestore(&adapter->driver_lock, flags); lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n"); } lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }
static int lbs_send_confirmwake(struct lbs_private *priv) { struct cmd_header cmd; int ret = 0; lbs_deb_enter(LBS_DEB_HOST); cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM); cmd.size = cpu_to_le16(sizeof(cmd)); cmd.seqnum = cpu_to_le16(++priv->seqnum); cmd.result = 0; lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd, sizeof(cmd)); ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd)); if (ret) lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n"); lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; }
/** * @brief This function processes a received 802.11 packet and forwards it * to kernel/upper layer * * @param priv A pointer to struct lbs_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ static int process_rxed_802_11_packet(struct lbs_private *priv, struct sk_buff *skb) { int ret = 0; struct net_device *dev = priv->dev; struct rx80211packethdr *p_rx_pkt; struct rxpd *prxpd; struct rx_radiotap_hdr radiotap_hdr; struct rx_radiotap_hdr *pradiotap_hdr; lbs_deb_enter(LBS_DEB_RX); p_rx_pkt = (struct rx80211packethdr *) skb->data; prxpd = &p_rx_pkt->rx_pd; // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received with bad length\n"); dev->stats.rx_length_errors++; ret = -EINVAL; kfree_skb(skb); goto done; } /* * Check rxpd status and update 802.3 stat, */ if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { //lbs_deb_rx("rx err: frame received with bad status\n"); dev->stats.rx_errors++; } lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); /* create the exported radio header */ /* radiotap header */ radiotap_hdr.hdr.it_version = 0; /* XXX must check this value for pad */ radiotap_hdr.hdr.it_pad = 0; radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) radiotap_hdr.flags |= IEEE80211_RADIOTAP_F_BADFCS; radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); /* XXX must check no carryout */ radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); /* add space for the new radio header */ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) { lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__); ret = -ENOMEM; kfree_skb(skb); goto done; } pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); /* Take the data rate from the rxpd structure * only if the rate is auto */ if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); lbs_compute_rssi(priv, prxpd); lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); dev->stats.rx_bytes += skb->len; dev->stats.rx_packets++; skb->protocol = eth_type_trans(skb, priv->rtap_net_dev); netif_rx(skb); ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; }
/** * @brief This function processes received packet and forwards it * to kernel/upper layer * * @param priv A pointer to struct lbs_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) { int ret = 0; struct net_device *dev = priv->dev; struct rxpackethdr *p_rx_pkt; struct rxpd *p_rx_pd; int hdrchop; struct ethhdr *p_ethhdr; const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; lbs_deb_enter(LBS_DEB_RX); BUG_ON(!skb); skb->ip_summed = CHECKSUM_NONE; if (priv->monitormode) return process_rxed_802_11_packet(priv, skb); p_rx_pkt = (struct rxpackethdr *) skb->data; p_rx_pd = &p_rx_pkt->rx_pd; if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME)) dev = priv->mesh_dev; lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min_t(unsigned int, skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received with bad length\n"); dev->stats.rx_length_errors++; ret = 0; dev_kfree_skb(skb); goto done; } /* * Check rxpd status and update 802.3 stat, */ if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { lbs_deb_rx("rx err: frame received with bad status\n"); lbs_pr_alert("rxpd not ok\n"); dev->stats.rx_errors++; ret = 0; dev_kfree_skb(skb); goto done; } lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, sizeof(p_rx_pkt->eth803_hdr.src_addr)); if (memcmp(&p_rx_pkt->rfc1042_hdr, rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { /* * Replace the 803 header and rfc1042 header (llc/snap) with an * EthernetII header, keep the src/dst and snap_type (ethertype) * * The firmware only passes up SNAP frames converting * all RX Data from 802.11 to 802.2/LLC/SNAP frames. * * To create the Ethernet II, just move the src, dst address right * before the snap_type. */ p_ethhdr = (struct ethhdr *) ((u8 *) & p_rx_pkt->eth803_hdr + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr) - sizeof(p_rx_pkt->eth803_hdr.dest_addr) - sizeof(p_rx_pkt->eth803_hdr.src_addr) - sizeof(p_rx_pkt->rfc1042_hdr.snap_type)); memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr, sizeof(p_ethhdr->h_source)); memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_ethhdr->h_dest)); /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header * that was removed */ hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt; } else { lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP", (u8 *) & p_rx_pkt->rfc1042_hdr, sizeof(p_rx_pkt->rfc1042_hdr)); /* Chop off the rxpd */ hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt; } /* Chop off the leading header bytes so the skb points to the start of * either the reconstructed EthII frame or the 802.2/llc/snap frame */ skb_pull(skb, hdrchop); /* Take the data rate from the rxpd structure * only if the rate is auto */ if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); lbs_compute_rssi(priv, p_rx_pd); lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); dev->stats.rx_bytes += skb->len; dev->stats.rx_packets++; skb->protocol = eth_type_trans(skb, dev); if (in_interrupt()) netif_rx(skb); else netif_rx_ni(skb); ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; }
int lbs_process_event(struct lbs_private *priv, u32 event) { int ret = 0; lbs_deb_enter(LBS_DEB_CMD); switch (event) { case MACREG_INT_CODE_LINK_SENSED: lbs_deb_cmd("EVENT: link sensed\n"); break; case MACREG_INT_CODE_DEAUTHENTICATED: lbs_deb_cmd("EVENT: deauthenticated\n"); lbs_mac_event_disconnected(priv); break; case MACREG_INT_CODE_DISASSOCIATED: lbs_deb_cmd("EVENT: disassociated\n"); lbs_mac_event_disconnected(priv); break; case MACREG_INT_CODE_LINK_LOST_NO_SCAN: lbs_deb_cmd("EVENT: link lost\n"); lbs_mac_event_disconnected(priv); break; case MACREG_INT_CODE_PS_SLEEP: lbs_deb_cmd("EVENT: ps sleep\n"); /* handle unexpected PS SLEEP event */ if (priv->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n"); break; } priv->psstate = PS_STATE_PRE_SLEEP; lbs_ps_confirm_sleep(priv); break; case MACREG_INT_CODE_HOST_AWAKE: lbs_deb_cmd("EVENT: host awake\n"); lbs_send_confirmwake(priv); break; case MACREG_INT_CODE_PS_AWAKE: lbs_deb_cmd("EVENT: ps awake\n"); /* handle unexpected PS AWAKE event */ if (priv->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); break; } priv->psstate = PS_STATE_AWAKE; if (priv->needtowakeup) { /* * wait for the command processing to finish * before resuming sending * priv->needtowakeup will be set to FALSE * in lbs_ps_wakeup() */ lbs_deb_cmd("waking up ...\n"); lbs_ps_wakeup(priv, 0); } break; case MACREG_INT_CODE_MIC_ERR_UNICAST: lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n"); handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); break; case MACREG_INT_CODE_MIC_ERR_MULTICAST: lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n"); handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); break; case MACREG_INT_CODE_MIB_CHANGED: lbs_deb_cmd("EVENT: MIB CHANGED\n"); break; case MACREG_INT_CODE_INIT_DONE: lbs_deb_cmd("EVENT: INIT DONE\n"); break; case MACREG_INT_CODE_ADHOC_BCN_LOST: lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: lbs_pr_alert("EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: lbs_pr_alert("EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: lbs_pr_alert("EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: lbs_pr_alert("EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: lbs_pr_alert("EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: /* Ignore spurious autostart events if autostart is disabled */ if (!priv->mesh_autostart_enabled) { lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; } lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); priv->mesh_connect_status = LBS_CONNECTED; if (priv->mesh_open) { netif_carrier_on(priv->mesh_dev); if (!priv->tx_pending_len) netif_wake_queue(priv->mesh_dev); } priv->mode = IW_MODE_ADHOC; schedule_work(&priv->sync_channel); break; default: lbs_pr_alert("EVENT: unknown event id %d\n", event); break; } lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; }
//HelloX: This thread will be waken up by other routines through the calling of //wake_up_interruptible routine,in HelloX's implementation,this mechanism should be //replaced by event,a dedicated event object is defined under lbs_private structure, //the lbs_thread should wait on this event object when shouldsleep = 1. //Other routines who want to process lbs command,should set the event object status //to signal,thus lead the wake up of lbs_thread. int lbs_thread(struct lbs_private *priv) { //struct net_device *dev = data; //struct lbs_private *priv = dev->ml_priv; //wait_queue_t wait; int shouldsleep; u8 resp_idx; //lbs_deb_enter(LBS_DEB_THREAD); //init_waitqueue_entry(&wait, current); do{ /*lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n", priv->currenttxskb, priv->dnld_sent); */ /*add_wait_queue(&priv->waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irq(&priv->driver_lock); if (kthread_should_stop()) shouldsleep = 0; */ if (priv->surpriseremoved) shouldsleep = 1; /* We need to wait until we're _told_ to die */ else if (priv->psstate == PS_STATE_SLEEP) shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */ else if (priv->cmd_timed_out) shouldsleep = 0; /* Command timed out. Recover */ else if (!priv->fw_ready) shouldsleep = 1; /* Firmware not ready. We're waiting for it */ else if (priv->dnld_sent) shouldsleep = 1; /* Something is en route to the device already */ //else if (priv->tx_pending_len > 0) // shouldsleep = 0; /* We've a packet to send */ else if (priv->resp_len[priv->resp_idx]) shouldsleep = 0; /* We have a command response */ else if (priv->cur_cmd) shouldsleep = 1; /* Can't send a command; one already running */ else if (!list_empty(&priv->cmdpendingq)) shouldsleep = 0; /* We have a command to send */ /* else if (__kfifo_len(priv->event_fifo)) shouldsleep = 0; */ /* We have an event to process */ else shouldsleep = 1; /* No command */ if (shouldsleep) { /*lbs_deb_thread("sleeping, connect_status %d, " "psmode %d, psstate %d\n", priv->connect_status, priv->psmode, priv->psstate);*/ //spin_unlock_irq(&priv->driver_lock); //schedule(); break; //HelloX: This break clause might be added by the modifier,to giveup execute. //Should remove this clause when implement this thread under HelloX. } /*else spin_unlock_irq(&priv->driver_lock);*/ /*lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n", priv->currenttxskb, priv->dnld_sent);*/ /*set_current_state(TASK_RUNNING); remove_wait_queue(&priv->waitq, &wait);*/ //HelloX: Should reset the event status to non-signaling here,to achieve sychronization //purpose. /*lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n", priv->currenttxskb, priv->dnld_sent); if (kthread_should_stop()) { lbs_deb_thread("break from main thread\n"); break; }*/ if (priv->surpriseremoved) { lbs_deb_thread("adapter removed; waiting to die...\n"); continue; } /*lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n", priv->currenttxskb, priv->dnld_sent);*/ /* Process any pending command response */ //spin_lock_irq(&priv->driver_lock); resp_idx = priv->resp_idx; if (priv->resp_len[resp_idx]) { // spin_unlock_irq(&priv->driver_lock); lbs_process_command_response(priv, priv->resp_buf[resp_idx], priv->resp_len[resp_idx]); //spin_lock_irq(&priv->driver_lock); priv->resp_len[resp_idx] = 0; } //spin_unlock_irq(&priv->driver_lock); /* command timeout stuff */ if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; if (++priv->nr_retries > 0) { lbs_pr_info("Excessive timeouts submitting " "command 0x%04x\n", le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); priv->nr_retries = 0; /*if (priv->reset_card) priv->reset_card(priv);*/ } else { priv->cur_cmd = NULL; priv->dnld_sent = DNLD_RES_RECEIVED; lbs_pr_info("requeueing command 0x%04x due " "to timeout (#%d)\n", le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries); /* Stick it back at the _top_ of the pending queue for immediate resubmission */ list_add(&cmdnode->list, &priv->cmdpendingq); } } priv->cmd_timed_out = 0; /* Process hardware events, e.g. card removed, link lost */ //spin_lock_irq(&priv->driver_lock); /* while (__kfifo_len(priv->event_fifo)) { u32 event; __kfifo_get(priv->event_fifo,(unsigned char *)&event,sizeof(event)); //spin_unlock_irq(&priv->driver_lock); lbs_process_event(priv, event); //spin_lock_irq(&priv->driver_lock); } */ //spin_unlock_irq(&priv->driver_lock); if (!priv->fw_ready) continue; /* Check if we need to confirm Sleep Request received previously */ if (priv->psstate == PS_STATE_PRE_SLEEP && !priv->dnld_sent && !priv->cur_cmd) { if (priv->connect_status == LBS_CONNECTED) { /*lbs_deb_thread("pre-sleep, currenttxskb %p, " "dnld_sent %d, cur_cmd %p\n", priv->currenttxskb, priv->dnld_sent, priv->cur_cmd);*/ //lbs_ps_confirm_sleep(priv); lbs_pr_alert("ignore PS_SleepConfirm in " "non-connected state\n"); while(1){ if(priv->psstate != PS_STATE_PRE_SLEEP)//bug break; } } else { /* workaround for firmware sending * deauth/linkloss event immediately * after sleep request; remove this * after firmware fixes it */ priv->psstate = PS_STATE_AWAKE; lbs_pr_alert("ignore PS_SleepConfirm in " "non-connected state\n"); } } /* The PS state is changed during processing of Sleep Request * event above */ if ((priv->psstate == PS_STATE_SLEEP) || (priv->psstate == PS_STATE_PRE_SLEEP)) continue; /* Execute the next command */ if (!priv->dnld_sent && !priv->cur_cmd) lbs_execute_next_command(priv); /* Wake-up command waiters which can't sleep in * lbs_prepare_and_send_command */ /*if (!list_empty(&priv->cmdpendingq)) wake_up_all(&priv->cmd_pending);*/ #ifdef MASK_DEBUG //spin_lock_irq(&priv->driver_lock); if (!priv->dnld_sent && priv->tx_pending_len > 0) { int ret = priv->hw_host_to_card(priv, MVMS_DAT, priv->tx_pending_buf, priv->tx_pending_len); if (ret) { lbs_deb_tx("host_to_card failed %d\n", ret); priv->dnld_sent = DNLD_RES_RECEIVED; } priv->tx_pending_len = 0; /*if (!priv->currenttxskb) { //We can wake the queues immediately if we aren't // waiting for TX feedback if (priv->connect_status == LBS_CONNECTED) netif_wake_queue(priv->dev); if (priv->mesh_dev && priv->mesh_connect_status == LBS_CONNECTED) netif_wake_queue(priv->mesh_dev); }*/ } #endif //spin_unlock_irq(&priv->driver_lock); }while(0); //HelloX: Maybe modified by the previous author,should change to while(1) clause when //migrate to HelloX. //del_timer(&priv->command_timer); //wake_up_all(&priv->cmd_pending); //lbs_deb_leave("leave main thread!\n"); return 0; }
/** * @brief This function processes a received 802.11 packet and forwards it * to kernel/upper layer * * @param priv A pointer to wlan_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) { wlan_adapter *adapter = priv->adapter; int ret = 0; struct rx80211packethdr *p_rx_pkt; struct rxpd *prxpd; struct rx_radiotap_hdr radiotap_hdr; struct rx_radiotap_hdr *pradiotap_hdr; lbs_deb_enter(LBS_DEB_RX); p_rx_pkt = (struct rx80211packethdr *) skb->data; prxpd = &p_rx_pkt->rx_pd; // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received wit bad length\n"); priv->stats.rx_length_errors++; ret = 0; goto done; } /* * Check rxpd status and update 802.3 stat, */ if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { //lbs_deb_rx("rx err: frame received with bad status\n"); priv->stats.rx_errors++; } lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); /* create the exported radio header */ if(priv->adapter->monitormode == WLAN_MONITOR_OFF) { /* no radio header */ /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); } else { /* radiotap header */ radiotap_hdr.hdr.it_version = 0; /* XXX must check this value for pad */ radiotap_hdr.hdr.it_pad = 0; radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); /* unknown values */ radiotap_hdr.flags = 0; radiotap_hdr.chan_freq = 0; radiotap_hdr.chan_flags = 0; radiotap_hdr.antenna = 0; /* known values */ radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); /* XXX must check no carryout */ radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; radiotap_hdr.rx_flags = 0; if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); /* add space for the new radio header */ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) { lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__); } pradiotap_hdr = (struct rx_radiotap_hdr *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); } /* Take the data rate from the rxpd structure * only if the rate is auto */ if (adapter->auto_rate) adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate); wlan_compute_rssi(priv, prxpd); lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); priv->stats.rx_bytes += skb->len; priv->stats.rx_packets++; libertas_upload_rx_packet(priv, skb); ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; }
/** * @brief This function executes next command in command * pending queue. It will put fimware back to PS mode * if applicable. * * @param priv A pointer to wlan_private structure * @return 0 or -1 */ int libertas_execute_next_command(wlan_private * priv) { wlan_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmdnode = NULL; struct cmd_ds_command *cmdptr; unsigned long flags; int ret = 0; // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the // only caller to us is libertas_thread() and we get even when a // data packet is received lbs_deb_enter(LBS_DEB_THREAD); spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd) { lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n"); spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = -1; goto done; } if (!list_empty(&adapter->cmdpendingq)) { cmdnode = (struct cmd_ctrl_node *) adapter->cmdpendingq.next; } spin_unlock_irqrestore(&adapter->driver_lock, flags); if (cmdnode) { cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; if (is_command_allowed_in_ps(cmdptr->command)) { if ((adapter->psstate == PS_STATE_SLEEP) || (adapter->psstate == PS_STATE_PRE_SLEEP)) { lbs_deb_host( "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n", le16_to_cpu(cmdptr->command), adapter->psstate); ret = -1; goto done; } lbs_deb_host("EXEC_NEXT_CMD: OK to send command " "0x%04x in psstate %d\n", le16_to_cpu(cmdptr->command), adapter->psstate); } else if (adapter->psstate != PS_STATE_FULL_POWER) { /* * 1. Non-PS command: * Queue it. set needtowakeup to TRUE if current state * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS. * 2. PS command but not Exit_PS: * Ignore it. * 3. PS command Exit_PS: * Set needtowakeup to TRUE if current state is SLEEP, * otherwise send this command down to firmware * immediately. */ if (cmdptr->command != cpu_to_le16(CMD_802_11_PS_MODE)) { /* Prepare to send Exit PS, * this non PS command will be sent later */ if ((adapter->psstate == PS_STATE_SLEEP) || (adapter->psstate == PS_STATE_PRE_SLEEP) ) { /* w/ new scheme, it will not reach here. since it is blocked in main_thread. */ adapter->needtowakeup = 1; } else libertas_ps_wakeup(priv, 0); ret = 0; goto done; } else { /* * PS command. Ignore it if it is not Exit_PS. * otherwise send it down immediately. */ struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; lbs_deb_host( "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n", psm->action); if (psm->action != cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n"); list_del((struct list_head *)cmdnode); libertas_cleanup_and_insert_cmd(priv, cmdnode); ret = 0; goto done; } if ((adapter->psstate == PS_STATE_SLEEP) || (adapter->psstate == PS_STATE_PRE_SLEEP)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n"); list_del((struct list_head *)cmdnode); libertas_cleanup_and_insert_cmd(priv, cmdnode); adapter->needtowakeup = 1; ret = 0; goto done; } lbs_deb_host( "EXEC_NEXT_CMD: sending EXIT_PS\n"); } } list_del((struct list_head *)cmdnode); lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n", le16_to_cpu(cmdptr->command)); DownloadcommandToStation(priv, cmdnode); } else { /* * check if in power save mode, if yes, put the device back * to PS mode */ if ((adapter->psmode != WLAN802_11POWERMODECAM) && (adapter->psstate == PS_STATE_FULL_POWER) && (adapter->connect_status == LIBERTAS_CONNECTED)) { if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { /* check for valid WPA group keys */ if (adapter->wpa_mcast_key.len || adapter->wpa_unicast_key.len) { lbs_deb_host( "EXEC_NEXT_CMD: WPA enabled and GTK_SET" " go back to PS_SLEEP"); libertas_ps_sleep(priv, 0); } } else { lbs_deb_host( "EXEC_NEXT_CMD: cmdpendingq empty, " "go back to PS_SLEEP"); libertas_ps_sleep(priv, 0); } } } ret = 0; done: lbs_deb_leave(LBS_DEB_THREAD); return ret; }
int libertas_process_event(wlan_private * priv) { int ret = 0; wlan_adapter *adapter = priv->adapter; u32 eventcause; lbs_deb_enter(LBS_DEB_CMD); spin_lock_irq(&adapter->driver_lock); eventcause = adapter->eventcause; spin_unlock_irq(&adapter->driver_lock); lbs_deb_cmd("event cause 0x%x\n", eventcause); switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { case MACREG_INT_CODE_LINK_SENSED: lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n"); break; case MACREG_INT_CODE_DEAUTHENTICATED: lbs_deb_cmd("EVENT: deauthenticated\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_DISASSOCIATED: lbs_deb_cmd("EVENT: disassociated\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: lbs_deb_cmd("EVENT: link lost\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_PS_SLEEP: lbs_deb_cmd("EVENT: sleep\n"); /* handle unexpected PS SLEEP event */ if (adapter->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n"); break; } adapter->psstate = PS_STATE_PRE_SLEEP; libertas_ps_confirm_sleep(priv, (u16) adapter->psmode); break; case MACREG_INT_CODE_PS_AWAKE: lbs_deb_cmd("EVENT: awake\n"); /* handle unexpected PS AWAKE event */ if (adapter->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); break; } adapter->psstate = PS_STATE_AWAKE; if (adapter->needtowakeup) { /* * wait for the command processing to finish * before resuming sending * adapter->needtowakeup will be set to FALSE * in libertas_ps_wakeup() */ lbs_deb_cmd("waking up ...\n"); libertas_ps_wakeup(priv, 0); } break; case MACREG_INT_CODE_MIC_ERR_UNICAST: lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n"); handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); break; case MACREG_INT_CODE_MIC_ERR_MULTICAST: lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n"); handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); break; case MACREG_INT_CODE_MIB_CHANGED: case MACREG_INT_CODE_INIT_DONE: break; case MACREG_INT_CODE_ADHOC_BCN_LOST: lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: lbs_pr_alert("EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: lbs_pr_alert("EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: lbs_pr_alert("EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: lbs_pr_alert("EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: lbs_pr_alert("EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: /* Ignore spurious autostart events if autostart is disabled */ if (!priv->mesh_autostart_enabled) { lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; } lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); adapter->connect_status = LIBERTAS_CONNECTED; if (priv->mesh_open == 1) { netif_wake_queue(priv->mesh_dev); netif_carrier_on(priv->mesh_dev); } adapter->mode = IW_MODE_ADHOC; schedule_work(&priv->sync_channel); break; default: lbs_pr_alert("EVENT: unknown event id 0x%04x\n", eventcause >> SBI_EVENT_CAUSE_SHIFT); break; } spin_lock_irq(&adapter->driver_lock); adapter->eventcause = 0; spin_unlock_irq(&adapter->driver_lock); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; }