Exemplo n.º 1
0
/**
 *  @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;
}
Exemplo n.º 2
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);
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
/**
 *  @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;
}
Exemplo n.º 6
0
/**
 *  @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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
//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;
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
/**
 *  @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;
}
Exemplo n.º 11
0
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;
}