* adding network config for olpc * adding libertas * config issue * quiet mode for bootloader

SVN-Revision: 9768
owl
Jens Muecke 2007-12-15 19:59:21 +00:00
parent b03f211098
commit 7eeb4e6f7f
41 changed files with 19037 additions and 12 deletions

56
package/libertas/Makefile Normal file
View File

@ -0,0 +1,56 @@
#
# Copyright (C) 2007 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# $Id: Makefile 8694 2007-09-08 19:55:42Z nbd $
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=kmod-libertas
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/libertas
SUBMENU:=Other modules
DEPENDS:=@TARGET_olpc +kmod-ieee80211
TITLE:=Marvell 88W8015 Wireless Driver
FILES:= \
$(PKG_BUILD_DIR)/libertas.$(LINUX_KMOD_SUFFIX) \
$(PKG_BUILD_DIR)/usb8xxx.$(LINUX_KMOD_SUFFIX)
AUTOLOAD:=$(call AutoLoad,20,libertas usb8xxx)
endef
define Download/firmware
URL:=http://dev.laptop.org/pub/firmware/libertas
FILE:=usb8388-5.220.11.p5.bin
MD5SUM=37cc814d5a475fcf8f8fbe89a9c5d546
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
SUBDIRS="$(PKG_BUILD_DIR)" \
CONFIG_LIBERTAS=m \
CONFIG_LIBERTAS_USB=m \
EXTRA_CFLAGS="-I$(PKG_BUILD_DIR) -include compat.h -I$(STAGING_DIR)/usr/include/mac80211" \
modules
endef
define KernelPackage/libertas/install
$(INSTALL_DIR) $(1)/lib/firmware
$(INSTALL_BIN) $(DL_DIR)/usb8388-5.220.11.p5.bin $(1)/lib/firmware/usb8388.bin
$(INSTALL_DATA) ./files/LICENSE $(1)/lib/firmware/
endef
$(eval $(call KernelPackage,libertas))
$(eval $(call Download,firmware))

View File

@ -0,0 +1,33 @@
Copyright (c) 2006, One Laptop per Child and Marvell Corporation.
All rights reserved.
Redistribution. Redistribution and use in binary form, without
modification, are permitted provided that the following conditions are
met:
* Redistributions must reproduce the above copyright notice and the
following disclaimer in the documentation and/or other materials
provided with the distribution.
* Neither the name of Marvell Corporation nor the names of its suppliers
may be used to endorse or promote products derived from this software
without specific prior written permission.
* No reverse engineering, decompilation, or disassembly of this software
is permitted.
* You may not use or attempt to use this software in conjunction with
any product that is offered by a third party as a replacement,
substitute or alternative to a Marvell Product where a Marvell Product
is defined as a proprietary wireless LAN embedded client solution of
Marvell or a Marvell Affiliate.
DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

700
package/libertas/src/11d.c Normal file
View File

@ -0,0 +1,700 @@
/**
* This file contains functions for 802.11D.
*/
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/wireless.h>
#include "host.h"
#include "decl.h"
#include "11d.h"
#include "dev.h"
#include "wext.h"
#define TX_PWR_DEFAULT 10
static struct region_code_mapping region_code_mapping[] = {
{"US ", 0x10}, /* US FCC */
{"CA ", 0x10}, /* IC Canada */
{"SG ", 0x10}, /* Singapore */
{"EU ", 0x30}, /* ETSI */
{"AU ", 0x30}, /* Australia */
{"KR ", 0x30}, /* Republic Of Korea */
{"ES ", 0x31}, /* Spain */
{"FR ", 0x32}, /* France */
{"JP ", 0x40}, /* Japan */
};
/* Following 2 structure defines the supported channels */
static struct chan_freq_power channel_freq_power_UN_BG[] = {
{1, 2412, TX_PWR_DEFAULT},
{2, 2417, TX_PWR_DEFAULT},
{3, 2422, TX_PWR_DEFAULT},
{4, 2427, TX_PWR_DEFAULT},
{5, 2432, TX_PWR_DEFAULT},
{6, 2437, TX_PWR_DEFAULT},
{7, 2442, TX_PWR_DEFAULT},
{8, 2447, TX_PWR_DEFAULT},
{9, 2452, TX_PWR_DEFAULT},
{10, 2457, TX_PWR_DEFAULT},
{11, 2462, TX_PWR_DEFAULT},
{12, 2467, TX_PWR_DEFAULT},
{13, 2472, TX_PWR_DEFAULT},
{14, 2484, TX_PWR_DEFAULT}
};
static u8 lbs_region_2_code(u8 *region)
{
u8 i;
for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
region[i] = toupper(region[i]);
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
if (!memcmp(region, region_code_mapping[i].region,
COUNTRY_CODE_LEN))
return (region_code_mapping[i].code);
}
/* default is US */
return (region_code_mapping[0].code);
}
static u8 *lbs_code_2_region(u8 code)
{
u8 i;
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
if (region_code_mapping[i].code == code)
return (region_code_mapping[i].region);
}
/* default is US */
return (region_code_mapping[0].region);
}
/**
* @brief This function finds the nrchan-th chan after the firstchan
* @param band band
* @param firstchan first channel number
* @param nrchan number of channels
* @return the nrchan-th chan number
*/
static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan)
/*find the nrchan-th chan after the firstchan*/
{
u8 i;
struct chan_freq_power *cfp;
u8 cfp_no;
cfp = channel_freq_power_UN_BG;
cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
for (i = 0; i < cfp_no; i++) {
if ((cfp + i)->channel == firstchan) {
lbs_deb_11d("firstchan found\n");
break;
}
}
if (i < cfp_no) {
/*if beyond the boundary */
if (i + nrchan < cfp_no) {
*chan = (cfp + i + nrchan)->channel;
return 1;
}
}
return 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 lbs_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;
}
u32 lbs_chan_2_freq(u8 chan, u8 band)
{
struct chan_freq_power *cf;
u16 i;
u32 freq = 0;
cf = channel_freq_power_UN_BG;
for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
if (chan == cf[i].channel)
freq = cf[i].freq;
}
return freq;
}
static int generate_domain_info_11d(struct parsed_region_chan_11d
*parsed_region_chan,
struct lbs_802_11d_domain_reg *domaininfo)
{
u8 nr_subband = 0;
u8 nr_chan = parsed_region_chan->nr_chan;
u8 nr_parsedchan = 0;
u8 firstchan = 0, nextchan = 0, maxpwr = 0;
u8 i, flag = 0;
memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
COUNTRY_CODE_LEN);
lbs_deb_11d("nrchan %d\n", nr_chan);
lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
sizeof(struct parsed_region_chan_11d));
for (i = 0; i < nr_chan; i++) {
if (!flag) {
flag = 1;
nextchan = firstchan =
parsed_region_chan->chanpwr[i].chan;
maxpwr = parsed_region_chan->chanpwr[i].pwr;
nr_parsedchan = 1;
continue;
}
if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
parsed_region_chan->chanpwr[i].pwr == maxpwr) {
nextchan++;
nr_parsedchan++;
} else {
domaininfo->subband[nr_subband].firstchan = firstchan;
domaininfo->subband[nr_subband].nrchan =
nr_parsedchan;
domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
nr_subband++;
nextchan = firstchan =
parsed_region_chan->chanpwr[i].chan;
maxpwr = parsed_region_chan->chanpwr[i].pwr;
}
}
if (flag) {
domaininfo->subband[nr_subband].firstchan = firstchan;
domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
nr_subband++;
}
domaininfo->nr_subband = nr_subband;
lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
COUNTRY_CODE_LEN + 1 +
sizeof(struct ieeetypes_subbandset) * nr_subband);
return 0;
}
/**
* @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
* @param region_chan pointer to struct region_channel
* @param *parsed_region_chan pointer to parsed_region_chan_11d
* @return N/A
*/
static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
struct parsed_region_chan_11d *
parsed_region_chan)
{
u8 i;
struct chan_freq_power *cfp;
if (region_chan == NULL) {
lbs_deb_11d("region_chan is NULL\n");
return;
}
cfp = region_chan->CFP;
if (cfp == NULL) {
lbs_deb_11d("cfp is NULL \n");
return;
}
parsed_region_chan->band = region_chan->band;
parsed_region_chan->region = region_chan->region;
memcpy(parsed_region_chan->countrycode,
lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
parsed_region_chan->band);
for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
parsed_region_chan->chanpwr[i].chan = cfp->channel;
parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
lbs_deb_11d("chan %d, pwr %d\n",
parsed_region_chan->chanpwr[i].chan,
parsed_region_chan->chanpwr[i].pwr);
}
parsed_region_chan->nr_chan = region_chan->nrcfp;
lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
return;
}
/**
* @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
* @param region region ID
* @param band band
* @param chan chan
* @return TRUE;FALSE
*/
static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan)
{
struct chan_freq_power *cfp;
int cfp_no;
u8 idx;
int ret = 0;
lbs_deb_enter(LBS_DEB_11D);
cfp = lbs_get_region_cfp_table(region, band, &cfp_no);
if (cfp == NULL)
return 0;
for (idx = 0; idx < cfp_no; idx++) {
if (chan == (cfp + idx)->channel) {
/* If Mrvl Chip Supported? */
if ((cfp + idx)->unsupported) {
ret = 0;
} else {
ret = 1;
}
goto done;
}
}
/*chan is not in the region table */
done:
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
return ret;
}
/**
* @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(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 (lbs_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;
}
/**
* @brief This function calculates the scan type for channels
* @param chan chan number
* @param parsed_region_chan pointer to parsed_region_chan_11d
* @return PASSIVE if chan is unknown; ACTIVE if chan is known
*/
u8 lbs_get_scan_type_11d(u8 chan,
struct parsed_region_chan_11d * parsed_region_chan)
{
u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
lbs_deb_enter(LBS_DEB_11D);
if (lbs_channel_known_11d(chan, parsed_region_chan)) {
lbs_deb_11d("found, do active scan\n");
scan_type = CMD_SCAN_TYPE_ACTIVE;
} else {
lbs_deb_11d("not found, do passive scan\n");
}
lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
return scan_type;
}
void lbs_init_11d(struct lbs_private *priv)
{
priv->enable11d = 0;
memset(&(priv->parsed_region_chan), 0,
sizeof(struct parsed_region_chan_11d));
return;
}
/**
* @brief This function sets DOMAIN INFO to FW
* @param priv pointer to struct lbs_private
* @return 0; -1
*/
static int set_domain_info_11d(struct lbs_private *priv)
{
int ret;
if (!priv->enable11d) {
lbs_deb_11d("dnld domain Info with 11d disabled\n");
return 0;
}
ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret)
lbs_deb_11d("fail to dnld domain info\n");
return ret;
}
/**
* @brief This function setups scan channels
* @param priv pointer to struct lbs_private
* @param band band
* @return 0
*/
int lbs_set_universaltable(struct lbs_private *priv, u8 band)
{
u16 size = sizeof(struct chan_freq_power);
u16 i = 0;
memset(priv->universal_channel, 0,
sizeof(priv->universal_channel));
priv->universal_channel[i].nrcfp =
sizeof(channel_freq_power_UN_BG) / size;
lbs_deb_11d("BG-band nrcfp %d\n",
priv->universal_channel[i].nrcfp);
priv->universal_channel[i].CFP = channel_freq_power_UN_BG;
priv->universal_channel[i].valid = 1;
priv->universal_channel[i].region = UNIVERSAL_REGION_CODE;
priv->universal_channel[i].band = band;
i++;
return 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;
}
/**
* @brief This function parses countryinfo from AP and download country info to FW
* @param priv pointer to struct lbs_private
* @param resp pointer to command response buffer
* @return 0; -1
*/
int lbs_ret_802_11d_domain_info(struct lbs_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;
}
/**
* @brief This function parses countryinfo from AP and download country info to FW
* @param priv pointer to struct lbs_private
* @return 0; -1
*/
int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
struct bss_descriptor * bss)
{
int ret;
lbs_deb_enter(LBS_DEB_11D);
if (priv->enable11d) {
memset(&priv->parsed_region_chan, 0,
sizeof(struct parsed_region_chan_11d));
ret = parse_domain_info_11d(&bss->countryinfo, 0,
&priv->parsed_region_chan);
if (ret == -1) {
lbs_deb_11d("error parsing domain_info from AP\n");
goto done;
}
memset(&priv->domainreg, 0,
sizeof(struct lbs_802_11d_domain_reg));
generate_domain_info_11d(&priv->parsed_region_chan,
&priv->domainreg);
ret = set_domain_info_11d(priv);
if (ret) {
lbs_deb_11d("error setting domain info\n");
goto done;
}
}
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
return ret;
}
/**
* @brief This function generates 11D info from user specified regioncode and download to FW
* @param priv pointer to struct lbs_private
* @return 0; -1
*/
int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
{
int ret;
struct region_channel *region_chan;
u8 j;
lbs_deb_enter(LBS_DEB_11D);
lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
if (priv->enable11d) {
/* update parsed_region_chan_11; dnld domaininf to FW */
for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
region_chan = &priv->region_channel[j];
lbs_deb_11d("%d region_chan->band %d\n", j,
region_chan->band);
if (!region_chan || !region_chan->valid
|| !region_chan->CFP)
continue;
if (region_chan->band != priv->curbssparams.band)
continue;
break;
}
if (j >= ARRAY_SIZE(priv->region_channel)) {
lbs_deb_11d("region_chan not found, band %d\n",
priv->curbssparams.band);
ret = -1;
goto done;
}
memset(&priv->parsed_region_chan, 0,
sizeof(struct parsed_region_chan_11d));
lbs_generate_parsed_region_chan_11d(region_chan,
&priv->
parsed_region_chan);
memset(&priv->domainreg, 0,
sizeof(struct lbs_802_11d_domain_reg));
generate_domain_info_11d(&priv->parsed_region_chan,
&priv->domainreg);
ret = set_domain_info_11d(priv);
if (ret) {
lbs_deb_11d("error setting domain info\n");
goto done;
}
}
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
return ret;
}

105
package/libertas/src/11d.h Normal file
View File

@ -0,0 +1,105 @@
/**
* This header file contains data structures and
* function declarations of 802.11d
*/
#ifndef _LBS_11D_
#define _LBS_11D_
#include "types.h"
#include "defs.h"
#define UNIVERSAL_REGION_CODE 0xff
/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
*/
#define MRVDRV_MAX_SUBBAND_802_11D 83
#define COUNTRY_CODE_LEN 3
#define MAX_NO_OF_CHAN 40
struct cmd_ds_command;
/** Data structure for Country IE*/
struct ieeetypes_subbandset {
u8 firstchan;
u8 nrchan;
u8 maxtxpwr;
} __attribute__ ((packed));
struct ieeetypes_countryinfoset {
u8 element_id;
u8 len;
u8 countrycode[COUNTRY_CODE_LEN];
struct ieeetypes_subbandset subband[1];
};
struct ieeetypes_countryinfofullset {
u8 element_id;
u8 len;
u8 countrycode[COUNTRY_CODE_LEN];
struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
} __attribute__ ((packed));
struct mrvlietypes_domainparamset {
struct mrvlietypesheader header;
u8 countrycode[COUNTRY_CODE_LEN];
struct ieeetypes_subbandset subband[1];
} __attribute__ ((packed));
struct cmd_ds_802_11d_domain_info {
__le16 action;
struct mrvlietypes_domainparamset domain;
} __attribute__ ((packed));
/** domain regulatory information */
struct lbs_802_11d_domain_reg {
/** country Code*/
u8 countrycode[COUNTRY_CODE_LEN];
/** No. of subband*/
u8 nr_subband;
struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
};
struct chan_power_11d {
u8 chan;
u8 pwr;
} __attribute__ ((packed));
struct parsed_region_chan_11d {
u8 band;
u8 region;
s8 countrycode[COUNTRY_CODE_LEN];
struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
u8 nr_chan;
} __attribute__ ((packed));
struct region_code_mapping {
u8 region[COUNTRY_CODE_LEN];
u8 code;
};
struct lbs_private;
u8 lbs_get_scan_type_11d(u8 chan,
struct parsed_region_chan_11d *parsed_region_chan);
u32 lbs_chan_2_freq(u8 chan, u8 band);
void lbs_init_11d(struct lbs_private *priv);
int lbs_set_universaltable(struct lbs_private *priv, u8 band);
int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
struct cmd_ds_command *cmd, u16 cmdno,
u16 cmdOption);
int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
struct cmd_ds_command *resp);
struct bss_descriptor;
int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
struct bss_descriptor * bss);
int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv);
#endif

62
package/libertas/src/:0 Normal file
View File

@ -0,0 +1,62 @@
#
# Copyright (C) 2007 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# $Id: Makefile 8694 2007-09-08 19:55:42Z nbd $
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=kmod-libertas
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/libertas
SUBMENU:=Other modules
DEPENDS:=@TARGET_olpc +kmod-mac80211
TITLE:=Marvell 88W8015 Wireless Driver
FILES:= \
$(PKG_BUILD_DIR)/libertas.$(LINUX_KMOD_SUFFIX) \
$(PKG_BUILD_DIR)/usb8xxx.$(LINUX_KMOD_SUFFIX)
# AUTOLOAD:=$(call AutoLoad,20,switch-core switch-robo switch-adm)
endef
define Download/firmware
URL:=http://dev.laptop.org/pub/firmware/libertas
FILE:=usb8388-5.220.11.p5.bin
MD5SUM=123
endef
define Download/firmware_license
URL:=http://dev.laptop.org/pub/firmware/libertas
FILE:=LICENSE
MD5SUM=123
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
SUBDIRS="$(PKG_BUILD_DIR)" \
CONFIG_LIBERTAS=m \
CONFIG_LIBERTAS_USB=m \
EXTRA_CFLAGS="-I$(PKG_BUILD_DIR) -include compat.h -I$(STAGING_DIR)/usr/include/mac80211" \
modules
endef
define KernelPackage/libertas/install
$(INSTALL_DIR) $(1)/lib/firmware
$(INSTALL_BIN) $(DL_DIR)/usb8388-5.220.11.p5.bin $(1)/lib/firmware/usb8388.bin
$(INSTALL_BIN) $(DL_DIR)/LICENSE $(1)/lib/firmware/
endef
$(eval $(call KernelPackage,libertas))
$(eval $(call Download,firmware))

View File

@ -0,0 +1,16 @@
Copyright (c) 2003-2006, Marvell International Ltd.
All Rights Reserved
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.

View File

@ -0,0 +1,15 @@
libertas-objs := main.o wext.o \
rx.o tx.o cmd.o \
cmdresp.o scan.o \
join.o 11d.o \
debugfs.o \
ethtool.o assoc.o
usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o
libertas_sdio-objs += if_sdio.o
obj-$(CONFIG_LIBERTAS) += libertas.o
obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o

229
package/libertas/src/README Normal file
View File

@ -0,0 +1,229 @@
================================================================================
README for USB8388
(c) Copyright © 2003-2006, Marvell International Ltd.
All Rights Reserved
This software file (the "File") is distributed by Marvell International
Ltd. under the terms of the GNU General Public License Version 2, June 1991
(the "License"). You may use, redistribute and/or modify this File in
accordance with the terms and conditions of the License, a copy of which
is available along with the File in the license.txt file or by writing to
the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
ARE EXPRESSLY DISCLAIMED. The License provides additional details about
this warranty disclaimer.
================================================================================
=====================
DRIVER LOADING
=====================
o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
o. Load driver by using the following command:
insmod usb8388.ko [fw_name=usb8388.bin]
=========================
ETHTOOL
=========================
Use the -i option to retrieve version information from the driver.
# ethtool -i eth0
driver: libertas
version: COMM-USB8388-318.p4
firmware-version: 5.110.7
bus-info:
Use the -e option to read the EEPROM contents of the card.
Usage:
ethtool -e ethX [raw on|off] [offset N] [length N]
-e retrieves and prints an EEPROM dump for the specified ethernet
device. When raw is enabled, then it dumps the raw EEPROM data
to stdout. The length and offset parameters allow dumping cer-
tain portions of the EEPROM. Default is to dump the entire EEP-
ROM.
# ethtool -e eth0 offset 0 length 16
Offset Values
------ ------
0x0000 38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
========================
DEBUGFS COMMANDS
========================
those commands are used via debugfs interface
===========
rdmac
rdbbp
rdrf
These commands are used to read the MAC, BBP and RF registers from the
card. These commands take one parameter that specifies the offset
location that is to be read. This parameter must be specified in
hexadecimal (its possible to preceed preceding the number with a "0x").
Path: /debugfs/libertas_wireless/ethX/registers/
Usage:
echo "0xa123" > rdmac ; cat rdmac
echo "0xa123" > rdbbp ; cat rdbbp
echo "0xa123" > rdrf ; cat rdrf
wrmac
wrbbp
wrrf
These commands are used to write the MAC, BBP and RF registers in the
card. These commands take two parameters that specify the offset
location and the value that is to be written. This parameters must
be specified in hexadecimal (its possible to preceed the number
with a "0x").
Usage:
echo "0xa123 0xaa" > wrmac
echo "0xa123 0xaa" > wrbbp
echo "0xa123 0xaa" > wrrf
sleepparams
This command is used to set the sleepclock configurations
Path: /debugfs/libertas_wireless/ethX/
Usage:
cat sleepparams: reads the current sleepclock configuration
echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
where:
p1 is Sleep clock error in ppm (0-65535)
p2 is Wakeup offset in usec (0-65535)
p3 is Clock stabilization time in usec (0-65535)
p4 is Control periodic calibration (0-2)
p5 is Control the use of external sleep clock (0-2)
p6 is reserved for debug (0-65535)
subscribed_events
The subscribed_events directory contains the interface for the
subscribed events API.
Path: /debugfs/libertas_wireless/ethX/subscribed_events/
Each event is represented by a filename. Each filename consists of the
following three fields:
Value Frequency Subscribed
To read the current values for a given event, do:
cat event
To set the current values, do:
echo "60 2 1" > event
Frequency field specifies the reporting frequency for this event.
If it is set to 0, then the event is reported only once, and then
automatically unsubscribed. If it is set to 1, then the event is
reported every time it occurs. If it is set to N, then the event is
reported every Nth time it occurs.
beacon_missed
Value field specifies the number of consecutive missing beacons which
triggers the LINK_LOSS event. This event is generated only once after
which the firmware resets its state. At initialization, the LINK_LOSS
event is subscribed by default. The default value of MissedBeacons is
60.
failure_count
Value field specifies the consecutive failure count threshold which
triggers the generation of the MAX_FAIL event. Once this event is
generated, the consecutive failure count is reset to 0.
At initialization, the MAX_FAIL event is NOT subscribed by
default.
high_rssi
This event is generated when the average received RSSI in beacons goes
above a threshold, specified by Value.
low_rssi
This event is generated when the average received RSSI in beacons goes
below a threshold, specified by Value.
high_snr
This event is generated when the average received SNR in beacons goes
above a threshold, specified by Value.
low_snr
This event is generated when the average received SNR in beacons goes
below a threshold, specified by Value.
extscan
This command is used to do a specific scan.
Path: /debugfs/libertas_wireless/ethX/
Usage: echo "SSID" > extscan
Example:
echo "LINKSYS-AP" > extscan
To see the results of use getscantable command.
getscantable
Display the current contents of the driver scan table (ie. get the
scan results).
Path: /debugfs/libertas_wireless/ethX/
Usage:
cat getscantable
setuserscan
Initiate a customized scan and retrieve the results
Path: /debugfs/libertas_wireless/ethX/
Usage:
echo "[ARGS]" > setuserscan
where [ARGS]:
bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
ssid="[SSID]" specify a SSID filter for the scan
keep=[0 or 1] keep the previous scan results (1), discard (0)
dur=[scan time] time to scan for each channel in milliseconds
type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
Any combination of the above arguments can be supplied on the command
line. If dur tokens are absent, the driver default setting will be used.
The bssid and ssid fields, if blank, will produce an unfiltered scan.
The type field will default to 3 (Any) and the keep field will default
to 0 (Discard).
Examples:
1) Perform a passive scan on all channels for 20 ms per channel:
echo "dur=20" > setuserscan
2) Perform an active scan for a specific SSID:
echo "ssid="TestAP"" > setuserscan
3) Scan all available channels (B/G, A bands) for a specific BSSID, keep
the current scan table intact, update existing or append new scan data:
echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
4) Scan for all infrastructure networks.
Keep the previous scan table intact. Update any duplicate BSSID/SSID
matches with the new scan data:
echo "type=1 keep=1" > setuserscan
All entries in the scan table (not just the new scan data when keep=1)
will be displayed upon completion by use of the getscantable ioctl.
==============================================================================

View File

@ -0,0 +1,766 @@
/* Copyright (C) 2006, Red Hat, Inc. */
#include <linux/bitops.h>
#include <net/ieee80211.h>
#include <linux/etherdevice.h>
#include "assoc.h"
#include "join.h"
#include "decl.h"
#include "hostcmd.h"
#include "host.h"
#include "cmd.h"
static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static int assoc_helper_essid(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
struct bss_descriptor * bss;
int channel = -1;
lbs_deb_enter(LBS_DEB_ASSOC);
/* FIXME: take channel into account when picking SSIDs if a channel
* is set.
*/
if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
channel = assoc_req->channel;
lbs_deb_assoc("SSID '%s' requested\n",
escape_essid(assoc_req->ssid, assoc_req->ssid_len));
if (assoc_req->mode == IW_MODE_INFRA) {
lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
assoc_req->ssid_len, 0);
bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
if (bss != NULL) {
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
ret = lbs_associate(priv, assoc_req);
} else {
lbs_deb_assoc("SSID not found; cannot associate\n");
}
} else if (assoc_req->mode == IW_MODE_ADHOC) {
/* Scan for the network, do not save previous results. Stale
* scan data will cause us to join a non-existant adhoc network
*/
lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
assoc_req->ssid_len, 1);
/* Search for the requested SSID in the scan table */
bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
if (bss != NULL) {
lbs_deb_assoc("SSID found, will join\n");
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
lbs_join_adhoc_network(priv, assoc_req);
} else {
/* else send START command */
lbs_deb_assoc("SSID not found, creating adhoc network\n");
memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
IW_ESSID_MAX_SIZE);
assoc_req->bss.ssid_len = assoc_req->ssid_len;
lbs_start_adhoc_network(priv, assoc_req);
}
}
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int assoc_helper_bssid(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
struct bss_descriptor * bss;
DECLARE_MAC_BUF(mac);
lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
print_mac(mac, assoc_req->bssid));
/* Search for index position in list for requested MAC */
bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
assoc_req->mode);
if (bss == NULL) {
lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
"cannot associate.\n", print_mac(mac, assoc_req->bssid));
goto out;
}
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
if (assoc_req->mode == IW_MODE_INFRA) {
ret = lbs_associate(priv, assoc_req);
lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
} else if (assoc_req->mode == IW_MODE_ADHOC) {
lbs_join_adhoc_network(priv, assoc_req);
}
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int assoc_helper_associate(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0, done = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
/* If we're given and 'any' BSSID, try associating based on SSID */
if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
if (compare_ether_addr(bssid_any, assoc_req->bssid)
&& compare_ether_addr(bssid_off, assoc_req->bssid)) {
ret = assoc_helper_bssid(priv, assoc_req);
done = 1;
}
}
if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
ret = assoc_helper_essid(priv, assoc_req);
}
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int assoc_helper_mode(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
if (assoc_req->mode == priv->mode)
goto done;
if (assoc_req->mode == IW_MODE_INFRA) {
if (priv->psstate != PS_STATE_FULL_POWER)
lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
priv->psmode = LBS802_11POWERMODECAM;
}
priv->mode = assoc_req->mode;
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_SNMP_MIB,
0, CMD_OPTION_WAITFORRSP,
OID_802_11_INFRASTRUCTURE_MODE,
/* Shoot me now */ (void *) (size_t) assoc_req->mode);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int update_channel(struct lbs_private *priv)
{
int ret;
/* the channel in f/w could be out of sync, get the current channel */
lbs_deb_enter(LBS_DEB_ASSOC);
ret = lbs_get_channel(priv);
if (ret > 0)
priv->curbssparams.channel = (u8) ret;
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
void lbs_sync_channel(struct work_struct *work)
{
struct lbs_private *priv = container_of(work, struct lbs_private,
sync_channel);
lbs_deb_enter(LBS_DEB_ASSOC);
if (update_channel(priv) != 0)
lbs_pr_info("Channel synchronization failed.");
lbs_deb_leave(LBS_DEB_ASSOC);
}
static int assoc_helper_channel(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
ret = update_channel(priv);
if (ret < 0) {
lbs_deb_assoc("ASSOC: channel: error getting channel.");
}
if (assoc_req->channel == priv->curbssparams.channel)
goto done;
if (priv->mesh_dev) {
/* Disconnect mesh while associating -- otherwise it
won't let us change channels */
lbs_mesh_config(priv, 0);
}
lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
priv->curbssparams.channel, assoc_req->channel);
ret = lbs_set_channel(priv, assoc_req->channel);
if (ret < 0)
lbs_deb_assoc("ASSOC: channel: error setting channel.");
/* FIXME: shouldn't need to grab the channel _again_ after setting
* it since the firmware is supposed to return the new channel, but
* whatever... */
ret = update_channel(priv);
if (ret < 0)
lbs_deb_assoc("ASSOC: channel: error getting channel.");
if (assoc_req->channel != priv->curbssparams.channel) {
lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
assoc_req->channel);
goto restore_mesh;
}
if ( assoc_req->secinfo.wep_enabled
&& (assoc_req->wep_keys[0].len
|| assoc_req->wep_keys[1].len
|| assoc_req->wep_keys[2].len
|| assoc_req->wep_keys[3].len)) {
/* Make sure WEP keys are re-sent to firmware */
set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
}
/* Must restart/rejoin adhoc networks after channel change */
set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
restore_mesh:
if (priv->mesh_dev)
lbs_mesh_config(priv, 1);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int assoc_helper_wep_keys(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int i;
int ret = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
/* Set or remove WEP keys */
if ( assoc_req->wep_keys[0].len
|| assoc_req->wep_keys[1].len
|| assoc_req->wep_keys[2].len
|| assoc_req->wep_keys[3].len) {
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_SET_WEP,
CMD_ACT_ADD,
CMD_OPTION_WAITFORRSP,
0, assoc_req);
} else {
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_SET_WEP,
CMD_ACT_REMOVE,
CMD_OPTION_WAITFORRSP,
0, NULL);
}
if (ret)
goto out;
/* enable/disable the MAC's WEP packet filter */
if (assoc_req->secinfo.wep_enabled)
priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
else
priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
ret = lbs_set_mac_packet_filter(priv);
if (ret)
goto out;
mutex_lock(&priv->lock);
/* Copy WEP keys into priv wep key fields */
for (i = 0; i < 4; i++) {
memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
sizeof(struct enc_key));
}
priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
mutex_unlock(&priv->lock);
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int assoc_helper_secinfo(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
u32 do_wpa;
u32 rsn = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
memcpy(&priv->secinfo, &assoc_req->secinfo,
sizeof(struct lbs_802_11_security));
ret = lbs_set_mac_packet_filter(priv);
if (ret)
goto out;
/* If RSN is already enabled, don't try to enable it again, since
* ENABLE_RSN resets internal state machines and will clobber the
* 4-way WPA handshake.
*/
/* Get RSN enabled/disabled */
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_ENABLE_RSN,
CMD_ACT_GET,
CMD_OPTION_WAITFORRSP,
0, &rsn);
if (ret) {
lbs_deb_assoc("Failed to get RSN status: %d", ret);
goto out;
}
/* Don't re-enable RSN if it's already enabled */
do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled);
if (do_wpa == rsn)
goto out;
/* Set RSN enabled/disabled */
rsn = do_wpa;
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_ENABLE_RSN,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP,
0, &rsn);
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int assoc_helper_wpa_keys(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
unsigned int flags = assoc_req->flags;
lbs_deb_enter(LBS_DEB_ASSOC);
/* Work around older firmware bug where WPA unicast and multicast
* keys must be set independently. Seen in SDIO parts with firmware
* version 5.0.11p0.
*/
if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_KEY_MATERIAL,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP,
0, assoc_req);
assoc_req->flags = flags;
}
if (ret)
goto out;
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_KEY_MATERIAL,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP,
0, assoc_req);
assoc_req->flags = flags;
}
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int assoc_helper_wpa_ie(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
priv->wpa_ie_len = assoc_req->wpa_ie_len;
} else {
memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
priv->wpa_ie_len = 0;
}
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
static int should_deauth_infrastructure(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
if (priv->connect_status != LBS_CONNECTED)
return 0;
if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
lbs_deb_assoc("Deauthenticating due to new SSID\n");
ret = 1;
goto out;
}
if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
lbs_deb_assoc("Deauthenticating due to new security\n");
ret = 1;
goto out;
}
}
if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
lbs_deb_assoc("Deauthenticating due to new BSSID\n");
ret = 1;
goto out;
}
if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
lbs_deb_assoc("Deauthenticating due to channel switch\n");
ret = 1;
goto out;
}
/* FIXME: deal with 'auto' mode somehow */
if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
if (assoc_req->mode != IW_MODE_INFRA) {
lbs_deb_assoc("Deauthenticating due to leaving "
"infra mode\n");
ret = 1;
goto out;
}
}
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return 0;
}
static int should_stop_adhoc(struct lbs_private *priv,
struct assoc_request * assoc_req)
{
lbs_deb_enter(LBS_DEB_ASSOC);
if (priv->connect_status != LBS_CONNECTED)
return 0;
if (lbs_ssid_cmp(priv->curbssparams.ssid,
priv->curbssparams.ssid_len,
assoc_req->ssid, assoc_req->ssid_len) != 0)
return 1;
/* FIXME: deal with 'auto' mode somehow */
if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
if (assoc_req->mode != IW_MODE_ADHOC)
return 1;
}
if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
if (assoc_req->channel != priv->curbssparams.channel)
return 1;
}
lbs_deb_leave(LBS_DEB_ASSOC);
return 0;
}
void lbs_association_worker(struct work_struct *work)
{
struct lbs_private *priv = container_of(work, struct lbs_private,
assoc_work.work);
struct assoc_request * assoc_req = NULL;
int ret = 0;
int find_any_ssid = 0;
DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_ASSOC);
mutex_lock(&priv->lock);
assoc_req = priv->pending_assoc_req;
priv->pending_assoc_req = NULL;
priv->in_progress_assoc_req = assoc_req;
mutex_unlock(&priv->lock);
if (!assoc_req)
goto done;
lbs_deb_assoc(
"Association Request:\n"
" flags: 0x%08lx\n"
" SSID: '%s'\n"
" chann: %d\n"
" band: %d\n"
" mode: %d\n"
" BSSID: %s\n"
" secinfo: %s%s%s\n"
" auth_mode: %d\n",
assoc_req->flags,
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
assoc_req->channel, assoc_req->band, assoc_req->mode,
print_mac(mac, assoc_req->bssid),
assoc_req->secinfo.WPAenabled ? " WPA" : "",
assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
assoc_req->secinfo.wep_enabled ? " WEP" : "",
assoc_req->secinfo.auth_mode);
/* If 'any' SSID was specified, find an SSID to associate with */
if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
&& !assoc_req->ssid_len)
find_any_ssid = 1;
/* But don't use 'any' SSID if there's a valid locked BSSID to use */
if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
if (compare_ether_addr(assoc_req->bssid, bssid_any)
&& compare_ether_addr(assoc_req->bssid, bssid_off))
find_any_ssid = 0;
}
if (find_any_ssid) {
u8 new_mode;
ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
&assoc_req->ssid_len, assoc_req->mode, &new_mode);
if (ret) {
lbs_deb_assoc("Could not find best network\n");
ret = -ENETUNREACH;
goto out;
}
/* Ensure we switch to the mode of the AP */
if (assoc_req->mode == IW_MODE_AUTO) {
set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
assoc_req->mode = new_mode;
}
}
/*
* Check if the attributes being changing require deauthentication
* from the currently associated infrastructure access point.
*/
if (priv->mode == IW_MODE_INFRA) {
if (should_deauth_infrastructure(priv, assoc_req)) {
ret = lbs_send_deauthentication(priv);
if (ret) {
lbs_deb_assoc("Deauthentication due to new "
"configuration request failed: %d\n",
ret);
}
}
} else if (priv->mode == IW_MODE_ADHOC) {
if (should_stop_adhoc(priv, assoc_req)) {
ret = lbs_stop_adhoc_network(priv);
if (ret) {
lbs_deb_assoc("Teardown of AdHoc network due to "
"new configuration request failed: %d\n",
ret);
}
}
}
/* Send the various configuration bits to the firmware */
if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
ret = assoc_helper_mode(priv, assoc_req);
if (ret)
goto out;
}
if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
ret = assoc_helper_channel(priv, assoc_req);
if (ret)
goto out;
}
if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
|| test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
ret = assoc_helper_wep_keys(priv, assoc_req);
if (ret)
goto out;
}
if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
ret = assoc_helper_secinfo(priv, assoc_req);
if (ret)
goto out;
}
if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
ret = assoc_helper_wpa_ie(priv, assoc_req);
if (ret)
goto out;
}
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
|| test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
ret = assoc_helper_wpa_keys(priv, assoc_req);
if (ret)
goto out;
}
/* SSID/BSSID should be the _last_ config option set, because they
* trigger the association attempt.
*/
if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
|| test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
int success = 1;
ret = assoc_helper_associate(priv, assoc_req);
if (ret) {
lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
ret);
success = 0;
}
if (priv->connect_status != LBS_CONNECTED) {
lbs_deb_assoc("ASSOC: association unsuccessful, "
"not connected\n");
success = 0;
}
if (success) {
lbs_deb_assoc("ASSOC: associated to '%s', %s\n",
escape_essid(priv->curbssparams.ssid,
priv->curbssparams.ssid_len),
print_mac(mac, priv->curbssparams.bssid));
lbs_prepare_and_send_command(priv,
CMD_802_11_RSSI,
0, CMD_OPTION_WAITFORRSP, 0, NULL);
lbs_prepare_and_send_command(priv,
CMD_802_11_GET_LOG,
0, CMD_OPTION_WAITFORRSP, 0, NULL);
} else {
ret = -1;
}
}
out:
if (ret) {
lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
ret);
}
mutex_lock(&priv->lock);
priv->in_progress_assoc_req = NULL;
mutex_unlock(&priv->lock);
kfree(assoc_req);
done:
lbs_deb_leave(LBS_DEB_ASSOC);
}
/*
* Caller MUST hold any necessary locks
*/
struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
{
struct assoc_request * assoc_req;
lbs_deb_enter(LBS_DEB_ASSOC);
if (!priv->pending_assoc_req) {
priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
GFP_KERNEL);
if (!priv->pending_assoc_req) {
lbs_pr_info("Not enough memory to allocate association"
" request!\n");
return NULL;
}
}
/* Copy current configuration attributes to the association request,
* but don't overwrite any that are already set.
*/
assoc_req = priv->pending_assoc_req;
if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
IW_ESSID_MAX_SIZE);
assoc_req->ssid_len = priv->curbssparams.ssid_len;
}
if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
assoc_req->channel = priv->curbssparams.channel;
if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
assoc_req->band = priv->curbssparams.band;
if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
assoc_req->mode = priv->mode;
if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
ETH_ALEN);
}
if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
int i;
for (i = 0; i < 4; i++) {
memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
sizeof(struct enc_key));
}
}
if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
sizeof(struct enc_key));
}
if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
sizeof(struct enc_key));
}
if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
memcpy(&assoc_req->secinfo, &priv->secinfo,
sizeof(struct lbs_802_11_security));
}
if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
MAX_WPA_IE_LEN);
assoc_req->wpa_ie_len = priv->wpa_ie_len;
}
lbs_deb_leave(LBS_DEB_ASSOC);
return assoc_req;
}

View File

@ -0,0 +1,12 @@
/* Copyright (C) 2006, Red Hat, Inc. */
#ifndef _LBS_ASSOC_H_
#define _LBS_ASSOC_H_
#include "dev.h"
void lbs_association_worker(struct work_struct *work);
struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
void lbs_sync_channel(struct work_struct *work);
#endif /* _LBS_ASSOC_H */

2233
package/libertas/src/cmd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
/* Copyright (C) 2007, Red Hat, Inc. */
#ifndef _LBS_CMD_H_
#define _LBS_CMD_H_
#include "hostcmd.h"
#include "dev.h"
#define lbs_cmd(priv, cmdnr, cmd, callback, callback_arg) \
__lbs_cmd(priv, cmdnr, &(cmd).hdr, sizeof(cmd), \
callback, callback_arg)
#define lbs_cmd_with_response(priv, cmdnr, cmd) \
__lbs_cmd(priv, cmdnr, &(cmd).hdr, sizeof(cmd), \
lbs_cmd_copyback, (unsigned long) &cmd)
int __lbs_cmd(struct lbs_private *priv, uint16_t command,
struct cmd_header *in_cmd, int in_cmd_size,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg);
int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
struct cmd_header *resp);
int lbs_update_hw_spec(struct lbs_private *priv);
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
struct cmd_ds_mesh_access *cmd);
int lbs_get_data_rate(struct lbs_private *priv);
int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
int lbs_get_channel(struct lbs_private *priv);
int lbs_set_channel(struct lbs_private *priv, u8 channel);
int lbs_mesh_config(struct lbs_private *priv, int enable);
#endif /* _LBS_CMD_H */

View File

@ -0,0 +1,897 @@
/**
* This file contains the handling of command
* responses as well as events generated by firmware.
*/
#include <linux/delay.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <net/iw_handler.h>
#include "host.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "join.h"
#include "wext.h"
/**
* @brief This function handles disconnect event. it
* reports disconnect to upper layer, clean tx/rx packets,
* reset link state etc.
*
* @param priv A pointer to struct lbs_private structure
* @return n/a
*/
void lbs_mac_event_disconnected(struct lbs_private *priv)
{
union iwreq_data wrqu;
if (priv->connect_status != LBS_CONNECTED)
return;
lbs_deb_enter(LBS_DEB_ASSOC);
memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
/*
* Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
* It causes problem in the Supplicant
*/
msleep_interruptible(1000);
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
/* Free Tx and Rx packets */
kfree_skb(priv->currenttxskb);
priv->currenttxskb = NULL;
/* report disconnect to upper layer */
netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev);
/* reset SNR/NF/RSSI values */
memset(priv->SNR, 0x00, sizeof(priv->SNR));
memset(priv->NF, 0x00, sizeof(priv->NF));
memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
priv->nextSNRNF = 0;
priv->numSNRNF = 0;
priv->connect_status = LBS_DISCONNECTED;
/* Clear out associated SSID and BSSID since connection is
* no longer valid.
*/
memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
priv->curbssparams.ssid_len = 0;
if (priv->psstate != PS_STATE_FULL_POWER) {
/* make firmware to exit PS mode */
lbs_deb_cmd("disconnected, so exit PS mode\n");
lbs_ps_wakeup(priv, 0);
}
lbs_deb_leave(LBS_DEB_CMD);
}
/**
* @brief This function handles MIC failure event.
*
* @param priv A pointer to struct lbs_private structure
* @para event the event id
* @return n/a
*/
static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
{
char buf[50];
lbs_deb_enter(LBS_DEB_CMD);
memset(buf, 0, sizeof(buf));
sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
strcat(buf, "unicast ");
} else {
strcat(buf, "multicast ");
}
lbs_send_iwevcustom_event(priv, buf);
lbs_deb_leave(LBS_DEB_CMD);
}
static int lbs_ret_reg_access(struct lbs_private *priv,
u16 type, struct cmd_ds_command *resp)
{
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
switch (type) {
case CMD_RET(CMD_MAC_REG_ACCESS):
{
struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
priv->offsetvalue.value = le32_to_cpu(reg->value);
break;
}
case CMD_RET(CMD_BBP_REG_ACCESS):
{
struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
priv->offsetvalue.value = reg->value;
break;
}
case CMD_RET(CMD_RF_REG_ACCESS):
{
struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
priv->offsetvalue.value = reg->value;
break;
}
default:
ret = -1;
}
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
static int lbs_ret_802_11_sleep_params(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
lbs_deb_enter(LBS_DEB_CMD);
lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
"extsleepclk 0x%x\n", le16_to_cpu(sp->error),
le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
sp->calcontrol, sp->externalsleepclk);
priv->sp.sp_error = le16_to_cpu(sp->error);
priv->sp.sp_offset = le16_to_cpu(sp->offset);
priv->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
priv->sp.sp_calcontrol = sp->calcontrol;
priv->sp.sp_extsleepclk = sp->externalsleepclk;
priv->sp.sp_reserved = le16_to_cpu(sp->reserved);
lbs_deb_enter(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_stat(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
lbs_deb_enter(LBS_DEB_CMD);
/* currently priv->wlan802_11Stat is unused
struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
// TODO Convert it to Big endian befor copy
memcpy(&priv->wlan802_11Stat,
p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
*/
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
u16 oid = le16_to_cpu(smib->oid);
u16 querytype = le16_to_cpu(smib->querytype);
lbs_deb_enter(LBS_DEB_CMD);
lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
querytype);
lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
if (querytype == CMD_ACT_GET) {
switch (oid) {
case FRAGTHRESH_I:
priv->fragthsd =
le16_to_cpu(*((__le16 *)(smib->value)));
lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
priv->fragthsd);
break;
case RTSTHRESH_I:
priv->rtsthsd =
le16_to_cpu(*((__le16 *)(smib->value)));
lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
priv->rtsthsd);
break;
case SHORT_RETRYLIM_I:
priv->txretrycount =
le16_to_cpu(*((__le16 *)(smib->value)));
lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
priv->rtsthsd);
break;
default:
break;
}
}
lbs_deb_enter(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_key_material(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_key_material *pkeymaterial =
&resp->params.keymaterial;
u16 action = le16_to_cpu(pkeymaterial->action);
lbs_deb_enter(LBS_DEB_CMD);
/* Copy the returned key to driver private data */
if (action == CMD_ACT_GET) {
u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
while (buf_ptr < resp_end) {
struct MrvlIEtype_keyParamSet * pkeyparamset =
(struct MrvlIEtype_keyParamSet *) buf_ptr;
struct enc_key * pkey;
u16 param_set_len = le16_to_cpu(pkeyparamset->length);
u16 key_len = le16_to_cpu(pkeyparamset->keylen);
u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
u8 * end;
end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+ sizeof (pkeyparamset->length)
+ param_set_len;
/* Make sure we don't access past the end of the IEs */
if (end > resp_end)
break;
if (key_flags & KEY_INFO_WPA_UNICAST)
pkey = &priv->wpa_unicast_key;
else if (key_flags & KEY_INFO_WPA_MCAST)
pkey = &priv->wpa_mcast_key;
else
break;
/* Copy returned key into driver */
memset(pkey, 0, sizeof(struct enc_key));
if (key_len > sizeof(pkey->key))
break;
pkey->type = key_type;
pkey->flags = key_flags;
pkey->len = key_len;
memcpy(pkey->key, pkeyparamset->key, pkey->len);
buf_ptr = end + 1;
}
}
lbs_deb_enter(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
lbs_deb_enter(LBS_DEB_CMD);
memcpy(priv->current_addr, macadd->macadd, ETH_ALEN);
lbs_deb_enter(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
lbs_deb_enter(LBS_DEB_CMD);
priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
lbs_deb_enter(LBS_DEB_CMD);
if (rates->action == CMD_ACT_GET) {
priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
priv->ratebitmap = le16_to_cpu(rates->bitmap);
}
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
lbs_deb_enter(LBS_DEB_CMD);
/* store the non average value */
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
priv->NF[TYPE_BEACON][TYPE_NOAVG]);
priv->RSSI[TYPE_BEACON][TYPE_AVG] =
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
priv->RSSI[TYPE_BEACON][TYPE_AVG]);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct lbs_ioctl_regrdwr *pbuf;
pbuf = (struct lbs_ioctl_regrdwr *) priv->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;
}
static int lbs_ret_get_log(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
lbs_deb_enter(LBS_DEB_CMD);
/* Stored little-endian */
memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_enable_rsn(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
u32 * pdata_buf = priv->cur_cmd->pdata_buf;
lbs_deb_enter(LBS_DEB_CMD);
if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
if (pdata_buf)
*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
}
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_beacon_control *bcn_ctrl =
&resp->params.bcn_ctrl;
lbs_deb_enter(LBS_DEB_CMD);
if (bcn_ctrl->action == CMD_ACT_GET) {
priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
}
lbs_deb_enter(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_subscribe_event *cmd_event =
&resp->params.subscribe_event;
struct cmd_ds_802_11_subscribe_event *dst_event =
priv->cur_cmd->pdata_buf;
lbs_deb_enter(LBS_DEB_CMD);
if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
dst_event->events = cmd_event->events;
memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
}
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static inline int handle_cmd_response(struct lbs_private *priv,
unsigned long dummy,
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(CMD_802_11_SCAN):
ret = lbs_ret_80211_scan(priv, resp);
break;
case CMD_RET(CMD_802_11_GET_LOG):
ret = lbs_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 = 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, resp);
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_GET_STAT):
ret = lbs_ret_802_11_stat(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(priv->cur_cmd->pdata_buf, &resp->params.afc,
sizeof(struct cmd_ds_802_11_afc));
spin_unlock_irqrestore(&priv->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 = lbs_ret_802_11_enable_rsn(priv, resp);
break;
case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
break;
case CMD_RET(CMD_802_11_RSSI):
ret = lbs_ret_802_11_rssi(priv, resp);
break;
case CMD_RET(CMD_802_11_MAC_ADDRESS):
ret = lbs_ret_802_11_mac_address(priv, resp);
break;
case CMD_RET(CMD_802_11_AD_HOC_STOP):
ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
break;
case CMD_RET(CMD_802_11_KEY_MATERIAL):
ret = lbs_ret_802_11_key_material(priv, resp);
break;
case CMD_RET(CMD_802_11_EEPROM_ACCESS):
ret = lbs_ret_802_11_eeprom_access(priv, resp);
break;
case CMD_RET(CMD_802_11D_DOMAIN_INFO):
ret = lbs_ret_802_11d_domain_info(priv, resp);
break;
case CMD_RET(CMD_802_11_SLEEP_PARAMS):
ret = lbs_ret_802_11_sleep_params(priv, resp);
break;
case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
spin_lock_irqsave(&priv->driver_lock, flags);
*((u16 *) priv->cur_cmd->pdata_buf) =
le16_to_cpu(resp->params.inactivity_timeout.timeout);
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_802_11_TPC_CFG):
spin_lock_irqsave(&priv->driver_lock, flags);
memmove(priv->cur_cmd->pdata_buf, &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(priv->cur_cmd->pdata_buf, &resp->params.ledgpio,
sizeof(struct cmd_ds_802_11_led_ctrl));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
ret = lbs_ret_802_11_subscribe_event(priv, resp);
break;
case CMD_RET(CMD_802_11_PWR_CFG):
spin_lock_irqsave(&priv->driver_lock, flags);
memmove(priv->cur_cmd->pdata_buf, &resp->params.pwrcfg,
sizeof(struct cmd_ds_802_11_pwr_cfg));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_GET_TSF):
spin_lock_irqsave(&priv->driver_lock, flags);
memcpy(priv->cur_cmd->pdata_buf,
&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->pdata_buf)
memcpy(priv->cur_cmd->pdata_buf,
&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->pdata_buf)
memcpy(priv->cur_cmd->pdata_buf, &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_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
resp->command);
break;
}
lbs_deb_leave(LBS_DEB_HOST);
return ret;
}
int lbs_process_rx_command(struct lbs_private *priv)
{
u16 respcmd;
struct cmd_header *resp;
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(&priv->command_timer);
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 = priv->cur_cmd->cmdbuf;
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", (void *) resp, priv->upld_len);
if (!(respcmd & 0x8000)) {
lbs_deb_host("invalid response!\n");
priv->cur_cmd_retcode = -1;
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
}
/* Store the response code to cur_cmd_retcode. */
priv->cur_cmd_retcode = result;
if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
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->mode == IW_MODE_ADHOC &&
action == CMD_SUBCMD_ENTER_PS)
priv->psmode = LBS802_11POWERMODECAM;
} else if (action == CMD_SUBCMD_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_ps_wakeup(priv, 0);
mutex_lock(&priv->lock);
spin_lock_irqsave(&priv->driver_lock, flags);
}
} else if (action == CMD_SUBCMD_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_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
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_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
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);
} else
ret = handle_cmd_response(priv, 0, resp);
spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd) {
/* Clean up and Put current command back to cmdfreeq */
__lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
priv->cur_cmd = NULL;
}
spin_unlock_irqrestore(&priv->driver_lock, flags);
done:
mutex_unlock(&priv->lock);
lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
int lbs_process_event(struct lbs_private *priv)
{
int ret = 0;
u32 eventcause;
lbs_deb_enter(LBS_DEB_CMD);
spin_lock_irq(&priv->driver_lock);
eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
spin_unlock_irq(&priv->driver_lock);
lbs_deb_cmd("event cause %d\n", eventcause);
switch (eventcause) {
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");
lbs_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_DISASSOCIATED:
lbs_deb_cmd("EVENT: disassociated\n");
lbs_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
lbs_deb_cmd("EVENT: link lost\n");
lbs_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_PS_SLEEP:
lbs_deb_cmd("EVENT: sleep\n");
/* handle unexpected PS SLEEP event */
if (priv->psstate == PS_STATE_FULL_POWER) {
lbs_deb_cmd(
"EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
break;
}
priv->psstate = PS_STATE_PRE_SLEEP;
lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
break;
case MACREG_INT_CODE_PS_AWAKE:
lbs_deb_cmd("EVENT: awake\n");
/* handle unexpected PS AWAKE event */
if (priv->psstate == PS_STATE_FULL_POWER) {
lbs_deb_cmd(
"EVENT: In FULL POWER mode - ignore PS AWAKE\n");
break;
}
priv->psstate = PS_STATE_AWAKE;
if (priv->needtowakeup) {
/*
* wait for the command processing to finish
* before resuming sending
* priv->needtowakeup will be set to FALSE
* in lbs_ps_wakeup()
*/
lbs_deb_cmd("waking up ...\n");
lbs_ps_wakeup(priv, 0);
}
break;
case MACREG_INT_CODE_MIC_ERR_UNICAST:
lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
break;
case MACREG_INT_CODE_MIC_ERR_MULTICAST:
lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
break;
case MACREG_INT_CODE_MIB_CHANGED:
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");
priv->mesh_connect_status = LBS_CONNECTED;
if (priv->mesh_open == 1) {
netif_wake_queue(priv->mesh_dev);
netif_carrier_on(priv->mesh_dev);
}
priv->mode = IW_MODE_ADHOC;
schedule_work(&priv->sync_channel);
break;
default:
lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
break;
}
spin_lock_irq(&priv->driver_lock);
priv->eventcause = 0;
spin_unlock_irq(&priv->driver_lock);
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}

View File

@ -0,0 +1,17 @@
#ifndef __COMPAT_H
#define __COMPAT_H
#include <linux/kernel.h>
#include <linux/types.h>
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
static inline char *print_mac(char *buf, const u8 *addr)
{
sprintf(buf, MAC_FMT,
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
return buf;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
#ifndef _LBS_DEBUGFS_H_
#define _LBS_DEBUGFS_H_
void lbs_debugfs_init(void);
void lbs_debugfs_remove(void);
void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev);
void lbs_debugfs_remove_one(struct lbs_private *priv);
#endif

View File

@ -0,0 +1,80 @@
/**
* This file contains declaration referring to
* functions defined in other source files
*/
#ifndef _LBS_DECL_H_
#define _LBS_DECL_H_
#include <linux/device.h>
#include "defs.h"
/** Function Prototype Declaration */
struct lbs_private;
struct sk_buff;
struct net_device;
struct cmd_ctrl_node;
struct cmd_ds_command;
int lbs_set_mac_packet_filter(struct lbs_private *priv);
void lbs_send_tx_feedback(struct lbs_private *priv);
int lbs_free_cmd_buffer(struct lbs_private *priv);
int lbs_prepare_and_send_command(struct lbs_private *priv,
u16 cmd_no,
u16 cmd_action,
u16 wait_option, u32 cmd_oid, void *pdata_buf);
void lbs_queue_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *cmdnode,
u8 addtail);
int lbs_allocate_cmd_buffer(struct lbs_private *priv);
int lbs_execute_next_command(struct lbs_private *priv);
int lbs_process_event(struct lbs_private *priv);
void lbs_interrupt(struct lbs_private *priv);
int lbs_set_radio_control(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
void lbs_get_fwversion(struct lbs_private *priv,
char *fwversion,
int maxlen);
/** The proc fs interface */
int lbs_process_rx_command(struct lbs_private *priv);
void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *ptempcmd);
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode);
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
struct lbs_private *priv,
u8 band,
u16 channel);
void lbs_mac_event_disconnected(struct lbs_private *priv);
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
/* main.c */
struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
u8 band,
int *cfp_no);
struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
int lbs_remove_card(struct lbs_private *priv);
int lbs_start_card(struct lbs_private *priv);
int lbs_stop_card(struct lbs_private *priv);
int lbs_reset_device(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
#endif

379
package/libertas/src/defs.h Normal file
View File

@ -0,0 +1,379 @@
/**
* This header file contains global constant/enum definitions,
* global variable declaration.
*/
#ifndef _LBS_DEFS_H_
#define _LBS_DEFS_H_
#include <linux/spinlock.h>
#ifdef CONFIG_LIBERTAS_DEBUG
#define DEBUG
#define PROC_DEBUG
#endif
#ifndef DRV_NAME
#define DRV_NAME "libertas"
#endif
#define LBS_DEB_ENTER 0x00000001
#define LBS_DEB_LEAVE 0x00000002
#define LBS_DEB_MAIN 0x00000004
#define LBS_DEB_NET 0x00000008
#define LBS_DEB_MESH 0x00000010
#define LBS_DEB_WEXT 0x00000020
#define LBS_DEB_IOCTL 0x00000040
#define LBS_DEB_SCAN 0x00000080
#define LBS_DEB_ASSOC 0x00000100
#define LBS_DEB_JOIN 0x00000200
#define LBS_DEB_11D 0x00000400
#define LBS_DEB_DEBUGFS 0x00000800
#define LBS_DEB_ETHTOOL 0x00001000
#define LBS_DEB_HOST 0x00002000
#define LBS_DEB_CMD 0x00004000
#define LBS_DEB_RX 0x00008000
#define LBS_DEB_TX 0x00010000
#define LBS_DEB_USB 0x00020000
#define LBS_DEB_CS 0x00040000
#define LBS_DEB_FW 0x00080000
#define LBS_DEB_THREAD 0x00100000
#define LBS_DEB_HEX 0x00200000
#define LBS_DEB_SDIO 0x00400000
extern unsigned int lbs_debug;
#ifdef DEBUG
#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
do { if ((lbs_debug & (grp)) == (grp)) \
printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
in_interrupt() ? " (INT)" : "", ## args); } while (0)
#else
#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
#endif
#define lbs_deb_enter(grp) \
LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__);
#define lbs_deb_enter_args(grp, fmt, args...) \
LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
#define lbs_deb_leave(grp) \
LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__);
#define lbs_deb_leave_args(grp, fmt, args...) \
LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \
__FUNCTION__, __LINE__, ##args);
#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args)
#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args)
#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args)
#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args)
#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args)
#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args)
#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args)
#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args)
#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args)
#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args)
#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args)
#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args)
#define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args)
#define lbs_pr_err(format, args...) \
printk(KERN_ERR DRV_NAME": " format, ## args)
#define lbs_pr_alert(format, args...) \
printk(KERN_ALERT DRV_NAME": " format, ## args)
#ifdef DEBUG
static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
{
int i = 0;
if (len &&
(lbs_debug & LBS_DEB_HEX) &&
(lbs_debug & grp))
{
for (i = 1; i <= len; i++) {
if ((i & 0xf) == 1) {
if (i != 1)
printk("\n");
printk(DRV_NAME " %s: ", prompt);
}
printk("%02x ", (u8) * buf);
buf++;
}
printk("\n");
}
}
#else
#define lbs_deb_hex(grp,prompt,buf,len) do {} while (0)
#endif
/** Buffer Constants */
/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
* driver has more local TxPDs. Each TxPD on the host memory is associated
* with a Tx control node. The driver maintains 8 RxPD descriptors for
* station firmware to store Rx packet information.
*
* Current version of MAC has a 32x6 multicast address buffer.
*
* 802.11b can have up to 14 channels, the driver keeps the
* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
*/
#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
#define LBS_NUM_CMD_BUFFERS 10
#define LBS_CMD_BUFFER_SIZE (2 * 1024)
#define MRVDRV_MAX_CHANNEL_SIZE 14
#define MRVDRV_ASSOCIATION_TIME_OUT 255
#define MRVDRV_SNAP_HEADER_LEN 8
#define LBS_UPLD_SIZE 2312
#define DEV_NAME_LEN 32
/** Misc constants */
/* This section defines 802.11 specific contants */
#define MRVDRV_MAX_BSS_DESCRIPTS 16
#define MRVDRV_MAX_REGION_CODE 6
#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
#define MRVDRV_MIN_MULTIPLE_DTIM 1
#define MRVDRV_MAX_MULTIPLE_DTIM 5
#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10
#define MRVDRV_CHANNELS_PER_SCAN 4
#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
#define MRVDRV_MIN_BEACON_INTERVAL 20
#define MRVDRV_MAX_BEACON_INTERVAL 1000
#define MRVDRV_BEACON_INTERVAL 100
#define MARVELL_MESH_IE_LENGTH 9
/** INT status Bit Definition*/
#define MRVDRV_TX_DNLD_RDY 0x0001
#define MRVDRV_RX_UPLD_RDY 0x0002
#define MRVDRV_CMD_DNLD_RDY 0x0004
#define MRVDRV_CMD_UPLD_RDY 0x0008
#define MRVDRV_CARDEVENT 0x0010
#define SBI_EVENT_CAUSE_SHIFT 3
/** TxPD status */
/* Station firmware use TxPD status field to report final Tx transmit
* result, Bit masks are used to present combined situations.
*/
#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
/** Tx mesh flag */
/* Currently we are using normal WDS flag as mesh flag.
* TODO: change to proper mesh flag when MAC understands it.
*/
#define TxPD_CONTROL_WDS_FRAME (1<<17)
#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
/** RxPD status */
#define MRVDRV_RXPD_STATUS_OK 0x0001
/** RxPD status - Received packet types */
/** Rx mesh flag */
/* Currently we are using normal WDS flag as mesh flag.
* TODO: change to proper mesh flag when MAC understands it.
*/
#define RxPD_CONTROL_WDS_FRAME (0x40)
#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
/** RSSI-related defines */
/* RSSI constants are used to implement 802.11 RSSI threshold
* indication. if the Rx packet signal got too weak for 5 consecutive
* times, miniport driver (driver) will report this event to wrapper
*/
#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
/** RTS/FRAG related defines */
#define MRVDRV_RTS_MIN_VALUE 0
#define MRVDRV_RTS_MAX_VALUE 2347
#define MRVDRV_FRAG_MIN_VALUE 256
#define MRVDRV_FRAG_MAX_VALUE 2346
/* This is for firmware specific length */
#define EXTRA_LEN 36
#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
(ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
(ETH_FRAME_LEN + sizeof(struct rxpd) \
+ MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
#define CMD_F_HOSTCMD (1 << 0)
#define FW_CAPINFO_WPA (1 << 0)
#define KEY_LEN_WPA_AES 16
#define KEY_LEN_WPA_TKIP 32
#define KEY_LEN_WEP_104 13
#define KEY_LEN_WEP_40 5
#define RF_ANTENNA_1 0x1
#define RF_ANTENNA_2 0x2
#define RF_ANTENNA_AUTO 0xFFFF
#define BAND_B (0x01)
#define BAND_G (0x02)
#define ALL_802_11_BANDS (BAND_B | BAND_G)
/** MACRO DEFINITIONS */
#define CAL_NF(NF) ((s32)(-(s32)(NF)))
#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF)))
#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
#define DEFAULT_BCN_AVG_FACTOR 8
#define DEFAULT_DATA_AVG_FACTOR 8
#define AVG_SCALE 100
#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \
(((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
AVG_SCALE)) / N))
#define MAX_RATES 14
#define MAX_LEDS 8
/** Global Variable Declaration */
extern const char lbs_driver_version[];
extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
extern u8 lbs_bg_rates[MAX_RATES];
/** ENUM definition*/
/** SNRNF_TYPE */
enum SNRNF_TYPE {
TYPE_BEACON = 0,
TYPE_RXPD,
MAX_TYPE_B
};
/** SNRNF_DATA*/
enum SNRNF_DATA {
TYPE_NOAVG = 0,
TYPE_AVG,
MAX_TYPE_AVG
};
/** LBS_802_11_POWER_MODE */
enum LBS_802_11_POWER_MODE {
LBS802_11POWERMODECAM,
LBS802_11POWERMODEMAX_PSP,
LBS802_11POWERMODEFAST_PSP,
/*not a real mode, defined as an upper bound */
LBS802_11POWEMODEMAX
};
/** PS_STATE */
enum PS_STATE {
PS_STATE_FULL_POWER,
PS_STATE_AWAKE,
PS_STATE_PRE_SLEEP,
PS_STATE_SLEEP
};
/** DNLD_STATE */
enum DNLD_STATE {
DNLD_RES_RECEIVED,
DNLD_DATA_SENT,
DNLD_CMD_SENT
};
/** LBS_MEDIA_STATE */
enum LBS_MEDIA_STATE {
LBS_CONNECTED,
LBS_DISCONNECTED
};
/** LBS_802_11_PRIVACY_FILTER */
enum LBS_802_11_PRIVACY_FILTER {
LBS802_11PRIVFILTERACCEPTALL,
LBS802_11PRIVFILTER8021XWEP
};
/** mv_ms_type */
enum mv_ms_type {
MVMS_DAT = 0,
MVMS_CMD = 1,
MVMS_TXDONE = 2,
MVMS_EVENT
};
/** SNMP_MIB_INDEX_e */
enum SNMP_MIB_INDEX_e {
DESIRED_BSSTYPE_I = 0,
OP_RATESET_I,
BCNPERIOD_I,
DTIMPERIOD_I,
ASSOCRSP_TIMEOUT_I,
RTSTHRESH_I,
SHORT_RETRYLIM_I,
LONG_RETRYLIM_I,
FRAGTHRESH_I,
DOT11D_I,
DOT11H_I,
MANUFID_I,
PRODID_I,
MANUF_OUI_I,
MANUF_NAME_I,
MANUF_PRODNAME_I,
MANUF_PRODVER_I,
};
/** KEY_TYPE_ID */
enum KEY_TYPE_ID {
KEY_TYPE_ID_WEP = 0,
KEY_TYPE_ID_TKIP,
KEY_TYPE_ID_AES
};
/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
enum KEY_INFO_WPA {
KEY_INFO_WPA_MCAST = 0x01,
KEY_INFO_WPA_UNICAST = 0x02,
KEY_INFO_WPA_ENABLED = 0x04
};
/** SNMP_MIB_VALUE_e */
enum SNMP_MIB_VALUE_e {
SNMP_MIB_VALUE_INFRA = 1,
SNMP_MIB_VALUE_ADHOC
};
/* Default values for fwt commands. */
#define FWT_DEFAULT_METRIC 0
#define FWT_DEFAULT_DIR 1
/* Default Rate, 11Mbps */
#define FWT_DEFAULT_RATE 3
#define FWT_DEFAULT_SSN 0xffffffff
#define FWT_DEFAULT_DSN 0
#define FWT_DEFAULT_HOPCOUNT 0
#define FWT_DEFAULT_TTL 0
#define FWT_DEFAULT_EXPIRATION 0
#define FWT_DEFAULT_SLEEPMODE 0
#define FWT_DEFAULT_SNR 0
#endif

365
package/libertas/src/dev.h Normal file
View File

@ -0,0 +1,365 @@
/**
* This file contains definitions and data structures specific
* to Marvell 802.11 NIC. It contains the Device Information
* structure struct lbs_private..
*/
#ifndef _LBS_DEV_H_
#define _LBS_DEV_H_
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <linux/ethtool.h>
#include <linux/debugfs.h>
#include "defs.h"
#include "scan.h"
extern struct ethtool_ops lbs_ethtool_ops;
#define MAX_BSSID_PER_CHANNEL 16
#define NR_TX_QUEUE 3
/* For the extended Scan */
#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
MRVDRV_MAX_CHANNEL_SIZE + 1
#define MAX_REGION_CHANNEL_NUM 2
/** Chan-freq-TxPower mapping table*/
struct chan_freq_power {
/** channel Number */
u16 channel;
/** frequency of this channel */
u32 freq;
/** Max allowed Tx power level */
u16 maxtxpower;
/** TRUE:channel unsupported; FLASE:supported*/
u8 unsupported;
};
/** region-band mapping table*/
struct region_channel {
/** TRUE if this entry is valid */
u8 valid;
/** region code for US, Japan ... */
u8 region;
/** band B/G/A, used for BAND_CONFIG cmd */
u8 band;
/** Actual No. of elements in the array below */
u8 nrcfp;
/** chan-freq-txpower mapping table*/
struct chan_freq_power *CFP;
};
struct lbs_802_11_security {
u8 WPAenabled;
u8 WPA2enabled;
u8 wep_enabled;
u8 auth_mode;
};
/** Current Basic Service Set State Structure */
struct current_bss_params {
/** bssid */
u8 bssid[ETH_ALEN];
/** ssid */
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
/** band */
u8 band;
/** channel */
u8 channel;
/** zero-terminated array of supported data rates */
u8 rates[MAX_RATES + 1];
};
/** sleep_params */
struct sleep_params {
u16 sp_error;
u16 sp_offset;
u16 sp_stabletime;
u8 sp_calcontrol;
u8 sp_extsleepclk;
u16 sp_reserved;
};
/* Mesh statistics */
struct lbs_mesh_stats {
u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
u32 fwd_drop_ttl; /* Fwd: TTL zero */
u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
u32 fwd_drop_noroute; /* Fwd: No route to Destination */
u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
u32 drop_blind; /* Rx: Dropped by blinding table */
u32 tx_failed_cnt; /* Tx: Failed transmissions */
};
/** Private structure for the MV device */
struct lbs_private {
int mesh_open;
int infra_open;
int mesh_autostart_enabled;
__le16 boot2_version;
char name[DEV_NAME_LEN];
void *card;
struct net_device *dev;
struct net_device_stats stats;
struct net_device *mesh_dev; /* Virtual device */
struct net_device *rtap_net_dev;
struct iw_statistics wstats;
struct lbs_mesh_stats mstats;
struct dentry *debugfs_dir;
struct dentry *debugfs_debug;
struct dentry *debugfs_files[6];
struct dentry *events_dir;
struct dentry *debugfs_events_files[6];
struct dentry *regs_dir;
struct dentry *debugfs_regs_files[6];
u32 mac_offset;
u32 bbp_offset;
u32 rf_offset;
/** Upload length */
u32 upld_len;
/* Upload buffer */
u8 upld_buf[LBS_UPLD_SIZE];
/* Download sent:
bit0 1/0=data_sent/data_tx_done,
bit1 1/0=cmd_sent/cmd_tx_done,
all other bits reserved 0 */
u8 dnld_sent;
/** thread to service interrupts */
struct task_struct *main_thread;
wait_queue_head_t waitq;
struct workqueue_struct *work_thread;
struct delayed_work scan_work;
struct delayed_work assoc_work;
struct work_struct sync_channel;
/** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
int (*hw_read_event_cause) (struct lbs_private *);
/* was struct lbs_adapter from here... */
/** Wlan adapter data structure*/
/** STATUS variables */
u8 fwreleasenumber[4];
u32 fwcapinfo;
/* protected with big lock */
struct mutex lock;
/* TX packet ready to be sent... */
int tx_pending_len; /* -1 while building packet */
u8 tx_pending_buf[LBS_UPLD_SIZE];
/* protected by hard_start_xmit serialization */
/** command-related variables */
u16 seqnum;
/* protected by big lock */
struct cmd_ctrl_node *cmd_array;
/** Current command */
struct cmd_ctrl_node *cur_cmd;
int cur_cmd_retcode;
/** command Queues */
/** Free command buffers */
struct list_head cmdfreeq;
/** Pending command buffers */
struct list_head cmdpendingq;
wait_queue_head_t cmd_pending;
/* command related variables protected by priv->driver_lock */
/** Async and Sync Event variables */
u32 intcounter;
u32 eventcause;
u8 nodename[16]; /* nickname */
/** spin locks */
spinlock_t driver_lock;
/** Timers */
struct timer_list command_timer;
u8 hisregcpy;
/** current ssid/bssid related parameters*/
struct current_bss_params curbssparams;
u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1];
u8 mesh_ssid_len;
/* IW_MODE_* */
u8 mode;
/* Scan results list */
struct list_head network_list;
struct list_head network_free_list;
struct bss_descriptor *networks;
u16 beacon_period;
u8 beacon_enable;
u8 adhoccreate;
/** capability Info used in Association, start, join */
u16 capability;
/** MAC address information */
u8 current_addr[ETH_ALEN];
u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
u32 nr_of_multicastmacaddr;
/** 802.11 statistics */
// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
u16 enablehwauto;
u16 ratebitmap;
u32 fragthsd;
u32 rtsthsd;
u8 txretrycount;
/** Tx-related variables (for single packet tx) */
struct sk_buff *currenttxskb;
/** NIC Operation characteristics */
u16 currentpacketfilter;
u32 connect_status;
u32 mesh_connect_status;
u16 regioncode;
u16 txpowerlevel;
/** POWER MANAGEMENT AND PnP SUPPORT */
u8 surpriseremoved;
u16 psmode; /* Wlan802_11PowermodeCAM=disable
Wlan802_11PowermodeMAX_PSP=enable */
u32 psstate;
u8 needtowakeup;
struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep;
struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req;
/** Encryption parameter */
struct lbs_802_11_security secinfo;
/** WEP keys */
struct enc_key wep_keys[4];
u16 wep_tx_keyidx;
/** WPA keys */
struct enc_key wpa_mcast_key;
struct enc_key wpa_unicast_key;
/** WPA Information Elements*/
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
/** Requested Signal Strength*/
u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
u16 nextSNRNF;
u16 numSNRNF;
u8 radioon;
u32 preamble;
/** data rate stuff */
u8 cur_rate;
u8 auto_rate;
/** sleep_params */
struct sleep_params sp;
/** RF calibration data */
#define MAX_REGION_CHANNEL_NUM 2
/** region channel data */
struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
/** 11D and Domain Regulatory Data */
struct lbs_802_11d_domain_reg domainreg;
struct parsed_region_chan_11d parsed_region_chan;
/** FSM variable for 11d support */
u32 enable11d;
/** MISCELLANEOUS */
u8 *prdeeprom;
struct lbs_offset_value offsetvalue;
struct cmd_ds_802_11_get_log logmsg;
u32 monitormode;
int last_scanned_channel;
u8 fw_ready;
};
/** Association request
*
* Encapsulates all the options that describe a specific assocation request
* or configuration of the wireless card's radio, mode, and security settings.
*/
struct assoc_request {
#define ASSOC_FLAG_SSID 1
#define ASSOC_FLAG_CHANNEL 2
#define ASSOC_FLAG_BAND 3
#define ASSOC_FLAG_MODE 4
#define ASSOC_FLAG_BSSID 5
#define ASSOC_FLAG_WEP_KEYS 6
#define ASSOC_FLAG_WEP_TX_KEYIDX 7
#define ASSOC_FLAG_WPA_MCAST_KEY 8
#define ASSOC_FLAG_WPA_UCAST_KEY 9
#define ASSOC_FLAG_SECINFO 10
#define ASSOC_FLAG_WPA_IE 11
unsigned long flags;
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
u8 channel;
u8 band;
u8 mode;
u8 bssid[ETH_ALEN];
/** WEP keys */
struct enc_key wep_keys[4];
u16 wep_tx_keyidx;
/** WPA keys */
struct enc_key wpa_mcast_key;
struct enc_key wpa_unicast_key;
struct lbs_802_11_security secinfo;
/** WPA Information Elements*/
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
/* BSS to associate with for infrastructure of Ad-Hoc join */
struct bss_descriptor bss;
};
#endif

View File

@ -0,0 +1,172 @@
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
#include "host.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "join.h"
#include "wext.h"
static const char * mesh_stat_strings[]= {
"drop_duplicate_bcast",
"drop_ttl_zero",
"drop_no_fwd_route",
"drop_no_buffers",
"fwded_unicast_cnt",
"fwded_bcast_cnt",
"drop_blind_table",
"tx_failed_cnt"
};
static void lbs_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct lbs_private *priv = (struct lbs_private *) dev->priv;
char fwver[32];
lbs_get_fwversion(priv, fwver, sizeof(fwver) - 1);
strcpy(info->driver, "libertas");
strcpy(info->version, lbs_driver_version);
strcpy(info->fw_version, fwver);
}
/* All 8388 parts have 16KiB EEPROM size at the time of writing.
* In case that changes this needs fixing.
*/
#define LBS_EEPROM_LEN 16384
static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
{
return LBS_EEPROM_LEN;
}
static int lbs_ethtool_get_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 * bytes)
{
struct lbs_private *priv = (struct lbs_private *) dev->priv;
struct lbs_ioctl_regrdwr regctrl;
char *ptr;
int ret;
regctrl.action = 0;
regctrl.offset = eeprom->offset;
regctrl.NOB = eeprom->len;
if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN)
return -EINVAL;
// mutex_lock(&priv->mutex);
priv->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
if (!priv->prdeeprom)
return -ENOMEM;
memcpy(priv->prdeeprom, &regctrl, sizeof(regctrl));
/* +14 is for action, offset, and NOB in
* response */
lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n",
regctrl.action, regctrl.offset, regctrl.NOB);
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_EEPROM_ACCESS,
regctrl.action,
CMD_OPTION_WAITFORRSP, 0,
&regctrl);
if (ret) {
if (priv->prdeeprom)
kfree(priv->prdeeprom);
goto done;
}
mdelay(10);
ptr = (char *)priv->prdeeprom;
/* skip the command header, but include the "value" u32 variable */
ptr = ptr + sizeof(struct lbs_ioctl_regrdwr) - 4;
/*
* Return the result back to the user
*/
memcpy(bytes, ptr, eeprom->len);
if (priv->prdeeprom)
kfree(priv->prdeeprom);
// mutex_unlock(&priv->mutex);
ret = 0;
done:
lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret);
return ret;
}
static void lbs_ethtool_get_stats(struct net_device * dev,
struct ethtool_stats * stats, u64 * data)
{
struct lbs_private *priv = dev->priv;
struct cmd_ds_mesh_access mesh_access;
int ret;
lbs_deb_enter(LBS_DEB_ETHTOOL);
/* Get Mesh Statistics */
ret = lbs_prepare_and_send_command(priv,
CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS,
CMD_OPTION_WAITFORRSP, 0, &mesh_access);
if (ret)
return;
priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
data[0] = priv->mstats.fwd_drop_rbt;
data[1] = priv->mstats.fwd_drop_ttl;
data[2] = priv->mstats.fwd_drop_noroute;
data[3] = priv->mstats.fwd_drop_nobuf;
data[4] = priv->mstats.fwd_unicast_cnt;
data[5] = priv->mstats.fwd_bcast_cnt;
data[6] = priv->mstats.drop_blind;
data[7] = priv->mstats.tx_failed_cnt;
lbs_deb_enter(LBS_DEB_ETHTOOL);
}
static void lbs_ethtool_get_strings(struct net_device *dev,
u32 stringset,
u8 * s)
{
int i;
lbs_deb_enter(LBS_DEB_ETHTOOL);
switch (stringset) {
case ETH_SS_STATS:
for (i=0; i < MESH_STATS_NUM; i++) {
memcpy(s + i * ETH_GSTRING_LEN,
mesh_stat_strings[i],
ETH_GSTRING_LEN);
}
break;
}
lbs_deb_enter(LBS_DEB_ETHTOOL);
}
struct ethtool_ops lbs_ethtool_ops = {
.get_drvinfo = lbs_ethtool_get_drvinfo,
.get_eeprom = lbs_ethtool_get_eeprom,
.get_eeprom_len = lbs_ethtool_get_eeprom_len,
.get_ethtool_stats = lbs_ethtool_get_stats,
.get_strings = lbs_ethtool_get_strings,
};

286
package/libertas/src/host.h Normal file
View File

@ -0,0 +1,286 @@
/**
* This file contains definitions of WLAN commands.
*/
#ifndef _LBS_HOST_H_
#define _LBS_HOST_H_
/** PUBLIC DEFINITIONS */
#define DEFAULT_AD_HOC_CHANNEL 6
#define DEFAULT_AD_HOC_CHANNEL_A 36
/** IEEE 802.11 oids */
#define OID_802_11_SSID 0x00008002
#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008
#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009
#define OID_802_11_RTS_THRESHOLD 0x0000800A
#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D
#define OID_802_11_SUPPORTED_RATES 0x0000800E
#define OID_802_11_STATISTICS 0x00008012
#define OID_802_11_TX_RETRYCOUNT 0x0000801D
#define OID_802_11D_ENABLE 0x00008020
#define CMD_OPTION_WAITFORRSP 0x0002
/** Host command IDs */
/* Return command are almost always the same as the host command, but with
* bit 15 set high. There are a few exceptions, though...
*/
#define CMD_RET(cmd) (0x8000 | cmd)
/* Return command convention exceptions: */
#define CMD_RET_802_11_ASSOCIATE 0x8012
/* Command codes */
#define CMD_CODE_DNLD 0x0002
#define CMD_GET_HW_SPEC 0x0003
#define CMD_EEPROM_UPDATE 0x0004
#define CMD_802_11_RESET 0x0005
#define CMD_802_11_SCAN 0x0006
#define CMD_802_11_GET_LOG 0x000b
#define CMD_MAC_MULTICAST_ADR 0x0010
#define CMD_802_11_AUTHENTICATE 0x0011
#define CMD_802_11_EEPROM_ACCESS 0x0059
#define CMD_802_11_ASSOCIATE 0x0050
#define CMD_802_11_SET_WEP 0x0013
#define CMD_802_11_GET_STAT 0x0014
#define CMD_802_3_GET_STAT 0x0015
#define CMD_802_11_SNMP_MIB 0x0016
#define CMD_MAC_REG_MAP 0x0017
#define CMD_BBP_REG_MAP 0x0018
#define CMD_MAC_REG_ACCESS 0x0019
#define CMD_BBP_REG_ACCESS 0x001a
#define CMD_RF_REG_ACCESS 0x001b
#define CMD_802_11_RADIO_CONTROL 0x001c
#define CMD_802_11_RF_CHANNEL 0x001d
#define CMD_802_11_RF_TX_POWER 0x001e
#define CMD_802_11_RSSI 0x001f
#define CMD_802_11_RF_ANTENNA 0x0020
#define CMD_802_11_PS_MODE 0x0021
#define CMD_802_11_DATA_RATE 0x0022
#define CMD_RF_REG_MAP 0x0023
#define CMD_802_11_DEAUTHENTICATE 0x0024
#define CMD_802_11_REASSOCIATE 0x0025
#define CMD_802_11_DISASSOCIATE 0x0026
#define CMD_MAC_CONTROL 0x0028
#define CMD_802_11_AD_HOC_START 0x002b
#define CMD_802_11_AD_HOC_JOIN 0x002c
#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
#define CMD_802_11_ENABLE_RSN 0x002f
#define CMD_802_11_PAIRWISE_TSC 0x0036
#define CMD_802_11_GROUP_TSC 0x0037
#define CMD_802_11_SET_AFC 0x003c
#define CMD_802_11_GET_AFC 0x003d
#define CMD_802_11_AD_HOC_STOP 0x0040
#define CMD_802_11_BEACON_STOP 0x0049
#define CMD_802_11_MAC_ADDRESS 0x004d
#define CMD_802_11_LED_GPIO_CTRL 0x004e
#define CMD_802_11_EEPROM_ACCESS 0x0059
#define CMD_802_11_BAND_CONFIG 0x0058
#define CMD_802_11D_DOMAIN_INFO 0x005b
#define CMD_802_11_KEY_MATERIAL 0x005e
#define CMD_802_11_SLEEP_PARAMS 0x0066
#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
#define CMD_802_11_TPC_CFG 0x0072
#define CMD_802_11_PWR_CFG 0x0073
#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
#define CMD_802_11_TX_RATE_QUERY 0x007f
#define CMD_GET_TSF 0x0080
#define CMD_BT_ACCESS 0x0087
#define CMD_FWT_ACCESS 0x0095
#define CMD_802_11_MONITOR_MODE 0x0098
#define CMD_MESH_ACCESS 0x009b
#define CMD_MESH_CONFIG 0x00a3
#define CMD_SET_BOOT2_VER 0x00a5
#define CMD_802_11_BEACON_CTRL 0x00b0
/* For the IEEE Power Save */
#define CMD_SUBCMD_ENTER_PS 0x0030
#define CMD_SUBCMD_EXIT_PS 0x0031
#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
#define CMD_SUBCMD_FULL_POWERUP 0x0036
#define CMD_ENABLE_RSN 0x0001
#define CMD_DISABLE_RSN 0x0000
#define CMD_ACT_GET 0x0000
#define CMD_ACT_SET 0x0001
#define CMD_ACT_GET_AES 0x0002
#define CMD_ACT_SET_AES 0x0003
#define CMD_ACT_REMOVE_AES 0x0004
/* Define action or option for CMD_802_11_SET_WEP */
#define CMD_ACT_ADD 0x0002
#define CMD_ACT_REMOVE 0x0004
#define CMD_ACT_USE_DEFAULT 0x0008
#define CMD_TYPE_WEP_40_BIT 0x01
#define CMD_TYPE_WEP_104_BIT 0x02
#define CMD_NUM_OF_WEP_KEYS 4
#define CMD_WEP_KEY_INDEX_MASK 0x3fff
/* Define action or option for CMD_802_11_RESET */
#define CMD_ACT_HALT 0x0003
/* Define action or option for CMD_802_11_SCAN */
#define CMD_BSS_TYPE_BSS 0x0001
#define CMD_BSS_TYPE_IBSS 0x0002
#define CMD_BSS_TYPE_ANY 0x0003
/* Define action or option for CMD_802_11_SCAN */
#define CMD_SCAN_TYPE_ACTIVE 0x0000
#define CMD_SCAN_TYPE_PASSIVE 0x0001
#define CMD_SCAN_RADIO_TYPE_BG 0
#define CMD_SCAN_PROBE_DELAY_TIME 0
/* Define action or option for CMD_MAC_CONTROL */
#define CMD_ACT_MAC_RX_ON 0x0001
#define CMD_ACT_MAC_TX_ON 0x0002
#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
#define CMD_ACT_MAC_WEP_ENABLE 0x0008
#define CMD_ACT_MAC_INT_ENABLE 0x0010
#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
/* Define action or option for CMD_802_11_RADIO_CONTROL */
#define CMD_TYPE_AUTO_PREAMBLE 0x0001
#define CMD_TYPE_SHORT_PREAMBLE 0x0002
#define CMD_TYPE_LONG_PREAMBLE 0x0003
/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
#define CMD_SUBSCRIBE_SNR_LOW 0x0002
#define CMD_SUBSCRIBE_FAILCOUNT 0x0004
#define CMD_SUBSCRIBE_BCNMISS 0x0008
#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
#define TURN_ON_RF 0x01
#define RADIO_ON 0x01
#define RADIO_OFF 0x00
#define SET_AUTO_PREAMBLE 0x05
#define SET_SHORT_PREAMBLE 0x03
#define SET_LONG_PREAMBLE 0x01
/* Define action or option for CMD_802_11_RF_CHANNEL */
#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
/* Define action or option for CMD_802_11_RF_TX_POWER */
#define CMD_ACT_TX_POWER_OPT_GET 0x0000
#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007
#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004
#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000
#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007
#define CMD_ACT_TX_POWER_INDEX_MID 0x0004
#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000
/* Define action or option for CMD_802_11_DATA_RATE */
#define CMD_ACT_SET_TX_AUTO 0x0000
#define CMD_ACT_SET_TX_FIX_RATE 0x0001
#define CMD_ACT_GET_TX_RATE 0x0002
#define CMD_ACT_SET_RX 0x0001
#define CMD_ACT_SET_TX 0x0002
#define CMD_ACT_SET_BOTH 0x0003
#define CMD_ACT_GET_RX 0x0004
#define CMD_ACT_GET_TX 0x0008
#define CMD_ACT_GET_BOTH 0x000c
/* Define action or option for CMD_802_11_PS_MODE */
#define CMD_TYPE_CAM 0x0000
#define CMD_TYPE_MAX_PSP 0x0001
#define CMD_TYPE_FAST_PSP 0x0002
/* Define action or option for CMD_BT_ACCESS */
enum cmd_bt_access_opts {
/* The bt commands start at 5 instead of 1 because the old dft commands
* are mapped to 1-4. These old commands are no longer maintained and
* should not be called.
*/
CMD_ACT_BT_ACCESS_ADD = 5,
CMD_ACT_BT_ACCESS_DEL,
CMD_ACT_BT_ACCESS_LIST,
CMD_ACT_BT_ACCESS_RESET,
CMD_ACT_BT_ACCESS_SET_INVERT,
CMD_ACT_BT_ACCESS_GET_INVERT
};
/* Define action or option for CMD_FWT_ACCESS */
enum cmd_fwt_access_opts {
CMD_ACT_FWT_ACCESS_ADD = 1,
CMD_ACT_FWT_ACCESS_DEL,
CMD_ACT_FWT_ACCESS_LOOKUP,
CMD_ACT_FWT_ACCESS_LIST,
CMD_ACT_FWT_ACCESS_LIST_ROUTE,
CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
CMD_ACT_FWT_ACCESS_RESET,
CMD_ACT_FWT_ACCESS_CLEANUP,
CMD_ACT_FWT_ACCESS_TIME,
};
/* Define action or option for CMD_MESH_ACCESS */
enum cmd_mesh_access_opts {
CMD_ACT_MESH_GET_TTL = 1,
CMD_ACT_MESH_SET_TTL,
CMD_ACT_MESH_GET_STATS,
CMD_ACT_MESH_GET_ANYCAST,
CMD_ACT_MESH_SET_ANYCAST,
CMD_ACT_MESH_SET_LINK_COSTS,
CMD_ACT_MESH_GET_LINK_COSTS,
CMD_ACT_MESH_SET_BCAST_RATE,
CMD_ACT_MESH_GET_BCAST_RATE,
CMD_ACT_MESH_SET_RREQ_DELAY,
CMD_ACT_MESH_GET_RREQ_DELAY,
CMD_ACT_MESH_SET_ROUTE_EXP,
CMD_ACT_MESH_GET_ROUTE_EXP,
CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
};
/** Card Event definition */
#define MACREG_INT_CODE_TX_PPA_FREE 0
#define MACREG_INT_CODE_TX_DMA_DONE 1
#define MACREG_INT_CODE_LINK_LOST_W_SCAN 2
#define MACREG_INT_CODE_LINK_LOST_NO_SCAN 3
#define MACREG_INT_CODE_LINK_SENSED 4
#define MACREG_INT_CODE_CMD_FINISHED 5
#define MACREG_INT_CODE_MIB_CHANGED 6
#define MACREG_INT_CODE_INIT_DONE 7
#define MACREG_INT_CODE_DEAUTHENTICATED 8
#define MACREG_INT_CODE_DISASSOCIATED 9
#define MACREG_INT_CODE_PS_AWAKE 10
#define MACREG_INT_CODE_PS_SLEEP 11
#define MACREG_INT_CODE_MIC_ERR_MULTICAST 13
#define MACREG_INT_CODE_MIC_ERR_UNICAST 14
#define MACREG_INT_CODE_WM_AWAKE 15
#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE 16
#define MACREG_INT_CODE_ADHOC_BCN_LOST 17
#define MACREG_INT_CODE_HOST_AWAKE 18
#define MACREG_INT_CODE_STOP_TX 19
#define MACREG_INT_CODE_START_TX 20
#define MACREG_INT_CODE_CHANNEL_SWITCH 21
#define MACREG_INT_CODE_MEASUREMENT_RDY 22
#define MACREG_INT_CODE_WMM_CHANGE 23
#define MACREG_INT_CODE_BG_SCAN_REPORT 24
#define MACREG_INT_CODE_RSSI_LOW 25
#define MACREG_INT_CODE_SNR_LOW 26
#define MACREG_INT_CODE_MAX_FAIL 27
#define MACREG_INT_CODE_RSSI_HIGH 28
#define MACREG_INT_CODE_SNR_HIGH 29
#define MACREG_INT_CODE_MESH_AUTO_STARTED 35
#define MACREG_INT_CODE_FIRMWARE_READY 48
#endif

View File

@ -0,0 +1,713 @@
/*
* This file contains the function prototypes, data structure
* and defines for all the host/station commands
*/
#ifndef _LBS_HOSTCMD_H
#define _LBS_HOSTCMD_H
#include <linux/wireless.h>
#include "11d.h"
#include "types.h"
/* 802.11-related definitions */
/* TxPD descriptor */
struct txpd {
/* Current Tx packet status */
__le32 tx_status;
/* Tx control */
__le32 tx_control;
__le32 tx_packet_location;
/* Tx packet length */
__le16 tx_packet_length;
/* First 2 byte of destination MAC address */
u8 tx_dest_addr_high[2];
/* Last 4 byte of destination MAC address */
u8 tx_dest_addr_low[4];
/* Pkt Priority */
u8 priority;
/* Pkt Trasnit Power control */
u8 powermgmt;
/* Amount of time the packet has been queued in the driver (units = 2ms) */
u8 pktdelay_2ms;
/* reserved */
u8 reserved1;
};
/* RxPD Descriptor */
struct rxpd {
/* Current Rx packet status */
__le16 status;
/* SNR */
u8 snr;
/* Tx control */
u8 rx_control;
/* Pkt length */
__le16 pkt_len;
/* Noise Floor */
u8 nf;
/* Rx Packet Rate */
u8 rx_rate;
/* Pkt addr */
__le32 pkt_ptr;
/* Next Rx RxPD addr */
__le32 next_rxpd_ptr;
/* Pkt Priority */
u8 priority;
u8 reserved[3];
};
struct cmd_header {
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
} __attribute__ ((packed));
struct cmd_ctrl_node {
struct list_head list;
/* wait for finish or not */
u16 wait_option;
/* command response */
void *pdata_buf;
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *);
unsigned long callback_arg;
/* command data */
struct cmd_header *cmdbuf;
/* wait queue */
u16 cmdwaitqwoken;
wait_queue_head_t cmdwait_q;
};
/* Generic structure to hold all key types. */
struct enc_key {
u16 len;
u16 flags; /* KEY_INFO_* from defs.h */
u16 type; /* KEY_TYPE_* from defs.h */
u8 key[32];
};
/* lbs_offset_value */
struct lbs_offset_value {
u32 offset;
u32 value;
};
/* Define general data structure */
/* cmd_DS_GEN */
struct cmd_ds_gen {
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
void *cmdresp[0];
};
#define S_DS_GEN sizeof(struct cmd_ds_gen)
/*
* Define data structure for CMD_GET_HW_SPEC
* This structure defines the response for the GET_HW_SPEC command
*/
struct cmd_ds_get_hw_spec {
struct cmd_header hdr;
/* HW Interface version number */
__le16 hwifversion;
/* HW version number */
__le16 version;
/* Max number of TxPD FW can handle */
__le16 nr_txpd;
/* Max no of Multicast address */
__le16 nr_mcast_adr;
/* MAC address */
u8 permanentaddr[6];
/* region Code */
__le16 regioncode;
/* Number of antenna used */
__le16 nr_antenna;
/* FW release number, example 1,2,3,4 = 3.2.1p4 */
u8 fwreleasenumber[4];
/* Base Address of TxPD queue */
__le32 wcb_base;
/* Read Pointer of RxPd queue */
__le32 rxpd_rdptr;
/* Write Pointer of RxPd queue */
__le32 rxpd_wrptr;
/*FW/HW capability */
__le32 fwcapinfo;
} __attribute__ ((packed));
struct cmd_ds_802_11_reset {
__le16 action;
};
struct cmd_ds_802_11_subscribe_event {
__le16 action;
__le16 events;
/* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
* number of TLVs. From the v5.1 manual, those TLVs would add up to
* 40 bytes. However, future firmware might add additional TLVs, so I
* bump this up a bit.
*/
u8 tlv[128];
};
/*
* This scan handle Country Information IE(802.11d compliant)
* Define data structure for CMD_802_11_SCAN
*/
struct cmd_ds_802_11_scan {
u8 bsstype;
u8 bssid[ETH_ALEN];
u8 tlvbuffer[1];
#if 0
mrvlietypes_ssidparamset_t ssidParamSet;
mrvlietypes_chanlistparamset_t ChanListParamSet;
mrvlietypes_ratesparamset_t OpRateSet;
#endif
};
struct cmd_ds_802_11_scan_rsp {
__le16 bssdescriptsize;
u8 nr_sets;
u8 bssdesc_and_tlvbuffer[1];
};
struct cmd_ds_802_11_get_log {
__le32 mcasttxframe;
__le32 failed;
__le32 retry;
__le32 multiretry;
__le32 framedup;
__le32 rtssuccess;
__le32 rtsfailure;
__le32 ackfailure;
__le32 rxfrag;
__le32 mcastrxframe;
__le32 fcserror;
__le32 txframe;
__le32 wepundecryptable;
};
struct cmd_ds_mac_control {
__le16 action;
__le16 reserved;
};
struct cmd_ds_mac_multicast_adr {
__le16 action;
__le16 nr_of_adrs;
u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
};
struct cmd_ds_802_11_authenticate {
u8 macaddr[ETH_ALEN];
u8 authtype;
u8 reserved[10];
};
struct cmd_ds_802_11_deauthenticate {
u8 macaddr[6];
__le16 reasoncode;
};
struct cmd_ds_802_11_associate {
u8 peerstaaddr[6];
__le16 capability;
__le16 listeninterval;
__le16 bcnperiod;
u8 dtimperiod;
#if 0
mrvlietypes_ssidparamset_t ssidParamSet;
mrvlietypes_phyparamset_t phyparamset;
mrvlietypes_ssparamset_t ssparamset;
mrvlietypes_ratesparamset_t ratesParamSet;
#endif
} __attribute__ ((packed));
struct cmd_ds_802_11_disassociate {
u8 destmacaddr[6];
__le16 reasoncode;
};
struct cmd_ds_802_11_associate_rsp {
struct ieeetypes_assocrsp assocRsp;
};
struct cmd_ds_802_11_ad_hoc_result {
u8 pad[3];
u8 bssid[ETH_ALEN];
};
struct cmd_ds_802_11_set_wep {
/* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
__le16 action;
/* key Index selected for Tx */
__le16 keyindex;
/* 40, 128bit or TXWEP */
u8 keytype[4];
u8 keymaterial[4][16];
};
struct cmd_ds_802_3_get_stat {
__le32 xmitok;
__le32 rcvok;
__le32 xmiterror;
__le32 rcverror;
__le32 rcvnobuffer;
__le32 rcvcrcerror;
};
struct cmd_ds_802_11_get_stat {
__le32 txfragmentcnt;
__le32 mcasttxframecnt;
__le32 failedcnt;
__le32 retrycnt;
__le32 Multipleretrycnt;
__le32 rtssuccesscnt;
__le32 rtsfailurecnt;
__le32 ackfailurecnt;
__le32 frameduplicatecnt;
__le32 rxfragmentcnt;
__le32 mcastrxframecnt;
__le32 fcserrorcnt;
__le32 bcasttxframecnt;
__le32 bcastrxframecnt;
__le32 txbeacon;
__le32 rxbeacon;
__le32 wepundecryptable;
};
struct cmd_ds_802_11_snmp_mib {
__le16 querytype;
__le16 oid;
__le16 bufsize;
u8 value[128];
};
struct cmd_ds_mac_reg_map {
__le16 buffersize;
u8 regmap[128];
__le16 reserved;
};
struct cmd_ds_bbp_reg_map {
__le16 buffersize;
u8 regmap[128];
__le16 reserved;
};
struct cmd_ds_rf_reg_map {
__le16 buffersize;
u8 regmap[64];
__le16 reserved;
};
struct cmd_ds_mac_reg_access {
__le16 action;
__le16 offset;
__le32 value;
};
struct cmd_ds_bbp_reg_access {
__le16 action;
__le16 offset;
u8 value;
u8 reserved[3];
};
struct cmd_ds_rf_reg_access {
__le16 action;
__le16 offset;
u8 value;
u8 reserved[3];
};
struct cmd_ds_802_11_radio_control {
__le16 action;
__le16 control;
};
struct cmd_ds_802_11_beacon_control {
__le16 action;
__le16 beacon_enable;
__le16 beacon_period;
};
struct cmd_ds_802_11_sleep_params {
/* ACT_GET/ACT_SET */
__le16 action;
/* Sleep clock error in ppm */
__le16 error;
/* Wakeup offset in usec */
__le16 offset;
/* Clock stabilization time in usec */
__le16 stabletime;
/* control periodic calibration */
u8 calcontrol;
/* control the use of external sleep clock */
u8 externalsleepclk;
/* reserved field, should be set to zero */
__le16 reserved;
};
struct cmd_ds_802_11_inactivity_timeout {
/* ACT_GET/ACT_SET */
__le16 action;
/* Inactivity timeout in msec */
__le16 timeout;
};
struct cmd_ds_802_11_rf_channel {
struct cmd_header hdr;
__le16 action;
__le16 channel;
__le16 rftype; /* unused */
__le16 reserved; /* unused */
u8 channellist[32]; /* unused */
};
struct cmd_ds_802_11_rssi {
/* weighting factor */
__le16 N;
__le16 reserved_0;
__le16 reserved_1;
__le16 reserved_2;
};
struct cmd_ds_802_11_rssi_rsp {
__le16 SNR;
__le16 noisefloor;
__le16 avgSNR;
__le16 avgnoisefloor;
};
struct cmd_ds_802_11_mac_address {
__le16 action;
u8 macadd[ETH_ALEN];
};
struct cmd_ds_802_11_rf_tx_power {
__le16 action;
__le16 currentlevel;
};
struct cmd_ds_802_11_rf_antenna {
__le16 action;
/* Number of antennas or 0xffff(diversity) */
__le16 antennamode;
};
struct cmd_ds_802_11_monitor_mode {
__le16 action;
__le16 mode;
};
struct cmd_ds_set_boot2_ver {
struct cmd_header hdr;
__le16 action;
__le16 version;
};
struct cmd_ds_802_11_ps_mode {
__le16 action;
__le16 nullpktinterval;
__le16 multipledtim;
__le16 reserved;
__le16 locallisteninterval;
};
struct PS_CMD_ConfirmSleep {
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
__le16 action;
__le16 reserved1;
__le16 multipledtim;
__le16 reserved;
__le16 locallisteninterval;
};
struct cmd_ds_802_11_data_rate {
struct cmd_header hdr;
__le16 action;
__le16 reserved;
u8 rates[MAX_RATES];
};
struct cmd_ds_802_11_rate_adapt_rateset {
__le16 action;
__le16 enablehwauto;
__le16 bitmap;
};
struct cmd_ds_802_11_ad_hoc_start {
u8 ssid[IW_ESSID_MAX_SIZE];
u8 bsstype;
__le16 beaconperiod;
u8 dtimperiod;
union IEEEtypes_ssparamset ssparamset;
union ieeetypes_phyparamset phyparamset;
__le16 probedelay;
__le16 capability;
u8 rates[MAX_RATES];
u8 tlv_memory_size_pad[100];
} __attribute__ ((packed));
struct adhoc_bssdesc {
u8 bssid[6];
u8 ssid[32];
u8 type;
__le16 beaconperiod;
u8 dtimperiod;
__le64 timestamp;
__le64 localtime;
union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset;
__le16 capability;
u8 rates[MAX_RATES];
/* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
* Adhoc join command and will cause a binary layout mismatch with
* the firmware
*/
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_join {
struct adhoc_bssdesc bss;
__le16 failtimeout;
__le16 probedelay;
} __attribute__ ((packed));
struct cmd_ds_802_11_enable_rsn {
__le16 action;
__le16 enable;
} __attribute__ ((packed));
struct MrvlIEtype_keyParamSet {
/* type ID */
__le16 type;
/* length of Payload */
__le16 length;
/* type of key: WEP=0, TKIP=1, AES=2 */
__le16 keytypeid;
/* key control Info specific to a keytypeid */
__le16 keyinfo;
/* length of key */
__le16 keylen;
/* key material of size keylen */
u8 key[32];
};
struct cmd_ds_802_11_key_material {
__le16 action;
struct MrvlIEtype_keyParamSet keyParamSet[2];
} __attribute__ ((packed));
struct cmd_ds_802_11_eeprom_access {
__le16 action;
/* multiple 4 */
__le16 offset;
__le16 bytecount;
u8 value;
} __attribute__ ((packed));
struct cmd_ds_802_11_tpc_cfg {
__le16 action;
u8 enable;
s8 P0;
s8 P1;
s8 P2;
u8 usesnr;
} __attribute__ ((packed));
struct cmd_ds_802_11_led_ctrl {
__le16 action;
__le16 numled;
u8 data[256];
} __attribute__ ((packed));
struct cmd_ds_802_11_pwr_cfg {
__le16 action;
u8 enable;
s8 PA_P0;
s8 PA_P1;
s8 PA_P2;
} __attribute__ ((packed));
struct cmd_ds_802_11_afc {
__le16 afc_auto;
union {
struct {
__le16 threshold;
__le16 period;
};
struct {
__le16 timing_offset; /* signed */
__le16 carrier_offset; /* signed */
};
};
} __attribute__ ((packed));
struct cmd_tx_rate_query {
__le16 txrate;
} __attribute__ ((packed));
struct cmd_ds_get_tsf {
__le64 tsfvalue;
} __attribute__ ((packed));
struct cmd_ds_bt_access {
__le16 action;
__le32 id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
} __attribute__ ((packed));
struct cmd_ds_fwt_access {
__le16 action;
__le32 id;
u8 valid;
u8 da[ETH_ALEN];
u8 dir;
u8 ra[ETH_ALEN];
__le32 ssn;
__le32 dsn;
__le32 metric;
u8 rate;
u8 hopcount;
u8 ttl;
__le32 expiration;
u8 sleepmode;
__le32 snr;
__le32 references;
u8 prec[ETH_ALEN];
} __attribute__ ((packed));
struct cmd_ds_mesh_config {
struct cmd_header hdr;
__le16 action;
__le16 channel;
__le16 type;
__le16 length;
u8 data[128]; /* last position reserved */
} __attribute__ ((packed));
struct cmd_ds_mesh_access {
struct cmd_header hdr;
__le16 action;
__le32 data[32]; /* last position reserved */
} __attribute__ ((packed));
/* Number of stats counters returned by the firmware */
#define MESH_STATS_NUM 8
struct cmd_ds_command {
/* command header */
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
/* command Body */
union {
struct cmd_ds_802_11_ps_mode psmode;
struct cmd_ds_802_11_scan scan;
struct cmd_ds_802_11_scan_rsp scanresp;
struct cmd_ds_mac_control macctrl;
struct cmd_ds_802_11_associate associate;
struct cmd_ds_802_11_deauthenticate deauth;
struct cmd_ds_802_11_set_wep wep;
struct cmd_ds_802_11_ad_hoc_start ads;
struct cmd_ds_802_11_reset reset;
struct cmd_ds_802_11_ad_hoc_result result;
struct cmd_ds_802_11_get_log glog;
struct cmd_ds_802_11_authenticate auth;
struct cmd_ds_802_11_get_stat gstat;
struct cmd_ds_802_3_get_stat gstat_8023;
struct cmd_ds_802_11_snmp_mib smib;
struct cmd_ds_802_11_rf_tx_power txp;
struct cmd_ds_802_11_rf_antenna rant;
struct cmd_ds_802_11_monitor_mode monitor;
struct cmd_ds_802_11_rate_adapt_rateset rateset;
struct cmd_ds_mac_multicast_adr madr;
struct cmd_ds_802_11_ad_hoc_join adj;
struct cmd_ds_802_11_radio_control radio;
struct cmd_ds_802_11_rf_channel rfchannel;
struct cmd_ds_802_11_rssi rssi;
struct cmd_ds_802_11_rssi_rsp rssirsp;
struct cmd_ds_802_11_disassociate dassociate;
struct cmd_ds_802_11_mac_address macadd;
struct cmd_ds_802_11_enable_rsn enbrsn;
struct cmd_ds_802_11_key_material keymaterial;
struct cmd_ds_mac_reg_access macreg;
struct cmd_ds_bbp_reg_access bbpreg;
struct cmd_ds_rf_reg_access rfreg;
struct cmd_ds_802_11_eeprom_access rdeeprom;
struct cmd_ds_802_11d_domain_info domaininfo;
struct cmd_ds_802_11d_domain_info domaininforesp;
struct cmd_ds_802_11_sleep_params sleep_params;
struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
struct cmd_ds_802_11_tpc_cfg tpccfg;
struct cmd_ds_802_11_pwr_cfg pwrcfg;
struct cmd_ds_802_11_afc afc;
struct cmd_ds_802_11_led_ctrl ledgpio;
struct cmd_tx_rate_query txrate;
struct cmd_ds_bt_access bt;
struct cmd_ds_fwt_access fwt;
struct cmd_ds_get_tsf gettsf;
struct cmd_ds_802_11_subscribe_event subscribe_event;
struct cmd_ds_802_11_beacon_control bcn_ctrl;
} params;
} __attribute__ ((packed));
#endif

View File

@ -0,0 +1,973 @@
/*
Driver for the Marvell 8385 based compact flash WLAN cards.
(C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/netdevice.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <linux/io.h>
#define DRV_NAME "libertas_cs"
#include "decl.h"
#include "defs.h"
#include "dev.h"
/********************************************************************/
/* Module stuff */
/********************************************************************/
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
MODULE_LICENSE("GPL");
/********************************************************************/
/* Data structures */
/********************************************************************/
struct if_cs_card {
struct pcmcia_device *p_dev;
struct lbs_private *priv;
void __iomem *iobase;
};
/********************************************************************/
/* Hardware access */
/********************************************************************/
/* This define enables wrapper functions which allow you
to dump all register accesses. You normally won't this,
except for development */
/* #define DEBUG_IO */
#ifdef DEBUG_IO
static int debug_output = 0;
#else
/* This way the compiler optimizes the printk's away */
#define debug_output 0
#endif
static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
{
unsigned int val = ioread8(card->iobase + reg);
if (debug_output)
printk(KERN_INFO "##inb %08x<%02x\n", reg, val);
return val;
}
static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
{
unsigned int val = ioread16(card->iobase + reg);
if (debug_output)
printk(KERN_INFO "##inw %08x<%04x\n", reg, val);
return val;
}
static inline void if_cs_read16_rep(
struct if_cs_card *card,
uint reg,
void *buf,
unsigned long count)
{
if (debug_output)
printk(KERN_INFO "##insw %08x<(0x%lx words)\n",
reg, count);
ioread16_rep(card->iobase + reg, buf, count);
}
static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
{
if (debug_output)
printk(KERN_INFO "##outb %08x>%02x\n", reg, val);
iowrite8(val, card->iobase + reg);
}
static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
{
if (debug_output)
printk(KERN_INFO "##outw %08x>%04x\n", reg, val);
iowrite16(val, card->iobase + reg);
}
static inline void if_cs_write16_rep(
struct if_cs_card *card,
uint reg,
void *buf,
unsigned long count)
{
if (debug_output)
printk(KERN_INFO "##outsw %08x>(0x%lx words)\n",
reg, count);
iowrite16_rep(card->iobase + reg, buf, count);
}
/*
* I know that polling/delaying is frowned upon. However, this procedure
* with polling is needed while downloading the firmware. At this stage,
* the hardware does unfortunately not create any interrupts.
*
* Fortunately, this function is never used once the firmware is in
* the card. :-)
*
* As a reference, see the "Firmware Specification v5.1", page 18
* and 19. I did not follow their suggested timing to the word,
* but this works nice & fast anyway.
*/
static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
{
int i;
for (i = 0; i < 1000; i++) {
u8 val = if_cs_read8(card, addr);
if (val == reg)
return i;
udelay(500);
}
return -ETIME;
}
/* Host control registers and their bit definitions */
#define IF_CS_H_STATUS 0x00000000
#define IF_CS_H_STATUS_TX_OVER 0x0001
#define IF_CS_H_STATUS_RX_OVER 0x0002
#define IF_CS_H_STATUS_DNLD_OVER 0x0004
#define IF_CS_H_INT_CAUSE 0x00000002
#define IF_CS_H_IC_TX_OVER 0x0001
#define IF_CS_H_IC_RX_OVER 0x0002
#define IF_CS_H_IC_DNLD_OVER 0x0004
#define IF_CS_H_IC_POWER_DOWN 0x0008
#define IF_CS_H_IC_HOST_EVENT 0x0010
#define IF_CS_H_IC_MASK 0x001f
#define IF_CS_H_INT_MASK 0x00000004
#define IF_CS_H_IM_MASK 0x001f
#define IF_CS_H_WRITE_LEN 0x00000014
#define IF_CS_H_WRITE 0x00000016
#define IF_CS_H_CMD_LEN 0x00000018
#define IF_CS_H_CMD 0x0000001A
#define IF_CS_C_READ_LEN 0x00000024
#define IF_CS_H_READ 0x00000010
/* Card control registers and their bit definitions */
#define IF_CS_C_STATUS 0x00000020
#define IF_CS_C_S_TX_DNLD_RDY 0x0001
#define IF_CS_C_S_RX_UPLD_RDY 0x0002
#define IF_CS_C_S_CMD_DNLD_RDY 0x0004
#define IF_CS_C_S_CMD_UPLD_RDY 0x0008
#define IF_CS_C_S_CARDEVENT 0x0010
#define IF_CS_C_S_MASK 0x001f
#define IF_CS_C_S_STATUS_MASK 0x7f00
/* The following definitions should be the same as the MRVDRV_ ones */
#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
#endif
#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
#endif
#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
#endif
#define IF_CS_C_INT_CAUSE 0x00000022
#define IF_CS_C_IC_MASK 0x001f
#define IF_CS_C_SQ_READ_LOW 0x00000028
#define IF_CS_C_SQ_HELPER_OK 0x10
#define IF_CS_C_CMD_LEN 0x00000030
#define IF_CS_C_CMD 0x00000012
#define IF_CS_SCRATCH 0x0000003F
/********************************************************************/
/* Interrupts */
/********************************************************************/
static inline void if_cs_enable_ints(struct if_cs_card *card)
{
lbs_deb_enter(LBS_DEB_CS);
if_cs_write16(card, IF_CS_H_INT_MASK, 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_H_INT_MASK, IF_CS_H_IM_MASK);
}
static irqreturn_t if_cs_interrupt(int irq, void *data)
{
struct if_cs_card *card = data;
u16 int_cause;
lbs_deb_enter(LBS_DEB_CS);
int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
if(int_cause == 0x0) {
/* Not for us */
return IRQ_NONE;
} else if (int_cause == 0xffff) {
/* Read in junk, the card has probably been removed */
card->priv->surpriseremoved = 1;
} else {
if (int_cause & IF_CS_H_IC_TX_OVER)
lbs_host_to_card_done(card->priv);
/* clear interrupt */
if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
}
spin_lock(&card->priv->driver_lock);
lbs_interrupt(card->priv);
spin_unlock(&card->priv->driver_lock);
return IRQ_HANDLED;
}
/********************************************************************/
/* I/O */
/********************************************************************/
/*
* Called from if_cs_host_to_card to send a command to the hardware
*/
static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
{
struct if_cs_card *card = (struct if_cs_card *)priv->card;
int ret = -1;
int loops = 0;
lbs_deb_enter(LBS_DEB_CS);
/* Is hardware ready? */
while (1) {
u16 val = if_cs_read16(card, IF_CS_C_STATUS);
if (val & IF_CS_C_S_CMD_DNLD_RDY)
break;
if (++loops > 100) {
lbs_pr_err("card not ready for commands\n");
goto done;
}
mdelay(1);
}
if_cs_write16(card, IF_CS_H_CMD_LEN, nb);
if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2);
/* Are we supposed to transfer an odd amount of bytes? */
if (nb & 1)
if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]);
/* "Assert the download over interrupt command in the Host
* status register" */
if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
/* "Assert the download over interrupt command in the Card
* interrupt case register" */
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
/*
* Called from if_cs_host_to_card to send a data to the hardware
*/
static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
{
struct if_cs_card *card = (struct if_cs_card *)priv->card;
lbs_deb_enter(LBS_DEB_CS);
if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
/* write even number of bytes, then odd byte if necessary */
if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2);
if (nb & 1)
if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]);
if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
lbs_deb_leave(LBS_DEB_CS);
}
/*
* Get the command result out of the card.
*/
static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
{
int ret = -1;
u16 val;
lbs_deb_enter(LBS_DEB_CS);
/* is hardware ready? */
val = if_cs_read16(priv->card, IF_CS_C_STATUS);
if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) {
lbs_pr_err("card not ready for CMD\n");
goto out;
}
*len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
goto out;
}
/* read even number of bytes, then odd byte if necessary */
if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16));
if (*len & 1)
data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
/* This is a workaround for a firmware that reports too much
* bytes */
*len -= 8;
ret = 0;
out:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
return ret;
}
static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
{
struct sk_buff *skb = NULL;
u16 len;
u8 *data;
lbs_deb_enter(LBS_DEB_CS);
len = if_cs_read16(priv->card, IF_CS_C_READ_LEN);
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
priv->stats.rx_dropped++;
printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
goto dat_err;
}
//TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
if (!skb)
goto out;
skb_put(skb, len);
skb_reserve(skb, 2);/* 16 byte align */
data = skb->data;
/* read even number of bytes, then odd byte if necessary */
if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16));
if (len & 1)
data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ);
dat_err:
if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER);
if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER);
out:
lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
return skb;
}
/********************************************************************/
/* Firmware */
/********************************************************************/
/*
* Tries to program the helper firmware.
*
* Return 0 on success
*/
static int if_cs_prog_helper(struct if_cs_card *card)
{
int ret = 0;
int sent = 0;
u8 scratch;
const struct firmware *fw;
lbs_deb_enter(LBS_DEB_CS);
scratch = if_cs_read8(card, IF_CS_SCRATCH);
/* "If the value is 0x5a, the firmware is already
* downloaded successfully"
*/
if (scratch == 0x5a)
goto done;
/* "If the value is != 00, it is invalid value of register */
if (scratch != 0x00) {
ret = -ENODEV;
goto done;
}
/* TODO: make firmware file configurable */
ret = request_firmware(&fw, "libertas_cs_helper.fw",
&handle_to_dev(card->p_dev));
if (ret) {
lbs_pr_err("can't load helper firmware\n");
ret = -ENODEV;
goto done;
}
lbs_deb_cs("helper size %td\n", fw->size);
/* "Set the 5 bytes of the helper image to 0" */
/* Not needed, this contains an ARM branch instruction */
for (;;) {
/* "the number of bytes to send is 256" */
int count = 256;
int remain = fw->size - sent;
if (remain < count)
count = remain;
/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
__LINE__, sent, fw->size); */
/* "write the number of bytes to be sent to the I/O Command
* write length register" */
if_cs_write16(card, IF_CS_H_CMD_LEN, count);
/* "write this to I/O Command port register as 16 bit writes */
if (count)
if_cs_write16_rep(card, IF_CS_H_CMD,
&fw->data[sent],
count >> 1);
/* "Assert the download over interrupt command in the Host
* status register" */
if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
/* "Assert the download over interrupt command in the Card
* interrupt case register" */
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
/* "The host polls the Card Status register ... for 50 ms before
declaring a failure */
ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
IF_CS_C_S_CMD_DNLD_RDY);
if (ret < 0) {
lbs_pr_err("can't download helper at 0x%x, ret %d\n",
sent, ret);
goto done;
}
if (count == 0)
break;
sent += count;
}
release_firmware(fw);
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
static int if_cs_prog_real(struct if_cs_card *card)
{
const struct firmware *fw;
int ret = 0;
int retry = 0;
int len = 0;
int sent;
lbs_deb_enter(LBS_DEB_CS);
/* TODO: make firmware file configurable */
ret = request_firmware(&fw, "libertas_cs.fw",
&handle_to_dev(card->p_dev));
if (ret) {
lbs_pr_err("can't load firmware\n");
ret = -ENODEV;
goto done;
}
lbs_deb_cs("fw size %td\n", fw->size);
ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
if (ret < 0) {
int i;
lbs_pr_err("helper firmware doesn't answer\n");
for (i = 0; i < 0x50; i += 2)
printk(KERN_INFO "## HS %02x: %04x\n",
i, if_cs_read16(card, i));
goto err_release;
}
for (sent = 0; sent < fw->size; sent += len) {
len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
__LINE__, sent, fw->size); */
if (len & 1) {
retry++;
lbs_pr_info("odd, need to retry this firmware block\n");
} else {
retry = 0;
}
if (retry > 20) {
lbs_pr_err("could not download firmware\n");
ret = -ENODEV;
goto err_release;
}
if (retry) {
sent -= len;
}
if_cs_write16(card, IF_CS_H_CMD_LEN, len);
if_cs_write16_rep(card, IF_CS_H_CMD,
&fw->data[sent],
(len+1) >> 1);
if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
IF_CS_C_S_CMD_DNLD_RDY);
if (ret < 0) {
lbs_pr_err("can't download firmware at 0x%x\n", sent);
goto err_release;
}
}
ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
if (ret < 0) {
lbs_pr_err("firmware download failed\n");
goto err_release;
}
ret = 0;
goto done;
err_release:
release_firmware(fw);
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
/********************************************************************/
/* Callback functions for libertas.ko */
/********************************************************************/
/* Send commands or data packets to the card */
static int if_cs_host_to_card(struct lbs_private *priv,
u8 type,
u8 *buf,
u16 nb)
{
int ret = -1;
lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
switch (type) {
case MVMS_DAT:
priv->dnld_sent = DNLD_DATA_SENT;
if_cs_send_data(priv, buf, nb);
ret = 0;
break;
case MVMS_CMD:
priv->dnld_sent = DNLD_CMD_SENT;
ret = if_cs_send_cmd(priv, buf, nb);
break;
default:
lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type);
}
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg)
{
struct if_cs_card *card = (struct if_cs_card *)priv->card;
int ret = 0;
u16 int_cause;
u8 *cmdbuf;
*ireg = 0;
lbs_deb_enter(LBS_DEB_CS);
if (priv->surpriseremoved)
goto out;
int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
*ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
if (!*ireg)
goto sbi_get_int_status_exit;
sbi_get_int_status_exit:
/* is there a data packet for us? */
if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
struct sk_buff *skb = if_cs_receive_data(priv);
lbs_process_rxed_packet(priv, skb);
*ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
}
if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
priv->dnld_sent = DNLD_RES_RECEIVED;
}
/* Card has a command result for us */
if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
spin_lock(&priv->driver_lock);
if (!priv->cur_cmd) {
cmdbuf = priv->upld_buf;
priv->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY;
} else {
cmdbuf = (u8 *) priv->cur_cmd->cmdbuf;
}
ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len);
spin_unlock(&priv->driver_lock);
if (ret < 0)
lbs_pr_err("could not receive cmd from card\n");
}
out:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->hisregcpy);
return ret;
}
static int if_cs_read_event_cause(struct lbs_private *priv)
{
lbs_deb_enter(LBS_DEB_CS);
priv->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
return 0;
}
/********************************************************************/
/* Card Services */
/********************************************************************/
/*
* After a card is removed, if_cs_release() will unregister the
* device, and release the PCMCIA configuration. If the device is
* still open, this will be postponed until it is closed.
*/
static void if_cs_release(struct pcmcia_device *p_dev)
{
struct if_cs_card *card = p_dev->priv;
lbs_deb_enter(LBS_DEB_CS);
pcmcia_disable_device(p_dev);
free_irq(p_dev->irq.AssignedIRQ, card);
if (card->iobase)
ioport_unmap(card->iobase);
lbs_deb_leave(LBS_DEB_CS);
}
/*
* This creates an "instance" of the driver, allocating local data
* structures for one device. The device is registered with Card
* Services.
*
* The dev_link structure is initialized, but we don't actually
* configure the card at this point -- we wait until we receive a card
* insertion event.
*/
static int if_cs_probe(struct pcmcia_device *p_dev)
{
int ret = -ENOMEM;
struct lbs_private *priv;
struct if_cs_card *card;
/* CIS parsing */
tuple_t tuple;
cisparse_t parse;
cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
cistpl_io_t *io = &cfg->io;
u_char buf[64];
lbs_deb_enter(LBS_DEB_CS);
card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
if (!card) {
lbs_pr_err("error in kzalloc\n");
goto out;
}
card->p_dev = p_dev;
p_dev->priv = card;
p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
p_dev->irq.Handler = NULL;
p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
p_dev->conf.Attributes = 0;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
tuple.Attributes = 0;
tuple.TupleData = buf;
tuple.TupleDataMax = sizeof(buf);
tuple.TupleOffset = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
(ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
(ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)
{
lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
goto out1;
}
p_dev->conf.ConfigIndex = cfg->index;
/* Do we need to allocate an interrupt? */
if (cfg->irq.IRQInfo1) {
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
}
/* IO window settings */
if (cfg->io.nwin != 1) {
lbs_pr_err("wrong CIS (check number of IO windows)\n");
ret = -ENODEV;
goto out1;
}
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
p_dev->io.BasePort1 = io->win[0].base;
p_dev->io.NumPorts1 = io->win[0].len;
/* This reserves IO space but doesn't actually enable it */
ret = pcmcia_request_io(p_dev, &p_dev->io);
if (ret) {
lbs_pr_err("error in pcmcia_request_io\n");
goto out1;
}
/*
* Allocate an interrupt line. Note that this does not assign
* a handler to the interrupt, unless the 'Handler' member of
* the irq structure is initialized.
*/
if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) {
ret = pcmcia_request_irq(p_dev, &p_dev->irq);
if (ret) {
lbs_pr_err("error in pcmcia_request_irq\n");
goto out1;
}
}
/* Initialize io access */
card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1);
if (!card->iobase) {
lbs_pr_err("error in ioport_map\n");
ret = -EIO;
goto out1;
}
/*
* This actually configures the PCMCIA socket -- setting up
* the I/O windows and the interrupt mapping, and putting the
* card and host interface into "Memory and IO" mode.
*/
ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
if (ret) {
lbs_pr_err("error in pcmcia_request_configuration\n");
goto out2;
}
/* Finally, report what we've done */
lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n",
p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,
p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
/* Load the firmware early, before calling into libertas.ko */
ret = if_cs_prog_helper(card);
if (ret == 0)
ret = if_cs_prog_real(card);
if (ret)
goto out2;
/* Make this card known to the libertas driver */
priv = lbs_add_card(card, &p_dev->dev);
if (!priv) {
ret = -ENOMEM;
goto out2;
}
/* Store pointers to our call-back functions */
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_cs_host_to_card;
priv->hw_get_int_status = if_cs_get_int_status;
priv->hw_read_event_cause = if_cs_read_event_cause;
priv->fw_ready = 1;
/* Now actually get the IRQ */
ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt,
IRQF_SHARED, DRV_NAME, card);
if (ret) {
lbs_pr_err("error in request_irq\n");
goto out3;
}
/* Clear any interrupt cause that happend while sending
* firmware/initializing card */
if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK);
if_cs_enable_ints(card);
/* And finally bring the card up */
if (lbs_start_card(priv) != 0) {
lbs_pr_err("could not activate card\n");
goto out3;
}
ret = 0;
goto out;
out3:
lbs_remove_card(priv);
out2:
ioport_unmap(card->iobase);
out1:
pcmcia_disable_device(p_dev);
out:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
/*
* This deletes a driver "instance". The device is de-registered with
* Card Services. If it has been released, all local data structures
* are freed. Otherwise, the structures will be freed when the device
* is released.
*/
static void if_cs_detach(struct pcmcia_device *p_dev)
{
struct if_cs_card *card = p_dev->priv;
lbs_deb_enter(LBS_DEB_CS);
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
if_cs_disable_ints(card);
if_cs_release(p_dev);
kfree(card);
lbs_deb_leave(LBS_DEB_CS);
}
/********************************************************************/
/* Module initialization */
/********************************************************************/
static struct pcmcia_device_id if_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
static struct pcmcia_driver lbs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = DRV_NAME,
},
.probe = if_cs_probe,
.remove = if_cs_detach,
.id_table = if_cs_ids,
};
static int __init if_cs_init(void)
{
int ret;
lbs_deb_enter(LBS_DEB_CS);
ret = pcmcia_register_driver(&lbs_driver);
lbs_deb_leave(LBS_DEB_CS);
return ret;
}
static void __exit if_cs_exit(void)
{
lbs_deb_enter(LBS_DEB_CS);
pcmcia_unregister_driver(&lbs_driver);
lbs_deb_leave(LBS_DEB_CS);
}
module_init(if_cs_init);
module_exit(if_cs_exit);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
/*
* linux/drivers/net/wireless/libertas/if_sdio.h
*
* Copyright 2007 Pierre Ossman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
#ifndef _LBS_IF_SDIO_H
#define _LBS_IF_SDIO_H
#define IF_SDIO_IOPORT 0x00
#define IF_SDIO_H_INT_MASK 0x04
#define IF_SDIO_H_INT_OFLOW 0x08
#define IF_SDIO_H_INT_UFLOW 0x04
#define IF_SDIO_H_INT_DNLD 0x02
#define IF_SDIO_H_INT_UPLD 0x01
#define IF_SDIO_H_INT_STATUS 0x05
#define IF_SDIO_H_INT_RSR 0x06
#define IF_SDIO_H_INT_STATUS2 0x07
#define IF_SDIO_RD_BASE 0x10
#define IF_SDIO_STATUS 0x20
#define IF_SDIO_IO_RDY 0x08
#define IF_SDIO_CIS_RDY 0x04
#define IF_SDIO_UL_RDY 0x02
#define IF_SDIO_DL_RDY 0x01
#define IF_SDIO_C_INT_MASK 0x24
#define IF_SDIO_C_INT_STATUS 0x28
#define IF_SDIO_C_INT_RSR 0x2C
#define IF_SDIO_SCRATCH 0x34
#define IF_SDIO_SCRATCH_OLD 0x80fe
#define IF_SDIO_FIRMWARE_OK 0xfedc
#define IF_SDIO_EVENT 0x80fc
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,108 @@
#ifndef _LBS_IF_USB_H
#define _LBS_IF_USB_H
#include <linux/wait.h>
#include <linux/timer.h>
struct lbs_private;
/**
* This file contains definition for USB interface.
*/
#define CMD_TYPE_REQUEST 0xF00DFACE
#define CMD_TYPE_DATA 0xBEADC0DE
#define CMD_TYPE_INDICATION 0xBEEFFACE
#define IPFIELD_ALIGN_OFFSET 2
#define BOOT_CMD_FW_BY_USB 0x01
#define BOOT_CMD_FW_IN_EEPROM 0x02
#define BOOT_CMD_UPDATE_BOOT2 0x03
#define BOOT_CMD_UPDATE_FW 0x04
#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
struct bootcmdstr
{
__le32 u32magicnumber;
u8 u8cmd_tag;
u8 au8dumy[11];
};
#define BOOT_CMD_RESP_OK 0x0001
#define BOOT_CMD_RESP_FAIL 0x0000
struct bootcmdrespStr
{
__le32 u32magicnumber;
u8 u8cmd_tag;
u8 u8result;
u8 au8dumy[2];
};
/* read callback private data */
struct read_cb_info {
struct usb_card_rec *cardp;
struct sk_buff *skb;
};
/** USB card description structure*/
struct usb_card_rec {
struct usb_device *udev;
struct urb *rx_urb, *tx_urb;
struct lbs_private *priv;
struct read_cb_info rinfo;
int bulk_in_size;
u8 bulk_in_endpointAddr;
u8 *bulk_out_buffer;
int bulk_out_size;
u8 bulk_out_endpointAddr;
const struct firmware *fw;
struct timer_list fw_timeout;
wait_queue_head_t fw_wq;
u8 CRC_OK;
u32 fwseqnum;
u32 lastseqnum;
u32 totalbytes;
u32 fwlastblksent;
u8 fwdnldover;
u8 fwfinalblk;
u8 surprise_removed;
u32 usb_event_cause;
u8 usb_int_cause;
s8 bootcmdresp;
};
/** fwheader */
struct fwheader {
__le32 dnldcmd;
__le32 baseaddr;
__le32 datalength;
__le32 CRC;
};
#define FW_MAX_DATA_BLK_SIZE 600
/** FWData */
struct FWData {
struct fwheader fwheader;
__le32 seqnum;
u8 data[FW_MAX_DATA_BLK_SIZE];
};
/** fwsyncheader */
struct fwsyncheader {
__le32 cmd;
__le32 seqnum;
};
#define FW_HAS_DATA_TO_RECV 0x00000001
#define FW_HAS_LAST_BLOCK 0x00000004
#define FW_DATA_XMIT_SIZE \
sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32)
#endif

894
package/libertas/src/join.c Normal file
View File

@ -0,0 +1,894 @@
/**
* Functions implementing wlan infrastructure and adhoc join routines,
* IOCTL handlers as well as command preperation and response routines
* for sending adhoc start, adhoc join, and association commands
* to the firmware.
*/
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/etherdevice.h>
#include <net/iw_handler.h>
#include "host.h"
#include "decl.h"
#include "join.h"
#include "dev.h"
#include "assoc.h"
/* The firmware needs certain bits masked out of the beacon-derviced capability
* field when associating/joining to BSSs.
*/
#define CAPINFO_MASK (~(0xda00))
/**
* @brief This function finds common rates between rate1 and card rates.
*
* It will fill common rates in rate1 as output if found.
*
* NOTE: Setting the MSB of the basic rates need to be taken
* care, either before or after calling this function
*
* @param priv A pointer to struct lbs_private structure
* @param rate1 the buffer which keeps input and output
* @param rate1_size the size of rate1 buffer; new size of buffer on return
*
* @return 0 or -1
*/
static int get_common_rates(struct lbs_private *priv,
u8 *rates,
u16 *rates_size)
{
u8 *card_rates = lbs_bg_rates;
size_t num_card_rates = sizeof(lbs_bg_rates);
int ret = 0, i, j;
u8 tmp[30];
size_t tmp_size = 0;
/* For each rate in card_rates that exists in rate1, copy to tmp */
for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
for (j = 0; rates[j] && (j < *rates_size); j++) {
if (rates[j] == card_rates[i])
tmp[tmp_size++] = card_rates[i];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
if (!priv->auto_rate) {
for (i = 0; i < tmp_size; i++) {
if (tmp[i] == priv->cur_rate)
goto done;
}
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
ret = -1;
goto done;
}
ret = 0;
done:
memset(rates, 0, *rates_size);
*rates_size = min_t(int, tmp_size, *rates_size);
memcpy(rates, tmp, *rates_size);
return ret;
}
/**
* @brief Sets the MSB on basic rates as the firmware requires
*
* Scan through an array and set the MSB for basic data rates.
*
* @param rates buffer of data rates
* @param len size of buffer
*/
static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
{
int i;
for (i = 0; i < len; i++) {
if (rates[i] == 0x02 || rates[i] == 0x04 ||
rates[i] == 0x0b || rates[i] == 0x16)
rates[i] |= 0x80;
}
}
/**
* @brief Unsets the MSB on basic rates
*
* Scan through an array and unset the MSB for basic data rates.
*
* @param rates buffer of data rates
* @param len size of buffer
*/
void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
{
int i;
for (i = 0; i < len; i++)
rates[i] &= 0x7f;
}
/**
* @brief Associate to a specific BSS discovered in a scan
*
* @param priv A pointer to struct lbs_private structure
* @param pbssdesc Pointer to the BSS descriptor to associate with.
*
* @return 0-success, otherwise fail
*/
int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req)
{
int ret;
lbs_deb_enter(LBS_DEB_ASSOC);
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
0, CMD_OPTION_WAITFORRSP,
0, assoc_req->bss.bssid);
if (ret)
goto done;
/* set preamble to firmware */
if ( (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
&& (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
else
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
lbs_set_radio_control(priv);
ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
/**
* @brief Start an Adhoc Network
*
* @param priv A pointer to struct lbs_private structure
* @param adhocssid The ssid of the Adhoc Network
* @return 0--success, -1--fail
*/
int lbs_start_adhoc_network(struct lbs_private *priv,
struct assoc_request *assoc_req)
{
int ret = 0;
priv->adhoccreate = 1;
if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
lbs_deb_join("AdhocStart: Short preamble\n");
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
} else {
lbs_deb_join("AdhocStart: Long preamble\n");
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
}
lbs_set_radio_control(priv);
lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
return ret;
}
/**
* @brief Join an adhoc network found in a previous scan
*
* @param priv A pointer to struct lbs_private structure
* @param pbssdesc Pointer to a BSS descriptor found in a previous scan
* to attempt to join
*
* @return 0--success, -1--fail
*/
int lbs_join_adhoc_network(struct lbs_private *priv,
struct assoc_request *assoc_req)
{
struct bss_descriptor * bss = &assoc_req->bss;
int ret = 0;
lbs_deb_join("%s: Current SSID '%s', ssid length %u\n",
__func__,
escape_essid(priv->curbssparams.ssid,
priv->curbssparams.ssid_len),
priv->curbssparams.ssid_len);
lbs_deb_join("%s: requested ssid '%s', ssid length %u\n",
__func__, escape_essid(bss->ssid, bss->ssid_len),
bss->ssid_len);
/* check if the requested SSID is already joined */
if ( priv->curbssparams.ssid_len
&& !lbs_ssid_cmp(priv->curbssparams.ssid,
priv->curbssparams.ssid_len,
bss->ssid, bss->ssid_len)
&& (priv->mode == IW_MODE_ADHOC)
&& (priv->connect_status == LBS_CONNECTED)) {
union iwreq_data wrqu;
lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
"current, not attempting to re-join");
/* Send the re-association event though, because the association
* request really was successful, even if just a null-op.
*/
memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
goto out;
}
/* Use shortpreamble only when both creator and card supports
short preamble */
if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
|| !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
lbs_deb_join("AdhocJoin: Long preamble\n");
priv->preamble = CMD_TYPE_LONG_PREAMBLE;
} else {
lbs_deb_join("AdhocJoin: Short preamble\n");
priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
}
lbs_set_radio_control(priv);
lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
priv->adhoccreate = 0;
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
0, CMD_OPTION_WAITFORRSP,
OID_802_11_SSID, assoc_req);
out:
return ret;
}
int lbs_stop_adhoc_network(struct lbs_private *priv)
{
return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
0, CMD_OPTION_WAITFORRSP, 0, NULL);
}
/**
* @brief Send Deauthentication Request
*
* @param priv A pointer to struct lbs_private structure
* @return 0--success, -1--fail
*/
int lbs_send_deauthentication(struct lbs_private *priv)
{
return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
0, CMD_OPTION_WAITFORRSP, 0, NULL);
}
/**
* @brief This function prepares command of authenticate.
*
* @param priv A pointer to struct lbs_private structure
* @param cmd A pointer to cmd_ds_command structure
* @param pdata_buf Void cast of pointer to a BSSID to authenticate with
*
* @return 0 or -1
*/
int lbs_cmd_80211_authenticate(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf)
{
struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
int ret = -1;
u8 *bssid = pdata_buf;
DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+ S_DS_GEN);
/* translate auth mode to 802.11 defined wire value */
switch (priv->secinfo.auth_mode) {
case IW_AUTH_ALG_OPEN_SYSTEM:
pauthenticate->authtype = 0x00;
break;
case IW_AUTH_ALG_SHARED_KEY:
pauthenticate->authtype = 0x01;
break;
case IW_AUTH_ALG_LEAP:
pauthenticate->authtype = 0x80;
break;
default:
lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
priv->secinfo.auth_mode);
goto out;
}
memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
print_mac(mac, bssid), pauthenticate->authtype);
ret = 0;
out:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
return ret;
}
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
struct cmd_ds_command *cmd)
{
struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
lbs_deb_enter(LBS_DEB_JOIN);
cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
S_DS_GEN);
/* set AP MAC address */
memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN);
/* Reason code 3 = Station is leaving */
#define REASON_CODE_STA_LEAVING 3
dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
lbs_deb_leave(LBS_DEB_JOIN);
return 0;
}
int lbs_cmd_80211_associate(struct lbs_private *priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
int ret = 0;
struct assoc_request * assoc_req = pdata_buf;
struct bss_descriptor * bss = &assoc_req->bss;
u8 *pos;
u16 tmpcap, tmplen;
struct mrvlietypes_ssidparamset *ssid;
struct mrvlietypes_phyparamset *phy;
struct mrvlietypes_ssparamset *ss;
struct mrvlietypes_ratesparamset *rates;
struct mrvlietypes_rsnparamset *rsn;
lbs_deb_enter(LBS_DEB_ASSOC);
pos = (u8 *) passo;
if (!priv) {
ret = -1;
goto done;
}
cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
pos += sizeof(passo->peerstaaddr);
/* set the listen interval */
passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
pos += sizeof(passo->capability);
pos += sizeof(passo->listeninterval);
pos += sizeof(passo->bcnperiod);
pos += sizeof(passo->dtimperiod);
ssid = (struct mrvlietypes_ssidparamset *) pos;
ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
tmplen = bss->ssid_len;
ssid->header.len = cpu_to_le16(tmplen);
memcpy(ssid->ssid, bss->ssid, tmplen);
pos += sizeof(ssid->header) + tmplen;
phy = (struct mrvlietypes_phyparamset *) pos;
phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
tmplen = sizeof(phy->fh_ds.dsparamset);
phy->header.len = cpu_to_le16(tmplen);
memcpy(&phy->fh_ds.dsparamset,
&bss->phyparamset.dsparamset.currentchan,
tmplen);
pos += sizeof(phy->header) + tmplen;
ss = (struct mrvlietypes_ssparamset *) pos;
ss->header.type = cpu_to_le16(TLV_TYPE_CF);
tmplen = sizeof(ss->cf_ibss.cfparamset);
ss->header.len = cpu_to_le16(tmplen);
pos += sizeof(ss->header) + tmplen;
rates = (struct mrvlietypes_ratesparamset *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
memcpy(&rates->rates, &bss->rates, MAX_RATES);
tmplen = MAX_RATES;
if (get_common_rates(priv, rates->rates, &tmplen)) {
ret = -1;
goto done;
}
pos += sizeof(rates->header) + tmplen;
rates->header.len = cpu_to_le16(tmplen);
lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
/* Copy the infra. association rates into Current BSS state structure */
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates.
*/
lbs_set_basic_rate_flags(rates->rates, tmplen);
if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
rsn = (struct mrvlietypes_rsnparamset *) pos;
/* WPA_IE or WPA2_IE */
rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
tmplen = (u16) assoc_req->wpa_ie[1];
rsn->header.len = cpu_to_le16(tmplen);
memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
sizeof(rsn->header) + tmplen);
pos += sizeof(rsn->header) + tmplen;
}
/* update curbssparams */
priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
ret = -1;
goto done;
}
cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
/* set the capability info */
tmpcap = (bss->capability & CAPINFO_MASK);
if (bss->mode == IW_MODE_INFRA)
tmpcap |= WLAN_CAPABILITY_ESS;
passo->capability = cpu_to_le16(tmpcap);
lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
int ret = 0;
int cmdappendsize = 0;
struct assoc_request * assoc_req = pdata_buf;
u16 tmpcap = 0;
size_t ratesize = 0;
lbs_deb_enter(LBS_DEB_JOIN);
if (!priv) {
ret = -1;
goto done;
}
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
/*
* Fill in the parameters for 2 data structures:
* 1. cmd_ds_802_11_ad_hoc_start command
* 2. priv->scantable[i]
*
* Driver will fill up SSID, bsstype,IBSS param, Physical Param,
* probe delay, and cap info.
*
* Firmware will fill up beacon period, DTIM, Basic rates
* and operational rates.
*/
memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
assoc_req->ssid_len);
/* set the BSS type */
adhs->bsstype = CMD_BSS_TYPE_IBSS;
priv->mode = IW_MODE_ADHOC;
if (priv->beacon_period == 0)
priv->beacon_period = MRVDRV_BEACON_INTERVAL;
adhs->beaconperiod = cpu_to_le16(priv->beacon_period);
/* set Physical param set */
#define DS_PARA_IE_ID 3
#define DS_PARA_IE_LEN 1
adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
WARN_ON(!assoc_req->channel);
lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
assoc_req->channel);
adhs->phyparamset.dsparamset.currentchan = assoc_req->channel;
/* set IBSS param set */
#define IBSS_PARA_IE_ID 6
#define IBSS_PARA_IE_LEN 2
adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
adhs->ssparamset.ibssparamset.atimwindow = 0;
/* set capability info */
tmpcap = WLAN_CAPABILITY_IBSS;
if (assoc_req->secinfo.wep_enabled) {
lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
tmpcap |= WLAN_CAPABILITY_PRIVACY;
} else {
lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
}
adhs->capability = cpu_to_le16(tmpcap);
/* probedelay */
adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
memset(adhs->rates, 0, sizeof(adhs->rates));
ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates));
memcpy(adhs->rates, lbs_bg_rates, ratesize);
/* Copy the ad-hoc creating rates into Current BSS state structure */
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize);
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates.
*/
lbs_set_basic_rate_flags(adhs->rates, ratesize);
lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
if (lbs_create_dnld_countryinfo_11d(priv)) {
lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
ret = -1;
goto done;
}
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) +
S_DS_GEN + cmdappendsize);
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
return ret;
}
int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv,
struct cmd_ds_command *cmd)
{
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
cmd->size = cpu_to_le16(S_DS_GEN);
return 0;
}
int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
struct assoc_request * assoc_req = pdata_buf;
struct bss_descriptor *bss = &assoc_req->bss;
int cmdappendsize = 0;
int ret = 0;
u16 ratesize = 0;
DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
sizeof(union ieeetypes_phyparamset));
memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
sizeof(union IEEEtypes_ssparamset));
join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
bss->capability, CAPINFO_MASK);
/* information on BSSID descriptor passed to FW */
lbs_deb_join(
"ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
print_mac(mac, join_cmd->bss.bssid),
join_cmd->bss.ssid);
/* failtimeout */
join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
/* probedelay */
join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
priv->curbssparams.channel = bss->channel;
/* Copy Data rates from the rates recorded in scan response */
memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
memcpy(join_cmd->bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
ret = -1;
goto done;
}
/* Copy the ad-hoc creating rates into Current BSS state structure */
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize);
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates.
*/
lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
join_cmd->bss.ssparamset.ibssparamset.atimwindow =
cpu_to_le16(bss->atimwindow);
if (assoc_req->secinfo.wep_enabled) {
u16 tmp = le16_to_cpu(join_cmd->bss.capability);
tmp |= WLAN_CAPABILITY_PRIVACY;
join_cmd->bss.capability = cpu_to_le16(tmp);
}
if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
/* wake up first */
__le32 Localpsmode;
Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
ret = lbs_prepare_and_send_command(priv,
CMD_802_11_PS_MODE,
CMD_ACT_SET,
0, 0, &Localpsmode);
if (ret) {
ret = -1;
goto done;
}
}
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
ret = -1;
goto done;
}
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) +
S_DS_GEN + cmdappendsize);
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
return ret;
}
int lbs_ret_80211_associate(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
int ret = 0;
union iwreq_data wrqu;
struct ieeetypes_assocrsp *passocrsp;
struct bss_descriptor * bss;
u16 status_code;
lbs_deb_enter(LBS_DEB_ASSOC);
if (!priv->in_progress_assoc_req) {
lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
ret = -1;
goto done;
}
bss = &priv->in_progress_assoc_req->bss;
passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
/*
* Older FW versions map the IEEE 802.11 Status Code in the association
* response to the following values returned in passocrsp->statuscode:
*
* IEEE Status Code Marvell Status Code
* 0 -> 0x0000 ASSOC_RESULT_SUCCESS
* 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
* 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
* 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
* 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
* others -> 0x0003 ASSOC_RESULT_REFUSED
*
* Other response codes:
* 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
* 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
* association response from the AP)
*/
status_code = le16_to_cpu(passocrsp->statuscode);
switch (status_code) {
case 0x00:
break;
case 0x01:
lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
break;
case 0x02:
lbs_deb_assoc("ASSOC_RESP: internal timer "
"expired while waiting for the AP\n");
break;
case 0x03:
lbs_deb_assoc("ASSOC_RESP: association "
"refused by AP\n");
break;
case 0x04:
lbs_deb_assoc("ASSOC_RESP: authentication "
"refused by AP\n");
break;
default:
lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
" unknown\n", status_code);
break;
}
if (status_code) {
lbs_mac_event_disconnected(priv);
ret = -1;
goto done;
}
lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
le16_to_cpu(resp->size) - S_DS_GEN);
/* Send a Media Connected event, according to the Spec */
priv->connect_status = LBS_CONNECTED;
/* Update current SSID and BSSID */
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
priv->curbssparams.ssid_len = bss->ssid_len;
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
lbs_deb_assoc("ASSOC_RESP: currentpacketfilter is 0x%x\n",
priv->currentpacketfilter);
priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
priv->nextSNRNF = 0;
priv->numSNRNF = 0;
netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev);
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
int lbs_ret_80211_disassociate(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
lbs_deb_enter(LBS_DEB_JOIN);
lbs_mac_event_disconnected(priv);
lbs_deb_leave(LBS_DEB_JOIN);
return 0;
}
int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
int ret = 0;
u16 command = le16_to_cpu(resp->command);
u16 result = le16_to_cpu(resp->result);
struct cmd_ds_802_11_ad_hoc_result *padhocresult;
union iwreq_data wrqu;
struct bss_descriptor *bss;
DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
padhocresult = &resp->params.result;
lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size));
lbs_deb_join("ADHOC_RESP: command = %x\n", command);
lbs_deb_join("ADHOC_RESP: result = %x\n", result);
if (!priv->in_progress_assoc_req) {
lbs_deb_join("ADHOC_RESP: no in-progress association request\n");
ret = -1;
goto done;
}
bss = &priv->in_progress_assoc_req->bss;
/*
* Join result code 0 --> SUCCESS
*/
if (result) {
lbs_deb_join("ADHOC_RESP: failed\n");
if (priv->connect_status == LBS_CONNECTED) {
lbs_mac_event_disconnected(priv);
}
ret = -1;
goto done;
}
/*
* Now the join cmd should be successful
* If BSSID has changed use SSID to compare instead of BSSID
*/
lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
escape_essid(bss->ssid, bss->ssid_len));
/* Send a Media Connected event, according to the Spec */
priv->connect_status = LBS_CONNECTED;
if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
/* Update the created network descriptor with the new BSSID */
memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
}
/* Set the BSSID from the joined/started descriptor */
memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
/* Set the new SSID to current SSID */
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
priv->curbssparams.ssid_len = bss->ssid_len;
netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev);
memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel);
lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
print_mac(mac, padhocresult->bssid));
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
return ret;
}
int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
lbs_deb_enter(LBS_DEB_JOIN);
lbs_mac_event_disconnected(priv);
lbs_deb_leave(LBS_DEB_JOIN);
return 0;
}

View File

@ -0,0 +1,53 @@
/**
* Interface for the wlan infrastructure and adhoc join routines
*
* Driver interface functions and type declarations for the join module
* implemented in join.c. Process all start/join requests for
* both adhoc and infrastructure networks
*/
#ifndef _LBS_JOIN_H
#define _LBS_JOIN_H
#include "defs.h"
#include "dev.h"
struct cmd_ds_command;
int lbs_cmd_80211_authenticate(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv,
struct cmd_ds_command *cmd);
int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
struct cmd_ds_command *cmd);
int lbs_cmd_80211_associate(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_ret_80211_disassociate(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_ret_80211_associate(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_start_adhoc_network(struct lbs_private *priv,
struct assoc_request * assoc_req);
int lbs_join_adhoc_network(struct lbs_private *priv,
struct assoc_request * assoc_req);
int lbs_stop_adhoc_network(struct lbs_private *priv);
int lbs_send_deauthentication(struct lbs_private *priv);
int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req);
void lbs_unset_basic_rate_flags(u8 *rates, size_t len);
#endif

1474
package/libertas/src/main.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
#include <net/ieee80211_radiotap.h>
struct tx_radiotap_hdr {
struct ieee80211_radiotap_header hdr;
u8 rate;
u8 txpower;
u8 rts_retries;
u8 data_retries;
#if 0
u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
#endif
} __attribute__ ((packed));
#define TX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
(1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \
(1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \
0)
#define IEEE80211_FC_VERSION_MASK 0x0003
#define IEEE80211_FC_TYPE_MASK 0x000c
#define IEEE80211_FC_TYPE_MGT 0x0000
#define IEEE80211_FC_TYPE_CTL 0x0004
#define IEEE80211_FC_TYPE_DATA 0x0008
#define IEEE80211_FC_SUBTYPE_MASK 0x00f0
#define IEEE80211_FC_TOFROMDS_MASK 0x0300
#define IEEE80211_FC_TODS_MASK 0x0100
#define IEEE80211_FC_FROMDS_MASK 0x0200
#define IEEE80211_FC_NODS 0x0000
#define IEEE80211_FC_TODS 0x0100
#define IEEE80211_FC_FROMDS 0x0200
#define IEEE80211_FC_DSTODS 0x0300
struct rx_radiotap_hdr {
struct ieee80211_radiotap_header hdr;
u8 flags;
u8 rate;
u16 chan_freq;
u16 chan_flags;
u8 antenna;
u8 antsignal;
u16 rx_flags;
#if 0
u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18];
#endif
} __attribute__ ((packed));
#define RX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
(1 << IEEE80211_RADIOTAP_RX_FLAGS) | \
0)

400
package/libertas/src/rx.c Normal file
View File

@ -0,0 +1,400 @@
/**
* This file contains the handling of RX in wlan driver.
*/
#include <linux/etherdevice.h>
#include <linux/types.h>
#include "hostcmd.h"
#include "radiotap.h"
#include "decl.h"
#include "dev.h"
#include "wext.h"
struct eth803hdr {
u8 dest_addr[6];
u8 src_addr[6];
u16 h803_len;
} __attribute__ ((packed));
struct rfc1042hdr {
u8 llc_dsap;
u8 llc_ssap;
u8 llc_ctrl;
u8 snap_oui[3];
u16 snap_type;
} __attribute__ ((packed));
struct rxpackethdr {
struct rxpd rx_pd;
struct eth803hdr eth803_hdr;
struct rfc1042hdr rfc1042_hdr;
} __attribute__ ((packed));
struct rx80211packethdr {
struct rxpd rx_pd;
void *eth80211_hdr;
} __attribute__ ((packed));
static int process_rxed_802_11_packet(struct lbs_private *priv,
struct sk_buff *skb);
/**
* @brief This function computes the avgSNR .
*
* @param priv A pointer to struct lbs_private structure
* @return avgSNR
*/
static u8 lbs_getavgsnr(struct lbs_private *priv)
{
u8 i;
u16 temp = 0;
if (priv->numSNRNF == 0)
return 0;
for (i = 0; i < priv->numSNRNF; i++)
temp += priv->rawSNR[i];
return (u8) (temp / priv->numSNRNF);
}
/**
* @brief This function computes the AvgNF
*
* @param priv A pointer to struct lbs_private structure
* @return AvgNF
*/
static u8 lbs_getavgnf(struct lbs_private *priv)
{
u8 i;
u16 temp = 0;
if (priv->numSNRNF == 0)
return 0;
for (i = 0; i < priv->numSNRNF; i++)
temp += priv->rawNF[i];
return (u8) (temp / priv->numSNRNF);
}
/**
* @brief This function save the raw SNR/NF to our internel buffer
*
* @param priv A pointer to struct lbs_private structure
* @param prxpd A pointer to rxpd structure of received packet
* @return n/a
*/
static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
{
if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
priv->numSNRNF++;
priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
priv->nextSNRNF++;
if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
priv->nextSNRNF = 0;
return;
}
/**
* @brief This function computes the RSSI in received packet.
*
* @param priv A pointer to struct lbs_private structure
* @param prxpd A pointer to rxpd structure of received packet
* @return n/a
*/
static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
{
lbs_deb_enter(LBS_DEB_RX);
lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
lbs_save_rawSNRNF(priv, p_rx_pd);
priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
priv->NF[TYPE_RXPD][TYPE_NOAVG]);
priv->RSSI[TYPE_RXPD][TYPE_AVG] =
CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
lbs_deb_leave(LBS_DEB_RX);
}
/**
* @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);
skb->ip_summed = CHECKSUM_NONE;
if (priv->monitormode != LBS_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 (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");
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 (priv->auto_rate)
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);
priv->stats.rx_bytes += skb->len;
priv->stats.rx_packets++;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
/**
* @brief This function converts Tx/Rx rates from the Marvell WLAN format
* (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
*
* @param rate Input rate
* @return Output Rate (0 if invalid)
*/
static u8 convert_mv_rate_to_radiotap(u8 rate)
{
switch (rate) {
case 0: /* 1 Mbps */
return 2;
case 1: /* 2 Mbps */
return 4;
case 2: /* 5.5 Mbps */
return 11;
case 3: /* 11 Mbps */
return 22;
/* case 4: reserved */
case 5: /* 6 Mbps */
return 12;
case 6: /* 9 Mbps */
return 18;
case 7: /* 12 Mbps */
return 24;
case 8: /* 18 Mbps */
return 36;
case 9: /* 24 Mbps */
return 48;
case 10: /* 36 Mbps */
return 72;
case 11: /* 48 Mbps */
return 96;
case 12: /* 54 Mbps */
return 108;
}
lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
return 0;
}
/**
* @brief This function processes a received 802.11 packet and forwards it
* to kernel/upper layer
*
* @param priv A pointer to struct lbs_private
* @param skb A pointer to skb which includes the received packet
* @return 0 or -1
*/
static int process_rxed_802_11_packet(struct lbs_private *priv,
struct sk_buff *skb)
{
int ret = 0;
struct rx80211packethdr *p_rx_pkt;
struct rxpd *prxpd;
struct rx_radiotap_hdr radiotap_hdr;
struct rx_radiotap_hdr *pradiotap_hdr;
lbs_deb_enter(LBS_DEB_RX);
p_rx_pkt = (struct rx80211packethdr *) skb->data;
prxpd = &p_rx_pkt->rx_pd;
// lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
lbs_deb_rx("rx err: frame received with bad length\n");
priv->stats.rx_length_errors++;
ret = -EINVAL;
kfree(skb);
goto done;
}
/*
* Check rxpd status and update 802.3 stat,
*/
if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
//lbs_deb_rx("rx err: frame received with bad status\n");
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 */
/* 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__);
ret = -ENOMEM;
kfree_skb(skb);
goto done;
}
pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
/* Take the data rate from the rxpd structure
* only if the rate is auto
*/
if (priv->auto_rate)
priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
lbs_compute_rssi(priv, prxpd);
lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
priv->stats.rx_bytes += skb->len;
priv->stats.rx_packets++;
skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
netif_rx(skb);
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
return ret;
}

1643
package/libertas/src/scan.c Normal file

File diff suppressed because it is too large Load Diff

205
package/libertas/src/scan.h Normal file
View File

@ -0,0 +1,205 @@
/**
* Interface for the wlan network scan routines
*
* Driver interface functions and type declarations for the scan module
* implemented in scan.c.
*/
#ifndef _LBS_SCAN_H
#define _LBS_SCAN_H
#include <net/ieee80211.h>
#include "hostcmd.h"
/**
* @brief Maximum number of channels that can be sent in a setuserscan ioctl
*
* @sa lbs_ioctl_user_scan_cfg
*/
#define LBS_IOCTL_USER_SCAN_CHAN_MAX 50
//! Infrastructure BSS scan type in lbs_scan_cmd_config
#define LBS_SCAN_BSS_TYPE_BSS 1
//! Adhoc BSS scan type in lbs_scan_cmd_config
#define LBS_SCAN_BSS_TYPE_IBSS 2
//! Adhoc or Infrastructure BSS scan type in lbs_scan_cmd_config, no filter
#define LBS_SCAN_BSS_TYPE_ANY 3
/**
* @brief Structure used internally in the wlan driver to configure a scan.
*
* Sent to the command processing module to configure the firmware
* scan command prepared by lbs_cmd_80211_scan.
*
* @sa lbs_scan_networks
*
*/
struct lbs_scan_cmd_config {
/**
* @brief BSS type to be sent in the firmware command
*
* Field can be used to restrict the types of networks returned in the
* scan. valid settings are:
*
* - LBS_SCAN_BSS_TYPE_BSS (infrastructure)
* - LBS_SCAN_BSS_TYPE_IBSS (adhoc)
* - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
*/
u8 bsstype;
/**
* @brief Specific BSSID used to filter scan results in the firmware
*/
u8 bssid[ETH_ALEN];
/**
* @brief length of TLVs sent in command starting at tlvBuffer
*/
int tlvbufferlen;
/**
* @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
*
* @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t
* @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t
*/
u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here
};
/**
* @brief IOCTL channel sub-structure sent in lbs_ioctl_user_scan_cfg
*
* Multiple instances of this structure are included in the IOCTL command
* to configure a instance of a scan on the specific channel.
*/
struct lbs_ioctl_user_scan_chan {
u8 channumber; //!< channel Number to scan
u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1
u8 scantype; //!< Scan type: Active = 0, Passive = 1
u16 scantime; //!< Scan duration in milliseconds; if 0 default used
};
/**
* @brief IOCTL input structure to configure an immediate scan cmd to firmware
*
* Used in the setuserscan (LBS_SET_USER_SCAN) private ioctl. Specifies
* a number of parameters to be used in general for the scan as well
* as a channel list (lbs_ioctl_user_scan_chan) for each scan period
* desired.
*
* @sa lbs_set_user_scan_ioctl
*/
struct lbs_ioctl_user_scan_cfg {
/**
* @brief BSS type to be sent in the firmware command
*
* Field can be used to restrict the types of networks returned in the
* scan. valid settings are:
*
* - LBS_SCAN_BSS_TYPE_BSS (infrastructure)
* - LBS_SCAN_BSS_TYPE_IBSS (adhoc)
* - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
*/
u8 bsstype;
/**
* @brief BSSID filter sent in the firmware command to limit the results
*/
u8 bssid[ETH_ALEN];
/* Clear existing scan results matching this BSSID */
u8 clear_bssid;
/**
* @brief SSID filter sent in the firmware command to limit the results
*/
char ssid[IW_ESSID_MAX_SIZE];
u8 ssid_len;
/* Clear existing scan results matching this SSID */
u8 clear_ssid;
};
/**
* @brief Structure used to store information for each beacon/probe response
*/
struct bss_descriptor {
u8 bssid[ETH_ALEN];
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
u16 capability;
/* receive signal strength in dBm */
long rssi;
u32 channel;
u16 beaconperiod;
u32 atimwindow;
/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
u8 mode;
/* zero-terminated array of supported data rates */
u8 rates[MAX_RATES + 1];
unsigned long last_scanned;
union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset;
struct ieeetypes_countryinfofullset countryinfo;
u8 wpa_ie[MAX_WPA_IE_LEN];
size_t wpa_ie_len;
u8 rsn_ie[MAX_WPA_IE_LEN];
size_t rsn_ie_len;
u8 mesh;
struct list_head list;
};
int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
u8 *ssid, u8 ssid_len, u8 *bssid, u8 mode,
int channel);
struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
u8 *bssid, u8 mode);
int lbs_find_best_network_ssid(struct lbs_private *priv, u8 *out_ssid,
u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode);
int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
u8 ssid_len, u8 clear_ssid);
int lbs_cmd_80211_scan(struct lbs_private *priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
int lbs_ret_80211_scan(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_scan_networks(struct lbs_private *priv,
const struct lbs_ioctl_user_scan_cfg *puserscanin,
int full_scan);
struct ifreq;
struct iw_point;
struct iw_param;
struct iw_request_info;
int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra);
int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra);
void lbs_scan_worker(struct work_struct *work);
#endif

221
package/libertas/src/tx.c Normal file
View File

@ -0,0 +1,221 @@
/**
* This file contains the handling of TX in wlan driver.
*/
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include "hostcmd.h"
#include "radiotap.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "wext.h"
/**
* @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
* units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
*
* @param rate Input rate
* @return Output Rate (0 if invalid)
*/
static u32 convert_radiotap_rate_to_mv(u8 rate)
{
switch (rate) {
case 2: /* 1 Mbps */
return 0 | (1 << 4);
case 4: /* 2 Mbps */
return 1 | (1 << 4);
case 11: /* 5.5 Mbps */
return 2 | (1 << 4);
case 22: /* 11 Mbps */
return 3 | (1 << 4);
case 12: /* 6 Mbps */
return 4 | (1 << 4);
case 18: /* 9 Mbps */
return 5 | (1 << 4);
case 24: /* 12 Mbps */
return 6 | (1 << 4);
case 36: /* 18 Mbps */
return 7 | (1 << 4);
case 48: /* 24 Mbps */
return 8 | (1 << 4);
case 72: /* 36 Mbps */
return 9 | (1 << 4);
case 96: /* 48 Mbps */
return 10 | (1 << 4);
case 108: /* 54 Mbps */
return 11 | (1 << 4);
}
return 0;
}
/**
* @brief This function checks the conditions and sends packet to IF
* layer if everything is ok.
*
* @param priv A pointer to struct lbs_private structure
* @param skb A pointer to skb which includes TX packet
* @return 0 or -1
*/
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);
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' */
priv->stats.tx_dropped++;
priv->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 (dev == priv->rtap_net_dev) {
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));
if (dev == priv->mesh_dev)
txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
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__);
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
if (priv->monitormode != LBS_MONITOR_OFF) {
/* 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;
}
/**
* @brief This function sends to the host the last transmitted packet,
* filling the radiotap headers with transmission information.
*
* @param priv A pointer to struct lbs_private structure
* @param status A 32 bit value containing transmission status.
*
* @returns void
*/
void lbs_send_tx_feedback(struct lbs_private *priv)
{
struct tx_radiotap_hdr *radiotap_hdr;
u32 status = priv->eventcause;
int txfail;
int try_count;
if (priv->monitormode == LBS_MONITOR_OFF ||
priv->currenttxskb == NULL)
return;
radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
txfail = (status >> 24);
#if 0
/* The version of roofnet that we've tested does not use this yet
* But it may be used in the future.
*/
if (txfail)
radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL;
#endif
try_count = (status >> 16) & 0xff;
radiotap_hdr->data_retries = (try_count) ?
(1 + priv->txretrycount - try_count) : 0;
priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
priv->rtap_net_dev);
netif_rx(priv->currenttxskb);
priv->currenttxskb = NULL;
if (priv->connect_status == LBS_CONNECTED)
netif_wake_queue(priv->dev);
if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
netif_wake_queue(priv->mesh_dev);
}
EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);

View File

@ -0,0 +1,242 @@
/**
* This header file contains definition for global types
*/
#ifndef _LBS_TYPES_H_
#define _LBS_TYPES_H_
#include <linux/if_ether.h>
#include <asm/byteorder.h>
struct ieeetypes_cfparamset {
u8 elementid;
u8 len;
u8 cfpcnt;
u8 cfpperiod;
__le16 cfpmaxduration;
__le16 cfpdurationremaining;
} __attribute__ ((packed));
struct ieeetypes_ibssparamset {
u8 elementid;
u8 len;
__le16 atimwindow;
} __attribute__ ((packed));
union IEEEtypes_ssparamset {
struct ieeetypes_cfparamset cfparamset;
struct ieeetypes_ibssparamset ibssparamset;
} __attribute__ ((packed));
struct ieeetypes_fhparamset {
u8 elementid;
u8 len;
__le16 dwelltime;
u8 hopset;
u8 hoppattern;
u8 hopindex;
} __attribute__ ((packed));
struct ieeetypes_dsparamset {
u8 elementid;
u8 len;
u8 currentchan;
} __attribute__ ((packed));
union ieeetypes_phyparamset {
struct ieeetypes_fhparamset fhparamset;
struct ieeetypes_dsparamset dsparamset;
} __attribute__ ((packed));
struct ieeetypes_assocrsp {
__le16 capability;
__le16 statuscode;
__le16 aid;
u8 iebuffer[1];
} __attribute__ ((packed));
/** TLV type ID definition */
#define PROPRIETARY_TLV_BASE_ID 0x0100
/* Terminating TLV type */
#define MRVL_TERMINATE_TLV_ID 0xffff
#define TLV_TYPE_SSID 0x0000
#define TLV_TYPE_RATES 0x0001
#define TLV_TYPE_PHY_FH 0x0002
#define TLV_TYPE_PHY_DS 0x0003
#define TLV_TYPE_CF 0x0004
#define TLV_TYPE_IBSS 0x0006
#define TLV_TYPE_DOMAIN 0x0007
#define TLV_TYPE_POWER_CAPABILITY 0x0021
#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8)
#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9)
#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
#define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11)
#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12)
#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13)
#define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14)
#define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15)
#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
#define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17)
#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
/** TLV related data structures*/
struct mrvlietypesheader {
__le16 type;
__le16 len;
} __attribute__ ((packed));
struct mrvlietypes_data {
struct mrvlietypesheader header;
u8 Data[1];
} __attribute__ ((packed));
struct mrvlietypes_ratesparamset {
struct mrvlietypesheader header;
u8 rates[1];
} __attribute__ ((packed));
struct mrvlietypes_ssidparamset {
struct mrvlietypesheader header;
u8 ssid[1];
} __attribute__ ((packed));
struct mrvlietypes_wildcardssidparamset {
struct mrvlietypesheader header;
u8 MaxSsidlength;
u8 ssid[1];
} __attribute__ ((packed));
struct chanscanmode {
#ifdef __BIG_ENDIAN_BITFIELD
u8 reserved_2_7:6;
u8 disablechanfilt:1;
u8 passivescan:1;
#else
u8 passivescan:1;
u8 disablechanfilt:1;
u8 reserved_2_7:6;
#endif
} __attribute__ ((packed));
struct chanscanparamset {
u8 radiotype;
u8 channumber;
struct chanscanmode chanscanmode;
__le16 minscantime;
__le16 maxscantime;
} __attribute__ ((packed));
struct mrvlietypes_chanlistparamset {
struct mrvlietypesheader header;
struct chanscanparamset chanscanparam[1];
} __attribute__ ((packed));
struct cfparamset {
u8 cfpcnt;
u8 cfpperiod;
__le16 cfpmaxduration;
__le16 cfpdurationremaining;
} __attribute__ ((packed));
struct ibssparamset {
__le16 atimwindow;
} __attribute__ ((packed));
struct mrvlietypes_ssparamset {
struct mrvlietypesheader header;
union {
struct cfparamset cfparamset[1];
struct ibssparamset ibssparamset[1];
} cf_ibss;
} __attribute__ ((packed));
struct fhparamset {
__le16 dwelltime;
u8 hopset;
u8 hoppattern;
u8 hopindex;
} __attribute__ ((packed));
struct dsparamset {
u8 currentchan;
} __attribute__ ((packed));
struct mrvlietypes_phyparamset {
struct mrvlietypesheader header;
union {
struct fhparamset fhparamset[1];
struct dsparamset dsparamset[1];
} fh_ds;
} __attribute__ ((packed));
struct mrvlietypes_rsnparamset {
struct mrvlietypesheader header;
u8 rsnie[1];
} __attribute__ ((packed));
struct mrvlietypes_tsftimestamp {
struct mrvlietypesheader header;
__le64 tsftable[1];
} __attribute__ ((packed));
/** Local Power capability */
struct mrvlietypes_powercapability {
struct mrvlietypesheader header;
s8 minpower;
s8 maxpower;
} __attribute__ ((packed));
/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
struct mrvlietypes_thresholds {
struct mrvlietypesheader header;
u8 value;
u8 freq;
} __attribute__ ((packed));
struct mrvlietypes_beaconsmissed {
struct mrvlietypesheader header;
u8 beaconmissed;
u8 reserved;
} __attribute__ ((packed));
struct mrvlietypes_numprobes {
struct mrvlietypesheader header;
__le16 numprobes;
} __attribute__ ((packed));
struct mrvlietypes_bcastprobe {
struct mrvlietypesheader header;
__le16 bcastprobe;
} __attribute__ ((packed));
struct mrvlietypes_numssidprobe {
struct mrvlietypesheader header;
__le16 numssidprobe;
} __attribute__ ((packed));
struct led_pin {
u8 led;
u8 pin;
} __attribute__ ((packed));
struct mrvlietypes_ledgpio {
struct mrvlietypesheader header;
struct led_pin ledpin[1];
} __attribute__ ((packed));
#endif

2213
package/libertas/src/wext.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
/**
* This file contains definition for IOCTL call.
*/
#ifndef _LBS_WEXT_H_
#define _LBS_WEXT_H_
/** lbs_ioctl_regrdwr */
struct lbs_ioctl_regrdwr {
/** Which register to access */
u16 whichreg;
/** Read or Write */
u16 action;
u32 offset;
u16 NOB;
u32 value;
};
#define LBS_MONITOR_OFF 0
extern struct iw_handler_def lbs_handler_def;
extern struct iw_handler_def mesh_handler_def;
#endif

View File

@ -0,0 +1,11 @@
# Copyright (C) 2006 OpenWrt.org
config interface loopback
option ifname lo
option proto static
option ipaddr 127.0.0.1
option netmask 255.0.0.0
config interface wlan
option ifname eth0
option proto dhcp

View File

@ -25,19 +25,14 @@ CONFIG_BATTERY_OLPC=y
# CONFIG_BINFMT_AOUT is not set
CONFIG_BINFMT_MISC=y
CONFIG_BITREVERSE=y
CONFIG_BLK_DEV_CRYPTOLOOP=y
CONFIG_BLK_DEV_GENERIC=m
CONFIG_BLK_DEV_IDE=m
CONFIG_BLK_DEV_IDEDISK=m
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_SC1200=m
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
@ -57,22 +52,21 @@ CONFIG_COMPAT_VDSO=y
# CONFIG_CRC_ITU_T is not set
# CONFIG_CRYPTO_AES is not set
# CONFIG_CRYPTO_AES_586 is not set
CONFIG_CRYPTO_ALGAPI=y
# CONFIG_CRYPTO_ANUBIS is not set
# CONFIG_CRYPTO_ARC4 is not set
CONFIG_CRYPTO_BLKCIPHER=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_CBC is not set
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_ECB is not set
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_HW is not set
# CONFIG_CRYPTO_KHAZAD is not set
CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
@ -82,6 +76,7 @@ CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_TEST is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_TWOFISH_586 is not set
@ -242,7 +237,6 @@ CONFIG_INSTRUMENTATION=y
# CONFIG_IP_NF_MATCH_AH is not set
# CONFIG_IP_NF_MATCH_ECN is not set
# CONFIG_IP_NF_MATCH_IPP2P is not set
# CONFIG_IP_NF_MATCH_LAYER7 is not set
# CONFIG_IP_NF_MATCH_OWNER is not set
# CONFIG_IP_NF_MATCH_RECENT is not set
# CONFIG_IP_NF_MATCH_TIME is not set

View File

@ -1,4 +1,4 @@
\ Boot script
" u:\boot\vmlinuz" to boot-device
" block2mtd.block2mtd=/dev/sda2,65536,rootfs root=/dev/mtdblock1 rootfstype=squashfs init=/etc/preinit rootdelay=5 noinitrd console=tty0" to boot-file
" block2mtd.block2mtd=/dev/sda2,65536,rootfs root=/dev/mtdblock1 rootfstype=squashfs init=/etc/preinit rootdelay=5 noinitrd console=tty0 quiet" to boot-file
boot