* adding network config for olpc * adding libertas * config issue * quiet mode for bootloader
SVN-Revision: 9768
This commit is contained in:
parent
b03f211098
commit
7eeb4e6f7f
41 changed files with 19037 additions and 12 deletions
56
package/libertas/Makefile
Normal file
56
package/libertas/Makefile
Normal 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))
|
33
package/libertas/files/LICENSE
Normal file
33
package/libertas/files/LICENSE
Normal 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
700
package/libertas/src/11d.c
Normal 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
105
package/libertas/src/11d.h
Normal 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
62
package/libertas/src/:0
Normal 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))
|
16
package/libertas/src/LICENSE
Normal file
16
package/libertas/src/LICENSE
Normal 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.
|
||||||
|
|
15
package/libertas/src/Makefile
Normal file
15
package/libertas/src/Makefile
Normal 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
229
package/libertas/src/README
Normal 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.
|
||||||
|
|
||||||
|
==============================================================================
|
766
package/libertas/src/assoc.c
Normal file
766
package/libertas/src/assoc.c
Normal 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;
|
||||||
|
}
|
12
package/libertas/src/assoc.h
Normal file
12
package/libertas/src/assoc.h
Normal 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
2233
package/libertas/src/cmd.c
Normal file
File diff suppressed because it is too large
Load diff
38
package/libertas/src/cmd.h
Normal file
38
package/libertas/src/cmd.h
Normal 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 */
|
897
package/libertas/src/cmdresp.c
Normal file
897
package/libertas/src/cmdresp.c
Normal 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;
|
||||||
|
}
|
17
package/libertas/src/compat.h
Normal file
17
package/libertas/src/compat.h
Normal 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
|
1163
package/libertas/src/debugfs.c
Normal file
1163
package/libertas/src/debugfs.c
Normal file
File diff suppressed because it is too large
Load diff
10
package/libertas/src/debugfs.h
Normal file
10
package/libertas/src/debugfs.h
Normal 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
|
80
package/libertas/src/decl.h
Normal file
80
package/libertas/src/decl.h
Normal 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
379
package/libertas/src/defs.h
Normal 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
365
package/libertas/src/dev.h
Normal 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
|
172
package/libertas/src/ethtool.c
Normal file
172
package/libertas/src/ethtool.c
Normal 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, ®ctrl, 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,
|
||||||
|
®ctrl);
|
||||||
|
|
||||||
|
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
286
package/libertas/src/host.h
Normal 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
|
713
package/libertas/src/hostcmd.h
Normal file
713
package/libertas/src/hostcmd.h
Normal 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
|
973
package/libertas/src/if_cs.c
Normal file
973
package/libertas/src/if_cs.c
Normal 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);
|
1079
package/libertas/src/if_sdio.c
Normal file
1079
package/libertas/src/if_sdio.c
Normal file
File diff suppressed because it is too large
Load diff
45
package/libertas/src/if_sdio.h
Normal file
45
package/libertas/src/if_sdio.h
Normal 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
|
1043
package/libertas/src/if_usb.c
Normal file
1043
package/libertas/src/if_usb.c
Normal file
File diff suppressed because it is too large
Load diff
108
package/libertas/src/if_usb.h
Normal file
108
package/libertas/src/if_usb.h
Normal 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
894
package/libertas/src/join.c
Normal 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;
|
||||||
|
}
|
53
package/libertas/src/join.h
Normal file
53
package/libertas/src/join.h
Normal 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
1474
package/libertas/src/main.c
Normal file
File diff suppressed because it is too large
Load diff
57
package/libertas/src/radiotap.h
Normal file
57
package/libertas/src/radiotap.h
Normal 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
400
package/libertas/src/rx.c
Normal 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
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
205
package/libertas/src/scan.h
Normal 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
221
package/libertas/src/tx.c
Normal 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);
|
242
package/libertas/src/types.h
Normal file
242
package/libertas/src/types.h
Normal 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
2213
package/libertas/src/wext.c
Normal file
File diff suppressed because it is too large
Load diff
23
package/libertas/src/wext.h
Normal file
23
package/libertas/src/wext.h
Normal 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
|
11
target/linux/olpc/base-files/etc/config/network
Normal file
11
target/linux/olpc/base-files/etc/config/network
Normal 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
|
|
@ -25,19 +25,14 @@ CONFIG_BATTERY_OLPC=y
|
||||||
# CONFIG_BINFMT_AOUT is not set
|
# CONFIG_BINFMT_AOUT is not set
|
||||||
CONFIG_BINFMT_MISC=y
|
CONFIG_BINFMT_MISC=y
|
||||||
CONFIG_BITREVERSE=y
|
CONFIG_BITREVERSE=y
|
||||||
CONFIG_BLK_DEV_CRYPTOLOOP=y
|
|
||||||
CONFIG_BLK_DEV_GENERIC=m
|
CONFIG_BLK_DEV_GENERIC=m
|
||||||
CONFIG_BLK_DEV_IDE=m
|
CONFIG_BLK_DEV_IDE=m
|
||||||
CONFIG_BLK_DEV_IDEDISK=m
|
CONFIG_BLK_DEV_IDEDISK=m
|
||||||
CONFIG_BLK_DEV_IDEDMA=y
|
CONFIG_BLK_DEV_IDEDMA=y
|
||||||
CONFIG_BLK_DEV_IDEDMA_PCI=y
|
CONFIG_BLK_DEV_IDEDMA_PCI=y
|
||||||
CONFIG_BLK_DEV_IDEPCI=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_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_SC1200=m
|
||||||
CONFIG_BLK_DEV_SD=y
|
CONFIG_BLK_DEV_SD=y
|
||||||
CONFIG_BLK_DEV_SR=y
|
CONFIG_BLK_DEV_SR=y
|
||||||
|
@ -57,22 +52,21 @@ CONFIG_COMPAT_VDSO=y
|
||||||
# CONFIG_CRC_ITU_T is not set
|
# CONFIG_CRC_ITU_T is not set
|
||||||
# CONFIG_CRYPTO_AES is not set
|
# CONFIG_CRYPTO_AES is not set
|
||||||
# CONFIG_CRYPTO_AES_586 is not set
|
# CONFIG_CRYPTO_AES_586 is not set
|
||||||
CONFIG_CRYPTO_ALGAPI=y
|
|
||||||
# CONFIG_CRYPTO_ANUBIS is not set
|
# CONFIG_CRYPTO_ANUBIS is not set
|
||||||
# CONFIG_CRYPTO_ARC4 is not set
|
# CONFIG_CRYPTO_ARC4 is not set
|
||||||
CONFIG_CRYPTO_BLKCIPHER=y
|
|
||||||
# CONFIG_CRYPTO_BLOWFISH is not set
|
# CONFIG_CRYPTO_BLOWFISH is not set
|
||||||
# CONFIG_CRYPTO_CAMELLIA is not set
|
# CONFIG_CRYPTO_CAMELLIA is not set
|
||||||
# CONFIG_CRYPTO_CAST5 is not set
|
# CONFIG_CRYPTO_CAST5 is not set
|
||||||
# CONFIG_CRYPTO_CAST6 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_CRC32C is not set
|
||||||
# CONFIG_CRYPTO_DEFLATE is not set
|
# CONFIG_CRYPTO_DEFLATE is not set
|
||||||
|
# CONFIG_CRYPTO_DES is not set
|
||||||
# CONFIG_CRYPTO_ECB is not set
|
# CONFIG_CRYPTO_ECB is not set
|
||||||
# CONFIG_CRYPTO_HMAC is not set
|
# CONFIG_CRYPTO_HMAC is not set
|
||||||
# CONFIG_CRYPTO_HW is not set
|
# CONFIG_CRYPTO_HW is not set
|
||||||
# CONFIG_CRYPTO_KHAZAD 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_MD4 is not set
|
||||||
# CONFIG_CRYPTO_MD5 is not set
|
# CONFIG_CRYPTO_MD5 is not set
|
||||||
# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA256 is not set
|
||||||
# CONFIG_CRYPTO_SHA512 is not set
|
# CONFIG_CRYPTO_SHA512 is not set
|
||||||
# CONFIG_CRYPTO_TEA is not set
|
# CONFIG_CRYPTO_TEA is not set
|
||||||
|
# CONFIG_CRYPTO_TEST is not set
|
||||||
# CONFIG_CRYPTO_TGR192 is not set
|
# CONFIG_CRYPTO_TGR192 is not set
|
||||||
# CONFIG_CRYPTO_TWOFISH is not set
|
# CONFIG_CRYPTO_TWOFISH is not set
|
||||||
# CONFIG_CRYPTO_TWOFISH_586 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_AH is not set
|
||||||
# CONFIG_IP_NF_MATCH_ECN is not set
|
# CONFIG_IP_NF_MATCH_ECN is not set
|
||||||
# CONFIG_IP_NF_MATCH_IPP2P 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_OWNER is not set
|
||||||
# CONFIG_IP_NF_MATCH_RECENT is not set
|
# CONFIG_IP_NF_MATCH_RECENT is not set
|
||||||
# CONFIG_IP_NF_MATCH_TIME is not set
|
# CONFIG_IP_NF_MATCH_TIME is not set
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
\ Boot script
|
\ Boot script
|
||||||
" u:\boot\vmlinuz" to boot-device
|
" 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
|
boot
|
||||||
|
|
Loading…
Reference in a new issue