Exemplo n.º 1
0
/**
 *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
 *  @param priv       pointer to struct lbs_private
 *  @param cmd        pointer to cmd buffer
 *  @param cmdno      cmd ID
 *  @param cmdOption  cmd action
 *  @return 	      0
*/
int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
				 struct cmd_ds_command *cmd, u16 cmdno,
				 u16 cmdoption)
{
	struct cmd_ds_802_11d_domain_info *pdomaininfo =
	    &cmd->params.domaininfo;
	struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
	u8 nr_subband = priv->domainreg.nr_subband;

	lbs_deb_enter(LBS_DEB_11D);

	lbs_deb_11d("nr_subband=%x\n", nr_subband);

	cmd->command = cpu_to_le16(cmdno);
	pdomaininfo->action = cpu_to_le16(cmdoption);
	if (cmdoption == CMD_ACT_GET) {
		cmd->size =
		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
		lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
			le16_to_cpu(cmd->size));
		goto done;
	}

	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
	memcpy(domain->countrycode, priv->domainreg.countrycode,
	       sizeof(domain->countrycode));

	domain->header.len =
	    cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
			     sizeof(domain->countrycode));

	if (nr_subband) {
		memcpy(domain->subband, priv->domainreg.subband,
		       nr_subband * sizeof(struct ieeetypes_subbandset));

		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
					     le16_to_cpu(domain->header.len) +
					     sizeof(struct mrvlietypesheader) +
					     S_DS_GEN);
	} else {
		cmd->size =
		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
	}

	lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));

done:
	lbs_deb_enter(LBS_DEB_11D);
	return 0;
}
Exemplo n.º 2
0
static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
				  struct cmd_ds_command *resp)
{
	wlan_adapter *adapter = priv->adapter;
	struct wlan_ioctl_regrdwr *pbuf;
	pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;

	lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
	       le16_to_cpu(resp->params.rdeeprom.bytecount));
	if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
		pbuf->NOB = 0;
		lbs_deb_cmd("EEPROM read length too big\n");
		return -1;
	}
	pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
	if (pbuf->NOB > 0) {

		memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
		       le16_to_cpu(resp->params.rdeeprom.bytecount));
		lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
			le16_to_cpu(resp->params.rdeeprom.bytecount));
	}
	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}
Exemplo n.º 3
0
int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
			       u16 cmd_action, void *pdata_buf)
{
	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);

	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
		sizeof(struct cmd_header));
	cmd->result = 0;
	bt_access->action = cpu_to_le16(cmd_action);

	switch (cmd_action) {
	case CMD_ACT_BT_ACCESS_ADD:
		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
			bt_access->addr1, 6);
		break;
	case CMD_ACT_BT_ACCESS_DEL:
		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
			bt_access->addr1, 6);
		break;
	case CMD_ACT_BT_ACCESS_LIST:
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
	case CMD_ACT_BT_ACCESS_RESET:
		break;
	case CMD_ACT_BT_ACCESS_SET_INVERT:
		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
		break;
	case CMD_ACT_BT_ACCESS_GET_INVERT:
		break;
	default:
		break;
	}
	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}
Exemplo n.º 4
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.º 5
0
static int wlan_ret_802_11_data_rate(wlan_private * priv,
				     struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
	wlan_adapter *adapter = priv->adapter;

	lbs_deb_enter(LBS_DEB_CMD);

	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
		sizeof(struct cmd_ds_802_11_data_rate));

	/* FIXME: get actual rates FW can do if this command actually returns
	 * all data rates supported.
	 */
	adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]);
	lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate);

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}
Exemplo n.º 6
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 	                TRUE; FALSE
*/
static u8 wlan_channel_known_11d(u8 chan,
			  struct parsed_region_chan_11d * parsed_region_chan)
{
	struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
	u8 nr_chan = parsed_region_chan->nr_chan;
	u8 i = 0;

	lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
		sizeof(struct chan_power_11d) * nr_chan);

	for (i = 0; i < nr_chan; i++) {
		if (chan == chanpwr[i].chan) {
			lbs_deb_11d("found chan %d\n", chan);
			return 1;
		}
	}

	lbs_deb_11d("chan %d not found\n", chan);
	return 0;
}
Exemplo n.º 7
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.º 8
0
/**
 *  @brief This function parses countryinfo from AP and download country info to FW
 *  @param priv    pointer to wlan_private
 *  @param resp    pointer to command response buffer
 *  @return 	   0; -1
 */
int libertas_ret_802_11d_domain_info(wlan_private * priv,
				 struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
	struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
	u16 action = le16_to_cpu(domaininfo->action);
	s16 ret = 0;
	u8 nr_subband = 0;

	lbs_deb_enter(LBS_DEB_11D);

	lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
		(int)le16_to_cpu(resp->size));

	nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
		      sizeof(struct ieeetypes_subbandset);

	lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);

	if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
		lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
		return -1;
	}

	switch (action) {
	case CMD_ACT_SET:	/*Proc Set action */
		break;

	case CMD_ACT_GET:
		break;
	default:
		lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
		ret = -1;
		break;
	}

	lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
	return ret;
}
Exemplo n.º 9
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.º 10
0
static int wlan_cmd_802_11_mac_address(wlan_private * priv,
				       struct cmd_ds_command *cmd,
				       u16 cmd_action)
{
	wlan_adapter *adapter = priv->adapter;

	lbs_deb_enter(LBS_DEB_CMD);
	cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
			     S_DS_GEN);
	cmd->result = 0;

	cmd->params.macadd.action = cpu_to_le16(cmd_action);

	if (cmd_action == CMD_ACT_SET) {
		memcpy(cmd->params.macadd.macadd,
		       adapter->current_addr, ETH_ALEN);
		lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6);
	}

	lbs_deb_leave(LBS_DEB_CMD);
	return 0;
}
Exemplo n.º 11
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.º 12
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) {
		lbs_pr_info("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) {
		lbs_pr_info("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 */
		lbs_pr_info("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 *psmode = (void *) &resp[1];
		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;
}
Exemplo n.º 13
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 =
	    wlan_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 (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
				/* Chan is not found in UN table */
				lbs_deb_11d("chan is not supported: %d \n", i);
				break;
			}

			lastchan = curchan;

			if (wlan_region_chan_supported_11d
			    (region, band, 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;
}
Exemplo n.º 14
0
Arquivo: tx.c Projeto: 020gzh/linux
/**
 * lbs_hard_start_xmit - checks the conditions and sends packet to IF
 * layer if everything is ok
 *
 * @skb:	A pointer to skb which includes TX packet
 * @dev:	A pointer to the &struct net_device
 * returns:	0 or -1
 */
netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	unsigned long flags;
	struct lbs_private *priv = dev->ml_priv;
	struct txpd *txpd;
	char *p802x_hdr;
	uint16_t pkt_len;
	netdev_tx_t ret = NETDEV_TX_OK;

	lbs_deb_enter(LBS_DEB_TX);

	/* 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->mesh_dev)
		netif_stop_queue(priv->mesh_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;

	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
		struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;

		/* set txpd fields from the radiotap header */
		txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));

		/* skip the radiotap header */
		p802x_hdr += sizeof(*rtap_hdr);
		pkt_len -= sizeof(*rtap_hdr);

		/* copy destination address from 802.11 header */
		memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
	} else {
		/* 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_mesh_set_txpd(priv, dev, 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;

	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
		/* 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;
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
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));
		
	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)
	{
		/*
		 *  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_pd;
	}
	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);

	rx_ethpkt->len  = size - hdrchop;
	rx_ethpkt->data = (char *)((char *)buffer+hdrchop);
	//Delivery the data into HelloX's kernel.
	//DeliveryPacket(rx_ethpkt->data,rx_ethpkt->len,NULL);

#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);
#endif
	ret = 0;
done:
	lbs_deb_leave_args(LBS_DEB_RX, ret);
	return ret;
}
Exemplo n.º 17
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)) {
		/*                                                         
                        */
		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;
	}

	/*                                                       */
	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 *psmode = (void *) &resp[1];
		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);
			/*
                                              
                                    
                                 
    */
			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) {
				/*
                                                         
                                                 
     */
				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 ((result != 0 || !(respcmd & 0x8000))) {
		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
		       result, respcmd);
		/*
                         
   */
		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) {
		/*                                                   */
		__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;
}
Exemplo n.º 18
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;
}
Exemplo n.º 19
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;
}
Exemplo 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;
}