Ejemplo n.º 1
0
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	unsigned long flags;
	struct lbs_private *priv = dev->priv;
	struct txpd *txpd;
	char *p802x_hdr;
	uint16_t pkt_len;
	int ret;

	lbs_deb_enter(LBS_DEB_TX);

#if (ANDROID_POWER_SAVE == 1)

	if (priv->deepsleep == false)
		lbs_update_ps_timer();
	else
	{
		if (priv->wifi_ps_work_req == 0)
		{
			printk("Need to wakeup for xmit: ether_proto=%x.\n", skb->protocol);
			priv->wifi_ps_work_req = WIFI_PS_PRE_WAKE;
			/*
			 * If no netif_carrier_off, upper layer will try again,
			 * and this may cause tx timeout and trigger watchdog.
			 */
			netif_stop_queue(priv->dev);
			netif_carrier_off(priv->dev);
			queue_delayed_work(priv->work_thread, &priv->ps_work,
					   msecs_to_jiffies(5));
		}
		return NETDEV_TX_BUSY;
	}
#endif

	ret = NETDEV_TX_OK;

	/* We need to protect against the queues being restarted before
	   we get round to stopping them */
	spin_lock_irqsave(&priv->driver_lock, flags);

	if (priv->surpriseremoved)
		goto free;

	if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
		lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
		       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
		/* We'll never manage to send this one; drop it and return 'OK' */

		dev->stats.tx_dropped++;
		dev->stats.tx_errors++;
		goto free;
	}


	netif_stop_queue(priv->dev);

	if (priv->tx_pending_len) {
		/* This can happen if packets come in on the mesh and eth
		   device simultaneously -- there's no mutual exclusion on
		   hard_start_xmit() calls between devices. */
		lbs_deb_tx("Packet on %s while busy\n", dev->name);
		ret = NETDEV_TX_BUSY;
		goto unlock;
	}

	priv->tx_pending_len = -1;
	spin_unlock_irqrestore(&priv->driver_lock, flags);

	lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));

	txpd = (void *)priv->tx_pending_buf;
	memset(txpd, 0, sizeof(struct txpd));

	p802x_hdr = skb->data;
	pkt_len = skb->len;

    /* copy destination address from 802.3 header */
    memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);

	txpd->tx_packet_length = cpu_to_le16(pkt_len);
	txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));

	lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));

	lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length));

	memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length));

	spin_lock_irqsave(&priv->driver_lock, flags);
	priv->tx_pending_len = pkt_len + sizeof(struct txpd);

	lbs_deb_tx("%s lined up packet\n", __func__);

	dev->stats.tx_packets++;
	dev->stats.tx_bytes += skb->len;

	dev->trans_start = jiffies;

	if (priv->monitormode) {
		/* Keep the skb to echo it back once Tx feedback is
		   received from FW */
		skb_orphan(skb);

		/* Keep the skb around for when we get feedback */
		priv->currenttxskb = skb;
	} else {
 free:
		dev_kfree_skb_any(skb);
	}
 unlock:
	spin_unlock_irqrestore(&priv->driver_lock, flags);
	wake_up(&priv->waitq);

	lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
	return ret;
}
Ejemplo n.º 2
0
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
{
	uint16_t respcmd, curcmd;
	struct cmd_header *resp;
	int ret = 0;
	unsigned long flags;
	uint16_t result;

	lbs_deb_enter(LBS_DEB_HOST);

	mutex_lock(&priv->lock);
	spin_lock_irqsave(&priv->driver_lock, flags);

	if (!priv->cur_cmd) {
		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
		ret = -1;
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		goto done;
	}

	resp = (void *)data;
	curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
	respcmd = le16_to_cpu(resp->command);
	result = le16_to_cpu(resp->result);

	lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
		     respcmd, le16_to_cpu(resp->seqnum), len);
	lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);

	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
		netdev_info(priv->dev,
			    "Received CMD_RESP with invalid sequence %d (expected %d)\n",
			    le16_to_cpu(resp->seqnum),
			    le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		ret = -1;
		goto done;
	}
	if (respcmd != CMD_RET(curcmd) &&
	    respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
		netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n",
			    respcmd, curcmd);
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		ret = -1;
		goto done;
	}

	if (resp->result == cpu_to_le16(0x0004)) {
		/* 0x0004 means -EAGAIN. Drop the response, let it time out
		   and be resubmitted */
		netdev_info(priv->dev,
			    "Firmware returns DEFER to command %x. Will let it time out...\n",
			    le16_to_cpu(resp->command));
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		ret = -1;
		goto done;
	}

	/* Now we got response from FW, cancel the command timer */
	del_timer(&priv->command_timer);
	priv->cmd_timed_out = 0;

	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
		/* struct cmd_ds_802_11_ps_mode also contains
		 * the header
		 */
		struct cmd_ds_802_11_ps_mode *psmode = (void *)resp;
		u16 action = le16_to_cpu(psmode->action);

		lbs_deb_host(
		       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
		       result, action);

		if (result) {
			lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
				    result);
			/*
			 * We should not re-try enter-ps command in
			 * ad-hoc mode. It takes place in
			 * lbs_execute_next_command().
			 */
			if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
			    action == PS_MODE_ACTION_ENTER_PS)
				priv->psmode = LBS802_11POWERMODECAM;
		} else if (action == PS_MODE_ACTION_ENTER_PS) {
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_AWAKE;

			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
			if (priv->connect_status != LBS_CONNECTED) {
				/*
				 * When Deauth Event received before Enter_PS command
				 * response, We need to wake up the firmware.
				 */
				lbs_deb_host(
				       "disconnected, invoking lbs_ps_wakeup\n");

				spin_unlock_irqrestore(&priv->driver_lock, flags);
				mutex_unlock(&priv->lock);
				lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS,
						false);
				mutex_lock(&priv->lock);
				spin_lock_irqsave(&priv->driver_lock, flags);
			}
		} else if (action == PS_MODE_ACTION_EXIT_PS) {
			priv->needtowakeup = 0;
			priv->psstate = PS_STATE_FULL_POWER;
			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
		} else {
			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
		}

		__lbs_complete_command(priv, priv->cur_cmd, result);
		spin_unlock_irqrestore(&priv->driver_lock, flags);

		ret = 0;
		goto done;
	}

	/* If the command is not successful, cleanup and return failure */
	if ((result != 0 || !(respcmd & 0x8000))) {
		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
		       result, respcmd);
		/*
		 * Handling errors here
		 */
		switch (respcmd) {
		case CMD_RET(CMD_GET_HW_SPEC):
		case CMD_RET(CMD_802_11_RESET):
			lbs_deb_host("CMD_RESP: reset failed\n");
			break;

		}
		__lbs_complete_command(priv, priv->cur_cmd, result);
		spin_unlock_irqrestore(&priv->driver_lock, flags);

		ret = -1;
		goto done;
	}

	spin_unlock_irqrestore(&priv->driver_lock, flags);

	if (priv->cur_cmd && priv->cur_cmd->callback) {
		ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
				resp);
	}

	spin_lock_irqsave(&priv->driver_lock, flags);

	if (priv->cur_cmd) {
		/* Clean up and Put current command back to cmdfreeq */
		__lbs_complete_command(priv, priv->cur_cmd, result);
	}
	spin_unlock_irqrestore(&priv->driver_lock, flags);

done:
	mutex_unlock(&priv->lock);
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
Ejemplo n.º 3
0
static inline int handle_cmd_response(u16 respcmd,
				      struct cmd_ds_command *resp,
				      wlan_private *priv)
{
	int ret = 0;
	unsigned long flags;
	wlan_adapter *adapter = priv->adapter;

	lbs_deb_enter(LBS_DEB_HOST);

	switch (respcmd) {
	case CMD_RET(CMD_MAC_REG_ACCESS):
	case CMD_RET(CMD_BBP_REG_ACCESS):
	case CMD_RET(CMD_RF_REG_ACCESS):
		ret = wlan_ret_reg_access(priv, respcmd, resp);
		break;

	case CMD_RET(CMD_GET_HW_SPEC):
		ret = wlan_ret_get_hw_spec(priv, resp);
		break;

	case CMD_RET(CMD_802_11_SCAN):
		ret = libertas_ret_80211_scan(priv, resp);
		break;

	case CMD_RET(CMD_802_11_GET_LOG):
		ret = wlan_ret_get_log(priv, resp);
		break;

	case CMD_RET_802_11_ASSOCIATE:
	case CMD_RET(CMD_802_11_ASSOCIATE):
	case CMD_RET(CMD_802_11_REASSOCIATE):
		ret = libertas_ret_80211_associate(priv, resp);
		break;

	case CMD_RET(CMD_802_11_DISASSOCIATE):
	case CMD_RET(CMD_802_11_DEAUTHENTICATE):
		ret = libertas_ret_80211_disassociate(priv, resp);
		break;

	case CMD_RET(CMD_802_11_AD_HOC_START):
	case CMD_RET(CMD_802_11_AD_HOC_JOIN):
		ret = libertas_ret_80211_ad_hoc_start(priv, resp);
		break;

	case CMD_RET(CMD_802_11_GET_STAT):
		ret = wlan_ret_802_11_stat(priv, resp);
		break;

	case CMD_RET(CMD_802_11_SNMP_MIB):
		ret = wlan_ret_802_11_snmp_mib(priv, resp);
		break;

	case CMD_RET(CMD_802_11_RF_TX_POWER):
		ret = wlan_ret_802_11_rf_tx_power(priv, resp);
		break;

	case CMD_RET(CMD_802_11_SET_AFC):
	case CMD_RET(CMD_802_11_GET_AFC):
		spin_lock_irqsave(&adapter->driver_lock, flags);
		memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc,
			sizeof(struct cmd_ds_802_11_afc));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);

		break;

	case CMD_RET(CMD_MAC_MULTICAST_ADR):
	case CMD_RET(CMD_MAC_CONTROL):
	case CMD_RET(CMD_802_11_SET_WEP):
	case CMD_RET(CMD_802_11_RESET):
	case CMD_RET(CMD_802_11_AUTHENTICATE):
	case CMD_RET(CMD_802_11_RADIO_CONTROL):
	case CMD_RET(CMD_802_11_BEACON_STOP):
		break;

	case CMD_RET(CMD_802_11_ENABLE_RSN):
		ret = libertas_ret_802_11_enable_rsn(priv, resp);
		break;

	case CMD_RET(CMD_802_11_DATA_RATE):
		ret = wlan_ret_802_11_data_rate(priv, resp);
		break;
	case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
		ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
		break;
	case CMD_RET(CMD_802_11_RF_CHANNEL):
		ret = wlan_ret_802_11_rf_channel(priv, resp);
		break;

	case CMD_RET(CMD_802_11_RSSI):
		ret = wlan_ret_802_11_rssi(priv, resp);
		break;

	case CMD_RET(CMD_802_11_MAC_ADDRESS):
		ret = wlan_ret_802_11_mac_address(priv, resp);
		break;

	case CMD_RET(CMD_802_11_AD_HOC_STOP):
		ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
		break;

	case CMD_RET(CMD_802_11_KEY_MATERIAL):
		ret = wlan_ret_802_11_key_material(priv, resp);
		break;

	case CMD_RET(CMD_802_11_EEPROM_ACCESS):
		ret = wlan_ret_802_11_eeprom_access(priv, resp);
		break;

	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
		ret = libertas_ret_802_11d_domain_info(priv, resp);
		break;

	case CMD_RET(CMD_802_11_SLEEP_PARAMS):
		ret = wlan_ret_802_11_sleep_params(priv, resp);
		break;
	case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
		spin_lock_irqsave(&adapter->driver_lock, flags);
		*((u16 *) adapter->cur_cmd->pdata_buf) =
		    le16_to_cpu(resp->params.inactivity_timeout.timeout);
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;

	case CMD_RET(CMD_802_11_TPC_CFG):
		spin_lock_irqsave(&adapter->driver_lock, flags);
		memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg,
			sizeof(struct cmd_ds_802_11_tpc_cfg));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
	case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
		spin_lock_irqsave(&adapter->driver_lock, flags);
		memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio,
			sizeof(struct cmd_ds_802_11_led_ctrl));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
	case CMD_RET(CMD_802_11_PWR_CFG):
		spin_lock_irqsave(&adapter->driver_lock, flags);
		memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
			sizeof(struct cmd_ds_802_11_pwr_cfg));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);

		break;

	case CMD_RET(CMD_GET_TSF):
		spin_lock_irqsave(&adapter->driver_lock, flags);
		memcpy(priv->adapter->cur_cmd->pdata_buf,
		       &resp->params.gettsf.tsfvalue, sizeof(u64));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
	case CMD_RET(CMD_BT_ACCESS):
		spin_lock_irqsave(&adapter->driver_lock, flags);
		if (adapter->cur_cmd->pdata_buf)
			memcpy(adapter->cur_cmd->pdata_buf,
			       &resp->params.bt.addr1, 2 * ETH_ALEN);
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
	case CMD_RET(CMD_FWT_ACCESS):
		spin_lock_irqsave(&adapter->driver_lock, flags);
		if (adapter->cur_cmd->pdata_buf)
			memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt,
			       sizeof(resp->params.fwt));
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		break;
	case CMD_RET(CMD_MESH_ACCESS):
		if (adapter->cur_cmd->pdata_buf)
			memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh,
			       sizeof(resp->params.mesh));
		break;
	default:
		lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
			    resp->command);
		break;
	}
	lbs_deb_leave(LBS_DEB_HOST);
	return ret;
}
Ejemplo n.º 4
0
static void __exit lbs_exit_module(void)
{
	lbs_deb_enter(LBS_DEB_MAIN);
	lbs_debugfs_remove();
	lbs_deb_leave(LBS_DEB_MAIN);
}
Ejemplo n.º 5
0
/**
 * lbs_add_card - adds the card. It will probe the
 * card, allocate the lbs_priv and initialize the device.
 *
 * @card:	A pointer to card
 * @dmdev:	A pointer to &struct device
 * returns:	A pointer to &struct lbs_private structure
 */
struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
{
	struct net_device *dev;
	struct wireless_dev *wdev;
	struct lbs_private *priv = NULL;

	lbs_deb_enter(LBS_DEB_MAIN);

	/* Allocate an Ethernet device and register it */
	wdev = lbs_cfg_alloc(dmdev);
	if (IS_ERR(wdev)) {
		pr_err("cfg80211 init failed\n");
		goto done;
	}

	wdev->iftype = NL80211_IFTYPE_STATION;
	priv = wdev_priv(wdev);
	priv->wdev = wdev;

	if (lbs_init_adapter(priv)) {
		pr_err("failed to initialize adapter structure\n");
		goto err_wdev;
	}

	dev = alloc_netdev(0, "wlan%d", ether_setup);
	if (!dev) {
		dev_err(dmdev, "no memory for network device instance\n");
		goto err_adapter;
	}

	dev->ieee80211_ptr = wdev;
	dev->ml_priv = priv;
	SET_NETDEV_DEV(dev, dmdev);
	wdev->netdev = dev;
	priv->dev = dev;

 	dev->netdev_ops = &lbs_netdev_ops;
	dev->watchdog_timeo = 5 * HZ;
	dev->ethtool_ops = &lbs_ethtool_ops;
	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;

	priv->card = card;

	strcpy(dev->name, "wlan%d");

	lbs_deb_thread("Starting main thread...\n");
	init_waitqueue_head(&priv->waitq);
	priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
	if (IS_ERR(priv->main_thread)) {
		lbs_deb_thread("Error creating main thread.\n");
		goto err_ndev;
	}

	priv->work_thread = create_singlethread_workqueue("lbs_worker");
	INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);

	priv->wol_criteria = EHS_REMOVE_WAKEUP;
	priv->wol_gpio = 0xff;
	priv->wol_gap = 20;
	priv->ehs_remove_supported = true;

	goto done;

 err_ndev:
	free_netdev(dev);

 err_adapter:
	lbs_free_adapter(priv);

 err_wdev:
	lbs_cfg_free(priv);

	priv = NULL;

done:
	lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv);
	return priv;
}
Ejemplo n.º 6
0
static int lbs_init_adapter(struct lbs_private *priv)
{
	size_t bufsize;
	int i, ret = 0;
	static u8 gnet_bss_desc[MAX_NETWORK_COUNT * sizeof(struct bss_descriptor)];

	lbs_deb_enter("enter lbs_init_adapter\n");
	/* Allocate buffer to store the BSSID list */
	bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
	/*priv->networks = kzalloc(bufsize, GFP_KERNEL);
	if (!priv->networks) {
		lbs_pr_err("Out of memory allocating beacons\n");
		ret = -1;
		goto out;
	}*/
	priv->networks=(struct bss_descriptor *)gnet_bss_desc;
	memset(priv->networks,0,bufsize);

	/* Initialize scan result lists */
	INIT_LIST_HEAD(&priv->network_free_list);//Initialize scan related list and objects.
	INIT_LIST_HEAD(&priv->network_list);
	//Link all bss descriptors into free list.
	for (i = 0; i < MAX_NETWORK_COUNT; i++) {
		list_add_tail(&priv->networks[i].list,
			      &priv->network_free_list);
	}

	memset(priv->current_addr, 0xff, ETH_ALEN);
	priv->connect_status = LBS_DISCONNECTED;
	priv->mesh_connect_status = LBS_DISCONNECTED;
	priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
	priv->mode = IW_MODE_INFRA;
	priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
	priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
	priv->radio_on = 1;
	priv->enablehwauto = 1;
	priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
	priv->psmode = LBS802_11POWERMODECAM;
	priv->psstate = PS_STATE_FULL_POWER;
	//mutex_init(&priv->lock);

	/*setup_timer(&priv->command_timer, command_timer_fn,
		(unsigned long)priv);*/

	INIT_LIST_HEAD(&priv->cmdfreeq);
	INIT_LIST_HEAD(&priv->cmdpendingq);

	/*spin_lock_init(&priv->driver_lock);
	init_waitqueue_head(&priv->cmd_pending);*/

	/* Allocate the command buffers */
	if (lbs_allocate_cmd_buffer(priv)) {
		lbs_pr_err("Out of memory allocating command buffers\n");
		ret = -ENOMEM;
		goto out;
	}
	priv->resp_idx = 0;
	priv->resp_len[0] = 0; //Contains the response from hardware.

	/* Create the event FIFO */
	/*priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL);
	if (IS_ERR(priv->event_fifo)) {
		lbs_pr_err("Out of memory allocating event FIFO buffer\n");
		ret = -ENOMEM;
		goto out;
	}*/

out:
	lbs_deb_leave_args("leave lbs_init_adapter(ret=%d)\n", ret);

	return ret;
}
Ejemplo n.º 7
0
/**
 *  @brief This function checks if chan txpwr is learned from AP/IBSS
 *  @param chan                 chan number
 *  @param parsed_region_chan   pointer to parsed_region_chan_11d
 *  @return 	                0
*/
static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
				 countryinfo,
				 u8 band,
				 struct parsed_region_chan_11d *
				 parsed_region_chan)
{
	u8 nr_subband, nrchan;
	u8 lastchan, firstchan;
	u8 region;
	u8 curchan = 0;

	u8 idx = 0;		/*chan index in parsed_region_chan */

	u8 j, i;

	lbs_deb_enter(LBS_DEB_11D);

	/*validation Rules:
	   1. valid region Code
	   2. First Chan increment
	   3. channel range no overlap
	   4. channel is valid?
	   5. channel is supported by region?
	   6. Others
	 */

	lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);

	if ((*(countryinfo->countrycode)) == 0
	    || (countryinfo->len <= COUNTRY_CODE_LEN)) {
		/* No region Info or Wrong region info: treat as No 11D info */
		goto done;
	}

	/*Step1: check region_code */
	parsed_region_chan->region = region =
	    lbs_region_2_code(countryinfo->countrycode);

	lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
	lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
		COUNTRY_CODE_LEN);

	parsed_region_chan->band = band;

	memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
	       COUNTRY_CODE_LEN);

	nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
	    sizeof(struct ieeetypes_subbandset);

	for (j = 0, lastchan = 0; j < nr_subband; j++) {

		if (countryinfo->subband[j].firstchan <= lastchan) {
			/*Step2&3. Check First Chan Num increment and no overlap */
			lbs_deb_11d("chan %d>%d, overlap\n",
			       countryinfo->subband[j].firstchan, lastchan);
			continue;
		}

		firstchan = countryinfo->subband[j].firstchan;
		nrchan = countryinfo->subband[j].nrchan;

		for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
			/*step4: channel is supported? */

			if (!lbs_get_chan_11d(firstchan, i, &curchan)) {
				/* Chan is not found in UN table */
				lbs_deb_11d("chan is not supported: %d \n", i);
				break;
			}

			lastchan = curchan;

			if (lbs_region_chan_supported_11d(region, curchan)) {
				/*step5: Check if curchan is supported by mrvl in region */
				parsed_region_chan->chanpwr[idx].chan = curchan;
				parsed_region_chan->chanpwr[idx].pwr =
				    countryinfo->subband[j].maxtxpwr;
				idx++;
			} else {
				/*not supported and ignore the chan */
				lbs_deb_11d(
				       "i %d, chan %d unsupported in region %x, band %d\n",
				       i, curchan, region, band);
			}
		}

		/*Step6: Add other checking if any */

	}

	parsed_region_chan->nr_chan = idx;

	lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
	lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
		2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);

done:
	lbs_deb_enter(LBS_DEB_11D);
	return 0;
}
Ejemplo n.º 8
0
static int wlan_cmd_802_11_set_wep(wlan_private * priv,
                                   struct cmd_ds_command *cmd,
                                   u32 cmd_act,
                                   void * pdata_buf)
{
	struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;
	struct assoc_request * assoc_req = pdata_buf;

	lbs_deb_enter(LBS_DEB_CMD);

	cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
	cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);

	if (cmd_act == CMD_ACT_ADD) {
		int i;

		if (!assoc_req) {
			lbs_deb_cmd("Invalid association request!");
			ret = -1;
			goto done;
		}

		wep->action = cpu_to_le16(CMD_ACT_ADD);

		/* default tx key index */
		wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
						  (u32)CMD_WEP_KEY_INDEX_MASK));

		/* Copy key types and material to host command structure */
		for (i = 0; i < 4; i++) {
			struct enc_key * pkey = &assoc_req->wep_keys[i];

			switch (pkey->len) {
			case KEY_LEN_WEP_40:
				wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
				break;
			case KEY_LEN_WEP_104:
				wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
				memmove(&wep->keymaterial[i], pkey->key,
				        pkey->len);
				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
				break;
			case 0:
				break;
			default:
				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
				       i, pkey->len);
				ret = -1;
				goto done;
				break;
			}
		}
	} else if (cmd_act == CMD_ACT_REMOVE) {
		/* ACT_REMOVE clears _all_ WEP keys */
		wep->action = cpu_to_le16(CMD_ACT_REMOVE);

		/* default tx key index */
		wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx &
						  (u32)CMD_WEP_KEY_INDEX_MASK));
		lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx);
	}

	ret = 0;

done:
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
0
static int if_usb_prog_firmware(wlan_private * priv)
{
	struct usb_card_rec *cardp = priv->card;
	int i = 0;
	static int reset_count = 10;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_USB);

	cardp->rinfo.priv = priv;

restart:
	if (if_usb_submit_rx_urb_fwload(priv) < 0) {
		lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
		ret = -1;
		goto done;
	}

	cardp->bootcmdresp = 0;
	do {
		int j = 0;
		i++;
		/* Issue Boot command = 1, Boot from Download-FW */
		if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
		/* wait for command response */
		do {
			j++;
			msleep_interruptible(100);
		} while (cardp->bootcmdresp == 0 && j < 10);
	} while (cardp->bootcmdresp == 0 && i < 5);

	if (cardp->bootcmdresp == 0) {
		if (--reset_count >= 0) {
			libertas_do_reset(priv);
			goto restart;
		}
		return -1;
	}

	i = 0;
	priv->adapter->fw_ready = 0;

	cardp->totalbytes = 0;
	cardp->fwlastblksent = 0;
	cardp->CRC_OK = 1;
	cardp->fwdnldover = 0;
	cardp->fwseqnum = -1;
	cardp->totalbytes = 0;
	cardp->fwfinalblk = 0;

	if_prog_firmware(priv);

	do {
		lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n");
		i++;
		msleep_interruptible(100);
		if (priv->adapter->surpriseremoved || i >= 20)
			break;
	} while (!cardp->fwdnldover);

	if (!cardp->fwdnldover) {
		lbs_pr_info("failed to load fw, resetting device!\n");
		if (--reset_count >= 0) {
			libertas_do_reset(priv);
			goto restart;
		}

		lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
		ret = -1;
		goto done;
	}

	if_usb_submit_rx_urb(priv);

	/* Delay 200 ms to waiting for the FW ready */
	msleep_interruptible(200);

	priv->adapter->fw_ready = 1;

done:
	lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
	return ret;
}
Ejemplo n.º 11
0
/**
 *  @brief This function prepare the command before send to firmware.
 *
 *  @param priv		A pointer to wlan_private structure
 *  @param cmd_no	command number
 *  @param cmd_action	command action: GET or SET
 *  @param wait_option	wait option: wait response or not
 *  @param cmd_oid	cmd oid: treated as sub command
 *  @param pdata_buf	A pointer to informaion buffer
 *  @return 		0 or -1
 */
int libertas_prepare_and_send_command(wlan_private * priv,
			  u16 cmd_no,
			  u16 cmd_action,
			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
{
	int ret = 0;
	wlan_adapter *adapter = priv->adapter;
	struct cmd_ctrl_node *cmdnode;
	struct cmd_ds_command *cmdptr;
	unsigned long flags;

	lbs_deb_enter(LBS_DEB_HOST);

	if (!adapter) {
		lbs_deb_host("PREP_CMD: adapter is NULL\n");
		ret = -1;
		goto done;
	}

	if (adapter->surpriseremoved) {
		lbs_deb_host("PREP_CMD: card removed\n");
		ret = -1;
		goto done;
	}

	cmdnode = libertas_get_free_cmd_ctrl_node(priv);

	if (cmdnode == NULL) {
		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");

		/* Wake up main thread to execute next command */
		wake_up_interruptible(&priv->waitq);
		ret = -1;
		goto done;
	}

	libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);

	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;

	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);

	if (!cmdptr) {
		lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
		libertas_cleanup_and_insert_cmd(priv, cmdnode);
		ret = -1;
		goto done;
	}

	/* Set sequence number, command and INT option */
	adapter->seqnum++;
	cmdptr->seqnum = cpu_to_le16(adapter->seqnum);

	cmdptr->command = cpu_to_le16(cmd_no);
	cmdptr->result = 0;

	switch (cmd_no) {
	case CMD_GET_HW_SPEC:
		ret = wlan_cmd_hw_spec(priv, cmdptr);
		break;
	case CMD_802_11_PS_MODE:
		ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
		break;

	case CMD_802_11_SCAN:
		ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
		break;

	case CMD_MAC_CONTROL:
		ret = wlan_cmd_mac_control(priv, cmdptr);
		break;

	case CMD_802_11_ASSOCIATE:
	case CMD_802_11_REASSOCIATE:
		ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
		break;

	case CMD_802_11_DEAUTHENTICATE:
		ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
		break;

	case CMD_802_11_SET_WEP:
		ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
		break;

	case CMD_802_11_AD_HOC_START:
		ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
		break;
	case CMD_CODE_DNLD:
		break;

	case CMD_802_11_RESET:
		ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
		break;

	case CMD_802_11_GET_LOG:
		ret = wlan_cmd_802_11_get_log(priv, cmdptr);
		break;

	case CMD_802_11_AUTHENTICATE:
		ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
		break;

	case CMD_802_11_GET_STAT:
		ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
		break;

	case CMD_802_11_SNMP_MIB:
		ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
					       cmd_action, cmd_oid, pdata_buf);
		break;

	case CMD_MAC_REG_ACCESS:
	case CMD_BBP_REG_ACCESS:
	case CMD_RF_REG_ACCESS:
		ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
		break;

	case CMD_802_11_RF_CHANNEL:
		ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
						 cmd_action, pdata_buf);
		break;

	case CMD_802_11_RF_TX_POWER:
		ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
						  cmd_action, pdata_buf);
		break;

	case CMD_802_11_RADIO_CONTROL:
		ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
		break;

	case CMD_802_11_DATA_RATE:
		ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
		break;
	case CMD_802_11_RATE_ADAPT_RATESET:
		ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
							 cmdptr, cmd_action);
		break;

	case CMD_MAC_MULTICAST_ADR:
		ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
		break;

	case CMD_802_11_MONITOR_MODE:
		ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr,
				          cmd_action, pdata_buf);
		break;

	case CMD_802_11_AD_HOC_JOIN:
		ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
		break;

	case CMD_802_11_RSSI:
		ret = wlan_cmd_802_11_rssi(priv, cmdptr);
		break;

	case CMD_802_11_AD_HOC_STOP:
		ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
		break;

	case CMD_802_11_ENABLE_RSN:
		ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
				pdata_buf);
		break;

	case CMD_802_11_KEY_MATERIAL:
		ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action,
				cmd_oid, pdata_buf);
		break;

	case CMD_802_11_PAIRWISE_TSC:
		break;
	case CMD_802_11_GROUP_TSC:
		break;

	case CMD_802_11_MAC_ADDRESS:
		ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
		break;

	case CMD_802_11_EEPROM_ACCESS:
		ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
						    cmd_action, pdata_buf);
		break;

	case CMD_802_11_SET_AFC:
	case CMD_802_11_GET_AFC:

		cmdptr->command = cpu_to_le16(cmd_no);
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
					   S_DS_GEN);

		memmove(&cmdptr->params.afc,
			pdata_buf, sizeof(struct cmd_ds_802_11_afc));

		ret = 0;
		goto done;

	case CMD_802_11D_DOMAIN_INFO:
		ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
						   cmd_no, cmd_action);
		break;

	case CMD_802_11_SLEEP_PARAMS:
		ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
		break;
	case CMD_802_11_INACTIVITY_TIMEOUT:
		ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
							 cmd_action, pdata_buf);
		libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
		break;

	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
		cmdptr->size =
		    cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
				     S_DS_GEN);

		memmove(&cmdptr->params.tpccfg,
			pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));

		ret = 0;
		break;
	case CMD_802_11_LED_GPIO_CTRL:
		{
			struct mrvlietypes_ledgpio *gpio =
			    (struct mrvlietypes_ledgpio*)
			    cmdptr->params.ledgpio.data;

			memmove(&cmdptr->params.ledgpio,
				pdata_buf,
				sizeof(struct cmd_ds_802_11_led_ctrl));

			cmdptr->command =
			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);

#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
			cmdptr->size =
			    cpu_to_le16(gpio->header.len + S_DS_GEN +
					     ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
			gpio->header.len = cpu_to_le16(gpio->header.len);

			ret = 0;
			break;
		}
	case CMD_802_11_PWR_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
		cmdptr->size =
		    cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
				     S_DS_GEN);
		memmove(&cmdptr->params.pwrcfg, pdata_buf,
			sizeof(struct cmd_ds_802_11_pwr_cfg));

		ret = 0;
		break;
	case CMD_BT_ACCESS:
		ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
		break;

	case CMD_FWT_ACCESS:
		ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
		break;

	case CMD_MESH_ACCESS:
		ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
		break;

	case CMD_SET_BOOT2_VER:
		ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf);
		break;

	case CMD_GET_TSF:
		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
					   S_DS_GEN);
		ret = 0;
		break;
	default:
		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
		ret = -1;
		break;
	}

	/* return error, since the command preparation failed */
	if (ret != 0) {
		lbs_deb_host("PREP_CMD: command preparation failed\n");
		libertas_cleanup_and_insert_cmd(priv, cmdnode);
		ret = -1;
		goto done;
	}

	cmdnode->cmdwaitqwoken = 0;

	libertas_queue_cmd(adapter, cmdnode, 1);
	wake_up_interruptible(&priv->waitq);

	if (wait_option & CMD_OPTION_WAITFORRSP) {
		lbs_deb_host("PREP_CMD: wait for response\n");
		might_sleep();
		wait_event_interruptible(cmdnode->cmdwait_q,
					 cmdnode->cmdwaitqwoken);
	}

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (adapter->cur_cmd_retcode) {
		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
		       adapter->cur_cmd_retcode);
		adapter->cur_cmd_retcode = 0;
		ret = -1;
	}
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
Ejemplo n.º 12
0
/**
 *  @brief This function reads of the packet into the upload buff,
 *  wake up the main thread and initialise the Rx callack.
 *
 *  @param urb		pointer to struct urb
 *  @return 	   	N/A
 */
static void if_usb_receive(struct urb *urb)
{
	struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
	wlan_private *priv = rinfo->priv;
	struct sk_buff *skb = rinfo->skb;
	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;

	int recvlength = urb->actual_length;
	u8 *recvbuff = NULL;
	u32 recvtype;

	lbs_deb_enter(LBS_DEB_USB);

	if (recvlength) {
		if (urb->status) {
			lbs_deb_usbd(&cardp->udev->dev,
				    "URB status is failed\n");
			kfree_skb(skb);
			goto setup_for_next;
		}

		recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
		memcpy(&recvtype, recvbuff, sizeof(u32));
		lbs_deb_usbd(&cardp->udev->dev,
			    "Recv length = 0x%x\n", recvlength);
		lbs_deb_usbd(&cardp->udev->dev,
			    "Receive type = 0x%X\n", recvtype);
		recvtype = le32_to_cpu(recvtype);
		lbs_deb_usbd(&cardp->udev->dev,
			    "Receive type after = 0x%X\n", recvtype);
	} else if (urb->status)
		goto rx_exit;


	switch (recvtype) {
	case CMD_TYPE_DATA:
		process_cmdtypedata(recvlength, skb, cardp, priv);
		break;

	case CMD_TYPE_REQUEST:
		process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
		break;

	case CMD_TYPE_INDICATION:
		/* Event cause handling */
		spin_lock(&priv->adapter->driver_lock);
		cardp->usb_event_cause = le32_to_cpu(*(__le32 *) (recvbuff + MESSAGE_HEADER_LEN));
		lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n",
			    cardp->usb_event_cause);
		if (cardp->usb_event_cause & 0xffff0000) {
			libertas_send_tx_feedback(priv);
			spin_unlock(&priv->adapter->driver_lock);
			break;
		}
		cardp->usb_event_cause <<= 3;
		cardp->usb_int_cause |= his_cardevent;
		kfree_skb(skb);
		libertas_interrupt(priv->dev);
		spin_unlock(&priv->adapter->driver_lock);
		goto rx_exit;
	default:
		kfree_skb(skb);
		break;
	}

setup_for_next:
	if_usb_submit_rx_urb(priv);
rx_exit:
	lbs_deb_leave(LBS_DEB_USB);
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
0
int libertas_process_rx_command(wlan_private * priv)
{
	u16 respcmd;
	struct cmd_ds_command *resp;
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;
	ulong flags;
	u16 result;

	lbs_deb_enter(LBS_DEB_HOST);

	/* Now we got response from FW, cancel the command timer */
	del_timer(&adapter->command_timer);

	mutex_lock(&adapter->lock);
	spin_lock_irqsave(&adapter->driver_lock, flags);

	if (!adapter->cur_cmd) {
		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
		ret = -1;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		goto done;
	}
	resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);

	respcmd = le16_to_cpu(resp->command);
	result = le16_to_cpu(resp->result);

	lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
		respcmd, priv->upld_len, jiffies);
	lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr,
		    priv->upld_len);

	if (!(respcmd & 0x8000)) {
		lbs_deb_host("invalid response!\n");
		adapter->cur_cmd_retcode = -1;
		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
		adapter->nr_cmd_pending--;
		adapter->cur_cmd = NULL;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		ret = -1;
		goto done;
	}

	/* Store the response code to cur_cmd_retcode. */
	adapter->cur_cmd_retcode = result;;

	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
		struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
		u16 action = le16_to_cpu(psmode->action);

		lbs_deb_host(
		       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
		       result, action);

		if (result) {
			lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
				    result);
			/*
			 * We should not re-try enter-ps command in
			 * ad-hoc mode. It takes place in
			 * libertas_execute_next_command().
			 */
			if (adapter->mode == IW_MODE_ADHOC &&
			    action == CMD_SUBCMD_ENTER_PS)
				adapter->psmode = WLAN802_11POWERMODECAM;
		} else if (action == CMD_SUBCMD_ENTER_PS) {
			adapter->needtowakeup = 0;
			adapter->psstate = PS_STATE_AWAKE;

			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
			if (adapter->connect_status != LIBERTAS_CONNECTED) {
				/*
				 * When Deauth Event received before Enter_PS command
				 * response, We need to wake up the firmware.
				 */
				lbs_deb_host(
				       "disconnected, invoking libertas_ps_wakeup\n");

				spin_unlock_irqrestore(&adapter->driver_lock, flags);
				mutex_unlock(&adapter->lock);
				libertas_ps_wakeup(priv, 0);
				mutex_lock(&adapter->lock);
				spin_lock_irqsave(&adapter->driver_lock, flags);
			}
		} else if (action == CMD_SUBCMD_EXIT_PS) {
			adapter->needtowakeup = 0;
			adapter->psstate = PS_STATE_FULL_POWER;
			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
		} else {
			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
		}

		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
		adapter->nr_cmd_pending--;
		adapter->cur_cmd = NULL;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);

		ret = 0;
		goto done;
	}

	if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
		/* Copy the response back to response buffer */
		memcpy(adapter->cur_cmd->pdata_buf, resp,
		       le16_to_cpu(resp->size));
		adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
	}

	/* If the command is not successful, cleanup and return failure */
	if ((result != 0 || !(respcmd & 0x8000))) {
		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
		       result, respcmd);
		/*
		 * Handling errors here
		 */
		switch (respcmd) {
		case CMD_RET(CMD_GET_HW_SPEC):
		case CMD_RET(CMD_802_11_RESET):
			lbs_deb_host("CMD_RESP: reset failed\n");
			break;

		}

		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
		adapter->nr_cmd_pending--;
		adapter->cur_cmd = NULL;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);

		ret = -1;
		goto done;
	}

	spin_unlock_irqrestore(&adapter->driver_lock, flags);

	ret = handle_cmd_response(respcmd, resp, priv);

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (adapter->cur_cmd) {
		/* Clean up and Put current command back to cmdfreeq */
		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
		adapter->nr_cmd_pending--;
		WARN_ON(adapter->nr_cmd_pending > 128);
		adapter->cur_cmd = NULL;
	}
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

done:
	mutex_unlock(&adapter->lock);
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
Ejemplo n.º 15
0
static inline int handle_cmd_response(struct lbs_private *priv,
				      struct cmd_header *cmd_response)
{
	struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
	int ret = 0;
	unsigned long flags;
	uint16_t respcmd = le16_to_cpu(resp->command);

	lbs_deb_enter(LBS_DEB_HOST);

	switch (respcmd) {
	case CMD_RET(CMD_MAC_REG_ACCESS):
	case CMD_RET(CMD_BBP_REG_ACCESS):
	case CMD_RET(CMD_RF_REG_ACCESS):
		ret = lbs_ret_reg_access(priv, respcmd, resp);
		break;

	case CMD_RET_802_11_ASSOCIATE:
	case CMD_RET(CMD_802_11_ASSOCIATE):
	case CMD_RET(CMD_802_11_REASSOCIATE):
		ret = lbs_ret_80211_associate(priv, resp);
		break;

	case CMD_RET(CMD_802_11_DISASSOCIATE):
	case CMD_RET(CMD_802_11_DEAUTHENTICATE):
		ret = lbs_ret_80211_disassociate(priv);
		break;

	case CMD_RET(CMD_802_11_AD_HOC_START):
	case CMD_RET(CMD_802_11_AD_HOC_JOIN):
		ret = lbs_ret_80211_ad_hoc_start(priv, resp);
		break;

	case CMD_RET(CMD_802_11_SNMP_MIB):
		ret = lbs_ret_802_11_snmp_mib(priv, resp);
		break;

	case CMD_RET(CMD_802_11_RF_TX_POWER):
		ret = lbs_ret_802_11_rf_tx_power(priv, resp);
		break;

	case CMD_RET(CMD_802_11_SET_AFC):
	case CMD_RET(CMD_802_11_GET_AFC):
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
			sizeof(struct cmd_ds_802_11_afc));
		spin_unlock_irqrestore(&priv->driver_lock, flags);

		break;

	case CMD_RET(CMD_802_11_RESET):
	case CMD_RET(CMD_802_11_AUTHENTICATE):
	case CMD_RET(CMD_802_11_BEACON_STOP):
		break;

	case CMD_RET(CMD_802_11_RSSI):
		ret = lbs_ret_802_11_rssi(priv, resp);
		break;

	case CMD_RET(CMD_802_11_AD_HOC_STOP):
		ret = lbs_ret_80211_ad_hoc_stop(priv);
		break;

	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
		ret = lbs_ret_802_11d_domain_info(resp);
		break;

	case CMD_RET(CMD_802_11_TPC_CFG):
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
			sizeof(struct cmd_ds_802_11_tpc_cfg));
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		break;
	case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio,
			sizeof(struct cmd_ds_802_11_led_ctrl));
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		break;

	case CMD_RET(CMD_GET_TSF):
		spin_lock_irqsave(&priv->driver_lock, flags);
		memcpy((void *)priv->cur_cmd->callback_arg,
		       &resp->params.gettsf.tsfvalue, sizeof(u64));
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		break;
	case CMD_RET(CMD_BT_ACCESS):
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (priv->cur_cmd->callback_arg)
			memcpy((void *)priv->cur_cmd->callback_arg,
			       &resp->params.bt.addr1, 2 * ETH_ALEN);
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		break;
	case CMD_RET(CMD_FWT_ACCESS):
		spin_lock_irqsave(&priv->driver_lock, flags);
		if (priv->cur_cmd->callback_arg)
			memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
			       sizeof(resp->params.fwt));
		spin_unlock_irqrestore(&priv->driver_lock, flags);
		break;
	case CMD_RET(CMD_802_11_BEACON_CTRL):
		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
		break;

	default:
		lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
			   le16_to_cpu(resp->command));
		break;
	}
	lbs_deb_leave(LBS_DEB_HOST);
	return ret;
}
Ejemplo n.º 16
0
static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
				    struct cmd_ds_command *cmd,
				    int cmd_action,
				    int cmd_oid, void *pdata_buf)
{
	struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
	wlan_adapter *adapter = priv->adapter;
	u8 ucTemp;

	lbs_deb_enter(LBS_DEB_CMD);

	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);

	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);

	switch (cmd_oid) {
	case OID_802_11_INFRASTRUCTURE_MODE:
	{
		u8 mode = (u8) (size_t) pdata_buf;
		pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
		pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
		pSNMPMIB->bufsize = sizeof(u8);
		if (mode == IW_MODE_ADHOC) {
			ucTemp = SNMP_MIB_VALUE_ADHOC;
		} else {
			/* Infra and Auto modes */
			ucTemp = SNMP_MIB_VALUE_INFRA;
		}

		memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));

		break;
	}

	case OID_802_11D_ENABLE:
		{
			u32 ulTemp;

			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);

			if (cmd_action == CMD_ACT_SET) {
				pSNMPMIB->querytype = CMD_ACT_SET;
				pSNMPMIB->bufsize = sizeof(u16);
				ulTemp = *(u32 *)pdata_buf;
				*((__le16 *)(pSNMPMIB->value)) =
				    cpu_to_le16((u16) ulTemp);
			}
			break;
		}

	case OID_802_11_FRAGMENTATION_THRESHOLD:
		{
			u32 ulTemp;

			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);

			if (cmd_action == CMD_ACT_GET) {
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
			} else if (cmd_action == CMD_ACT_SET) {
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
				ulTemp = *((u32 *) pdata_buf);
				*((__le16 *)(pSNMPMIB->value)) =
				    cpu_to_le16((u16) ulTemp);

			}

			break;
		}

	case OID_802_11_RTS_THRESHOLD:
		{

			u32 ulTemp;
			pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I);

			if (cmd_action == CMD_ACT_GET) {
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
			} else if (cmd_action == CMD_ACT_SET) {
				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
				ulTemp = *((u32 *)pdata_buf);
				*(__le16 *)(pSNMPMIB->value) =
				    cpu_to_le16((u16) ulTemp);

			}
			break;
		}
	case OID_802_11_TX_RETRYCOUNT:
		pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);

		if (cmd_action == CMD_ACT_GET) {
			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
		} else if (cmd_action == CMD_ACT_SET) {
			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
			*((__le16 *)(pSNMPMIB->value)) =
			    cpu_to_le16((u16) adapter->txretrycount);
		}

		break;
	default:
		break;
	}

	lbs_deb_cmd(
	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
	       le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));

	lbs_deb_cmd(
	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
	       le16_to_cpu(pSNMPMIB->bufsize),
	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}
Ejemplo n.º 17
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, char *buffer,u16 size)
{
	int ret = 0;
	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 };
	struct eth_packet *rx_ethpkt=&priv->rx_pkt;//我们要的以太网数据报
	lbs_deb_enter(LBS_DEB_RX);
	p_rx_pd = (struct rxpd *)buffer;//包的状态信息
	p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd +
		le32_to_cpu(p_rx_pd->pkt_ptr));//得到存放802.3的头信息的地址
		
//	lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", buffer,
	//	 min(size, 100));

	if (size < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
		lbs_deb_rx("rx err: frame received with bad length\n");
		ret = 0;
		goto done;
	}
#ifdef MASK_DEBUG
	lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n",
		size, (size_t)le32_to_cpu(p_rx_pd->pkt_ptr),
		size - (size_t)le32_to_cpu(p_rx_pd->pkt_ptr));

	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));
#endif
	if (memcmp(&p_rx_pkt->rfc1042_hdr,
		   rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {//这是RFC1042中定义的SNAP头信息,比较是否是rfc1042封装的mac帧
		/*
		 *  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.
		 */
		 //marvel芯片给出的数据为802.11LLC层的数据包格式,有snap头,现在将其更改为802.3的
		 //数据报格式,只要将802.11mac头信息中的源地址和目的地址复制到snap的右边即可,具体格式请参考相关标准的
		 //mac帧格式
		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));//找出存放802.3 MAC的起始位置

		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_pd;//用于重新更改skb->data的地址,后面使用的是skb_pull
	} 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_pd;
	}

	/* 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);//去掉前面的rxtp以及802.11mac

	rx_ethpkt->len=size-hdrchop;
	rx_ethpkt->data=(char *)((char *)buffer+hdrchop);//这就是我们数据的真正存放地址
	//dbg_netdata("rx network data",rx_ethpkt->data,rx_ethpkt->len);
	/* Take the data rate from the rxpd structure
	 * only if the rate is auto
	 */
#if 0
	if (priv->enablehwauto)
		priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);//记录下当前数据传输的速率

	lbs_compute_rssi(priv, p_rx_pd);//副产品,计算RSSI信号强度
#endif
	ret = 0;
done:
	lbs_deb_leave_args(LBS_DEB_RX, ret);
	return ret;
}
Ejemplo n.º 18
0
static int wlan_cmd_reg_access(wlan_private * priv,
			       struct cmd_ds_command *cmdptr,
			       u8 cmd_action, void *pdata_buf)
{
	struct wlan_offset_value *offval;

	lbs_deb_enter(LBS_DEB_CMD);

	offval = (struct wlan_offset_value *)pdata_buf;

	switch (cmdptr->command) {
	case CMD_MAC_REG_ACCESS:
		{
			struct cmd_ds_mac_reg_access *macreg;

			cmdptr->size =
			    cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
					+ S_DS_GEN);
			macreg =
			    (struct cmd_ds_mac_reg_access *)&cmdptr->params.
			    macreg;

			macreg->action = cpu_to_le16(cmd_action);
			macreg->offset = cpu_to_le16((u16) offval->offset);
			macreg->value = cpu_to_le32(offval->value);

			break;
		}

	case CMD_BBP_REG_ACCESS:
		{
			struct cmd_ds_bbp_reg_access *bbpreg;

			cmdptr->size =
			    cpu_to_le16(sizeof
					     (struct cmd_ds_bbp_reg_access)
					     + S_DS_GEN);
			bbpreg =
			    (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
			    bbpreg;

			bbpreg->action = cpu_to_le16(cmd_action);
			bbpreg->offset = cpu_to_le16((u16) offval->offset);
			bbpreg->value = (u8) offval->value;

			break;
		}

	case CMD_RF_REG_ACCESS:
		{
			struct cmd_ds_rf_reg_access *rfreg;

			cmdptr->size =
			    cpu_to_le16(sizeof
					     (struct cmd_ds_rf_reg_access) +
					     S_DS_GEN);
			rfreg =
			    (struct cmd_ds_rf_reg_access *)&cmdptr->params.
			    rfreg;

			rfreg->action = cpu_to_le16(cmd_action);
			rfreg->offset = cpu_to_le16((u16) offval->offset);
			rfreg->value = (u8) offval->value;

			break;
		}

	default:
		break;
	}

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}
Ejemplo n.º 19
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:
		printk("EVENT: link sensed\n");//掉线
		break;

	case MACREG_INT_CODE_DEAUTHENTICATED:
		printk("EVENT: deauthenticated\n");
		//lbs_mac_event_disconnected(priv);
		break;

	case MACREG_INT_CODE_DISASSOCIATED:
		printk("EVENT: disassociated\n");
		//lbs_mac_event_disconnected(priv);
		break;

	case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
		printk("EVENT: link lost\n");
		//lbs_mac_event_disconnected(priv);
		break;

	case MACREG_INT_CODE_PS_SLEEP:
		printk("EVENT: ps sleep\n");

		/* handle unexpected PS SLEEP event */
		if (priv->psstate == PS_STATE_FULL_POWER) {
			printk("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:
		printk("EVENT: host awake\n");
		//lbs_send_confirmwake(priv);
		break;

	case MACREG_INT_CODE_PS_AWAKE:
		printk("EVENT: ps awake\n");
		/* handle unexpected PS AWAKE event */
		if (priv->psstate == PS_STATE_FULL_POWER) {
			printk(
			       "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()
			 */
			printk("waking up ...\n");
			//lbs_ps_wakeup(priv, 0);
		}
		break;

	case MACREG_INT_CODE_MIC_ERR_UNICAST:
		printk("EVENT: UNICAST MIC ERROR\n");
		//handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
		break;

	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
		printk("EVENT: MULTICAST MIC ERROR\n");
		//handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
		break;

	case MACREG_INT_CODE_MIB_CHANGED:
		printk("EVENT: MIB CHANGED\n");
		break;
	case MACREG_INT_CODE_INIT_DONE:
		printk("EVENT: INIT DONE\n");
		break;
	case MACREG_INT_CODE_ADHOC_BCN_LOST:
		printk("EVENT: ADHOC beacon lost\n");
		break;
	case MACREG_INT_CODE_RSSI_LOW:
		printk("EVENT: rssi low\n");
		break;
	case MACREG_INT_CODE_SNR_LOW:
		printk("EVENT: snr low\n");
		break;
	case MACREG_INT_CODE_MAX_FAIL:
		printk("EVENT: max fail\n");
		break;
	case MACREG_INT_CODE_RSSI_HIGH:
		printk("EVENT: rssi high\n");
		break;
	case MACREG_INT_CODE_SNR_HIGH:
		printk("EVENT: snr high\n");
		break;
#ifdef MASK_DEBUG
	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;
#endif
	default:
		printk("EVENT: unknown event id %d\n", event);
		break;
	}

	lbs_deb_leave_args(LBS_DEB_CMD, ret);
	return ret;
}
Ejemplo n.º 20
0
/*
 * TODO: Fix the issue when DownloadcommandToStation is being called the
 * second time when the command times out. All the cmdptr->xxx are in little
 * endian and therefore all the comparissions will fail.
 * For now - we are not performing the endian conversion the second time - but
 * for PS and DEEP_SLEEP we need to worry
 */
static int DownloadcommandToStation(wlan_private * priv,
				    struct cmd_ctrl_node *cmdnode)
{
	unsigned long flags;
	struct cmd_ds_command *cmdptr;
	wlan_adapter *adapter = priv->adapter;
	int ret = -1;
	u16 cmdsize;
	u16 command;

	lbs_deb_enter(LBS_DEB_HOST);

	if (!adapter || !cmdnode) {
		lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n");
		goto done;
	}

	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;

	spin_lock_irqsave(&adapter->driver_lock, flags);
	if (!cmdptr || !cmdptr->size) {
		lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
		__libertas_cleanup_and_insert_cmd(priv, cmdnode);
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		goto done;
	}

	adapter->cur_cmd = cmdnode;
	adapter->cur_cmd_retcode = 0;
	spin_unlock_irqrestore(&adapter->driver_lock, flags);

	cmdsize = cmdptr->size;
	command = cpu_to_le16(cmdptr->command);

	lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
		    command, le16_to_cpu(cmdptr->size), jiffies);
	lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);

	cmdnode->cmdwaitqwoken = 0;
	cmdsize = cpu_to_le16(cmdsize);

	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);

	if (ret != 0) {
		lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
		spin_lock_irqsave(&adapter->driver_lock, flags);
		adapter->cur_cmd_retcode = ret;
		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
		adapter->nr_cmd_pending--;
		adapter->cur_cmd = NULL;
		spin_unlock_irqrestore(&adapter->driver_lock, flags);
		goto done;
	}

	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);

	/* Setup the timer after transmit command */
	if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
	    || command == CMD_802_11_ASSOCIATE)
		mod_timer(&adapter->command_timer, jiffies + (10*HZ));
	else
		mod_timer(&adapter->command_timer, jiffies + (5*HZ));

	ret = 0;

done:
	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
	return ret;
}
Ejemplo n.º 21
0
/**
 * lbs_add_mesh - add mshX interface
 *
 * @priv:	A pointer to the &struct lbs_private structure
 * returns:	0 if successful, -X otherwise
 */
static int lbs_add_mesh(struct lbs_private *priv)
{
	struct net_device *mesh_dev = NULL;
	struct wireless_dev *mesh_wdev;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_MESH);

	/* Allocate a virtual mesh device */
	mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
	if (!mesh_wdev) {
		lbs_deb_mesh("init mshX wireless device failed\n");
		ret = -ENOMEM;
		goto done;
	}

	mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
	if (!mesh_dev) {
		lbs_deb_mesh("init mshX device failed\n");
		ret = -ENOMEM;
		goto err_free_wdev;
	}

	mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
	mesh_wdev->wiphy = priv->wdev->wiphy;
	mesh_wdev->netdev = mesh_dev;

	mesh_dev->ml_priv = priv;
	mesh_dev->ieee80211_ptr = mesh_wdev;
	priv->mesh_dev = mesh_dev;

	mesh_dev->netdev_ops = &mesh_netdev_ops;
	mesh_dev->ethtool_ops = &lbs_ethtool_ops;
	memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);

	SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);

	mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
	/* Register virtual mesh interface */
	ret = register_netdev(mesh_dev);
	if (ret) {
		pr_err("cannot register mshX virtual interface\n");
		goto err_free_netdev;
	}

	ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
	if (ret)
		goto err_unregister;

	lbs_persist_config_init(mesh_dev);

	/* Everything successful */
	ret = 0;
	goto done;

err_unregister:
	unregister_netdev(mesh_dev);

err_free_netdev:
	free_netdev(mesh_dev);

err_free_wdev:
	kfree(mesh_wdev);

done:
	lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
	return ret;
}
Ejemplo n.º 22
0
/*
 * Check mesh FW version and appropriately send the mesh start
 * command
 */
int lbs_init_mesh(struct lbs_private *priv)
{
	struct net_device *dev = priv->dev;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_MESH);

	priv->mesh_connect_status = LBS_DISCONNECTED;

	/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
	/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
	/* 5.110.22 have mesh command with 0xa3 command id */
	/* 10.0.0.p0 FW brings in mesh config command with different id */
	/* Check FW version MSB and initialize mesh_fw_ver */
	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
		/* Enable mesh, if supported, and work out which TLV it uses.
		   0x100 + 291 is an unofficial value used in 5.110.20.pXX
		   0x100 + 37 is the official value used in 5.110.21.pXX
		   but we check them in that order because 20.pXX doesn't
		   give an error -- it just silently fails. */

		/* 5.110.20.pXX firmware will fail the command if the channel
		   doesn't match the existing channel. But only if the TLV
		   is correct. If the channel is wrong, _BOTH_ versions will
		   give an error to 0x100+291, and allow 0x100+37 to succeed.
		   It's just that 5.110.20.pXX will not have done anything
		   useful */

		priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
				    priv->channel)) {
			priv->mesh_tlv = TLV_TYPE_MESH_ID;
			if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
					    priv->channel))
				priv->mesh_tlv = 0;
		}
	} else
	if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
		(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
		/* 10.0.0.pXX new firmwares should succeed with TLV
		 * 0x100+37; Do not invoke command with old TLV.
		 */
		priv->mesh_tlv = TLV_TYPE_MESH_ID;
		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
				    priv->channel))
			priv->mesh_tlv = 0;
	}


	if (priv->mesh_tlv) {
		sprintf(priv->mesh_ssid, "mesh");
		priv->mesh_ssid_len = 4;

		lbs_add_mesh(priv);

		if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
			netdev_err(dev, "cannot register lbs_mesh attribute\n");

		ret = 1;
	}

	lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
	return ret;
}
Ejemplo n.º 23
0
/**
 *  lbs_thread - handles the major jobs in the LBS driver.
 *  It handles all events generated by firmware, RX data received
 *  from firmware and TX data sent from kernel.
 *
 *  @data:	A pointer to &lbs_thread structure
 *  returns:	0
 */
static int lbs_thread(void *data)
{
	struct net_device *dev = data;
	struct lbs_private *priv = dev->ml_priv;
	wait_queue_t wait;

	lbs_deb_enter(LBS_DEB_THREAD);

	init_waitqueue_entry(&wait, current);

	for (;;) {
		int shouldsleep;
		u8 resp_idx;

		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;	/* Bye */
		else 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) &&
					!(priv->wakeup_dev_required))
			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();
		} 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);

		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);

		/* Process hardware events, e.g. card removed, link lost */
		spin_lock_irq(&priv->driver_lock);
		while (kfifo_len(&priv->event_fifo)) {
			u32 event;

			if (kfifo_out(&priv->event_fifo,
				(unsigned char *) &event, sizeof(event)) !=
				sizeof(event))
					break;
			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->wakeup_dev_required) {
			lbs_deb_thread("Waking up device...\n");
			/* Wake up device */
			if (priv->exit_deep_sleep(priv))
				lbs_deb_thread("Wakeup device failed\n");
			continue;
		}

		/* command timeout stuff */
		if (priv->cmd_timed_out && priv->cur_cmd) {
			struct cmd_ctrl_node *cmdnode = priv->cur_cmd;

			netdev_info(dev, "Timeout submitting command 0x%04x\n",
				    le16_to_cpu(cmdnode->cmdbuf->command));
			lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
			if (priv->reset_card)
				priv->reset_card(priv);
		}
		priv->cmd_timed_out = 0;

		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);
			} else {
				/* workaround for firmware sending
				 * deauth/linkloss event immediately
				 * after sleep request; remove this
				 * after firmware fixes it
				 */
				priv->psstate = PS_STATE_AWAKE;
				netdev_alert(dev,
					     "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;

		if (priv->is_deep_sleep)
			continue;

		/* Execute the next command */
		if (!priv->dnld_sent && !priv->cur_cmd)
			lbs_execute_next_command(priv);

		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 &&
				    netif_running(priv->mesh_dev))
					netif_wake_queue(priv->mesh_dev);
			}
		}
		spin_unlock_irq(&priv->driver_lock);
	}

	del_timer(&priv->command_timer);
	del_timer(&priv->auto_deepsleep_timer);

	lbs_deb_leave(LBS_DEB_THREAD);
	return 0;
}
Ejemplo n.º 24
0
/**
 *  @brief This function processes received 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
 */
int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
{
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;

	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);

	if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
		return process_rxed_802_11_packet(priv, skb);

	p_rx_pkt = (struct rxpackethdr *) skb->data;
	p_rx_pd = &p_rx_pkt->rx_pd;
	if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
		SET_MESH_FRAME(skb);
	else
		UNSET_MESH_FRAME(skb);

	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");
		priv->stats.rx_length_errors++;
		ret = 0;
		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");
		priv->stats.rx_errors++;
		ret = 0;
		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 (adapter->auto_rate)
		adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate);

	wlan_compute_rssi(priv, p_rx_pd);

	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;
}
Ejemplo n.º 25
0
int lbs_process_event(struct lbs_private *priv, u32 event)
{
	int ret = 0;
	struct cmd_header cmd;

	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, false);
		break;

	case MACREG_INT_CODE_DISASSOCIATED:
		lbs_deb_cmd("EVENT: disassociated\n");
		lbs_mac_event_disconnected(priv, false);
		break;

	case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
		lbs_deb_cmd("EVENT: link lost\n");
		lbs_mac_event_disconnected(priv, true);
		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, ignoring PS_SLEEP\n");
			break;
		}
		if (!list_empty(&priv->cmdpendingq)) {
			lbs_deb_cmd("EVENT: commands in queue, do not 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");
		if (priv->reset_deep_sleep_wakeup)
			priv->reset_deep_sleep_wakeup(priv);
		priv->is_deep_sleep = 0;
		lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
				sizeof(cmd));
		priv->is_host_sleep_activated = 0;
		wake_up_interruptible(&priv->host_sleep_q);
		break;

	case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
		if (priv->reset_deep_sleep_wakeup)
			priv->reset_deep_sleep_wakeup(priv);
		lbs_deb_cmd("EVENT: ds awake\n");
		priv->is_deep_sleep = 0;
		priv->wakeup_dev_required = 0;
		wake_up_interruptible(&priv->ds_awake_q);
		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_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
		}
		break;

	case MACREG_INT_CODE_MIC_ERR_UNICAST:
		lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
		lbs_send_mic_failureevent(priv, event);
		break;

	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
		lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
		lbs_send_mic_failureevent(priv, event);
		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:
		netdev_alert(priv->dev, "EVENT: rssi low\n");
		break;
	case MACREG_INT_CODE_SNR_LOW:
		netdev_alert(priv->dev, "EVENT: snr low\n");
		break;
	case MACREG_INT_CODE_MAX_FAIL:
		netdev_alert(priv->dev, "EVENT: max fail\n");
		break;
	case MACREG_INT_CODE_RSSI_HIGH:
		netdev_alert(priv->dev, "EVENT: rssi high\n");
		break;
	case MACREG_INT_CODE_SNR_HIGH:
		netdev_alert(priv->dev, "EVENT: snr high\n");
		break;

	case MACREG_INT_CODE_MESH_AUTO_STARTED:
		/* Ignore spurious autostart events */
		netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n");
		break;

	default:
		netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event);
		break;
	}

	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}
Ejemplo n.º 26
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;
}
Ejemplo n.º 27
0
static inline void if_cs_disable_ints(struct if_cs_card *card)
{
	lbs_deb_enter(LBS_DEB_CS);
	if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
}
Ejemplo n.º 28
0
static int wlan_ret_get_hw_spec(wlan_private * priv,
				struct cmd_ds_command *resp)
{
	u32 i;
	struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
	wlan_adapter *adapter = priv->adapter;
	int ret = 0;
	DECLARE_MAC_BUF(mac);

	lbs_deb_enter(LBS_DEB_CMD);

	adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);

	memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4);

	lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
		    adapter->fwreleasenumber[2], adapter->fwreleasenumber[1],
		    adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]);
	lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
		    print_mac(mac, hwspec->permanentaddr));
	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
	       hwspec->hwifversion, hwspec->version);

	/* Clamp region code to 8-bit since FW spec indicates that it should
	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
	 * returns non-zero high 8 bits here.
	 */
	adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF;

	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
		/* use the region code to search for the index */
		if (adapter->regioncode == libertas_region_code_to_index[i]) {
			break;
		}
	}

	/* if it's unidentified region code, use the default (USA) */
	if (i >= MRVDRV_MAX_REGION_CODE) {
		adapter->regioncode = 0x10;
		lbs_pr_info("unidentified region code; using the default (USA)\n");
	}

	if (adapter->current_addr[0] == 0xff)
		memmove(adapter->current_addr, hwspec->permanentaddr, ETH_ALEN);

	memcpy(priv->dev->dev_addr, adapter->current_addr, ETH_ALEN);
	if (priv->mesh_dev)
		memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);

	if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
		ret = -1;
		goto done;
	}

	if (libertas_set_universaltable(priv, 0)) {
		ret = -1;
		goto done;
	}

done:
	lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}