Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
9758d0f0
Commit
9758d0f0
authored
Jun 27, 2005
by
Jeff Garzik
Committed by
Jeff Garzik
Jun 27, 2005
Browse files
Options
Browse Files
Download
Plain Diff
Merge /spare/repo/netdev-2.6/ branch 'orinoco'
parents
0dd3c781
1a9fe638
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
2368 additions
and
1011 deletions
+2368
-1011
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.c
+1457
-1010
drivers/net/wireless/orinoco.h
drivers/net/wireless/orinoco.h
+29
-1
include/net/ieee80211.h
include/net/ieee80211.h
+882
-0
No files found.
drivers/net/wireless/orinoco.c
View file @
9758d0f0
...
...
@@ -46,382 +46,9 @@
* under either the MPL or the GPL. */
/*
* v0.01 -> v0.02 - 21/3/2001 - Jean II
* o Allow to use regular ethX device name instead of dldwdX
* o Warning on IBSS with ESSID=any for firmware 6.06
* o Put proper range.throughput values (optimistic)
* o IWSPY support (IOCTL and stat gather in Rx path)
* o Allow setting frequency in Ad-Hoc mode
* o Disable WEP setting if !has_wep to work on old firmware
* o Fix txpower range
* o Start adding support for Samsung/Compaq firmware
*
* v0.02 -> v0.03 - 23/3/2001 - Jean II
* o Start adding Symbol support - need to check all that
* o Fix Prism2/Symbol WEP to accept 128 bits keys
* o Add Symbol WEP (add authentication type)
* o Add Prism2/Symbol rate
* o Add PM timeout (holdover duration)
* o Enable "iwconfig eth0 key off" and friends (toggle flags)
* o Enable "iwconfig eth0 power unicast/all" (toggle flags)
* o Try with an Intel card. It report firmware 1.01, behave like
* an antiquated firmware, however on windows it says 2.00. Yuck !
* o Workaround firmware bug in allocate buffer (Intel 1.01)
* o Finish external renaming to orinoco...
* o Testing with various Wavelan firmwares
*
* v0.03 -> v0.04 - 30/3/2001 - Jean II
* o Update to Wireless 11 -> add retry limit/lifetime support
* o Tested with a D-Link DWL 650 card, fill in firmware support
* o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot)
* o Fixed the Prism2 WEP bugs that I introduced in v0.03 :-(
* It works on D-Link *only* after a tcpdump. Weird...
* And still doesn't work on Intel card. Grrrr...
* o Update the mode after a setport3
* o Add preamble setting for Symbol cards (not yet enabled)
* o Don't complain as much about Symbol cards...
*
* v0.04 -> v0.04b - 22/4/2001 - David Gibson
* o Removed the 'eth' parameter - always use ethXX as the
* interface name instead of dldwdXX. The other was racy
* anyway.
* o Clean up RID definitions in hermes.h, other cleanups
*
* v0.04b -> v0.04c - 24/4/2001 - Jean II
* o Tim Hurley <timster AT seiki.bliztech.com> reported a D-Link card
* with vendor 02 and firmware 0.08. Added in the capabilities...
* o Tested Lucent firmware 7.28, everything works...
*
* v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt
* o Spin-off Pcmcia code. This file is renamed orinoco.c,
* and orinoco_cs.c now contains only the Pcmcia specific stuff
* o Add Airport driver support on top of orinoco.c (see airport.c)
*
* v0.05 -> v0.05a - 4/5/2001 - Jean II
* o Revert to old Pcmcia code to fix breakage of Ben's changes...
*
* v0.05a -> v0.05b - 4/5/2001 - Jean II
* o add module parameter 'ignore_cis_vcc' for D-Link @ 5V
* o D-Link firmware doesn't support multicast. We just print a few
* error messages, but otherwise everything works...
* o For David : set/getport3 works fine, just upgrade iwpriv...
*
* v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt
* o Adapt airport.c to latest changes in orinoco.c
* o Remove deferred power enabling code
*
* v0.05c -> v0.05d - 5/5/2001 - Jean II
* o Workaround to SNAP decapsulate frame from Linksys AP
* original patch from : Dong Liu <dliu AT research.bell-labs.com>
* (note : the memcmp bug was mine - fixed)
* o Remove set_retry stuff, no firmware support it (bloat--).
*
* v0.05d -> v0.06 - 25/5/2001 - Jean II
* Original patch from "Hong Lin" <alin AT redhat.com>,
* "Ian Kinner" <ikinner AT redhat.com>
* and "David Smith" <dsmith AT redhat.com>
* o Init of priv->tx_rate_ctrl in firmware specific section.
* o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh !
* o Spectrum card always need cor_reset (for every reset)
* o Fix cor_reset to not lose bit 7 in the register
* o flush_stale_links to remove zombie Pcmcia instances
* o Ack previous hermes event before reset
* Me (with my little hands)
* o Allow orinoco.c to call cor_reset via priv->card_reset_handler
* o Add priv->need_card_reset to toggle this feature
* o Fix various buglets when setting WEP in Symbol firmware
* Now, encryption is fully functional on Symbol cards. Youpi !
*
* v0.06 -> v0.06b - 25/5/2001 - Jean II
* o IBSS on Symbol use port_mode = 4. Please don't ask...
*
* v0.06b -> v0.06c - 29/5/2001 - Jean II
* o Show first spy address in /proc/net/wireless for IBSS mode as well
*
* v0.06c -> v0.06d - 6/7/2001 - David Gibson
* o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus'
* wishes to reduce the number of unnecessary messages.
* o Removed bogus message on CRC error.
* o Merged fixes for v0.08 Prism 2 firmware from William Waghorn
* <willwaghorn AT yahoo.co.uk>
* o Slight cleanup/re-arrangement of firmware detection code.
*
* v0.06d -> v0.06e - 1/8/2001 - David Gibson
* o Removed some redundant global initializers (orinoco_cs.c).
* o Added some module metadata
*
* v0.06e -> v0.06f - 14/8/2001 - David Gibson
* o Wording fix to license
* o Added a 'use_alternate_encaps' module parameter for APs which need an
* oui of 00:00:00. We really need a better way of handling this, but
* the module flag is better than nothing for now.
*
* v0.06f -> v0.07 - 20/8/2001 - David Gibson
* o Removed BAP error retries from hermes_bap_seek(). For Tx we now
* let the upper layers handle the retry, we retry explicitly in the
* Rx path, but don't make as much noise about it.
* o Firmware detection cleanups.
*
* v0.07 -> v0.07a - 1/10/3001 - Jean II
* o Add code to read Symbol firmware revision, inspired by latest code
* in Spectrum24 by Lee John Keyser-Allen - Thanks Lee !
* o Thanks to Jared Valentine <hidden AT xmission.com> for "providing" me
* a 3Com card with a recent firmware, fill out Symbol firmware
* capabilities of latest rev (2.20), as well as older Symbol cards.
* o Disable Power Management in newer Symbol firmware, the API
* has changed (documentation needed).
*
* v0.07a -> v0.08 - 3/10/2001 - David Gibson
* o Fixed a possible buffer overrun found by the Stanford checker (in
* dldwd_ioctl_setiwencode()). Can only be called by root anyway, so not
* a big problem.
* o Turned has_big_wep on for Intersil cards. That's not true for all of
* them but we should at least let the capable ones try.
* o Wait for BUSY to clear at the beginning of hermes_bap_seek(). I
* realized that my assumption that the driver's serialization
* would prevent the BAP being busy on entry was possibly false, because
* things other than seeks may make the BAP busy.
* o Use "alternate" (oui 00:00:00) encapsulation by default.
* Setting use_old_encaps will mimic the old behaviour, but I think we
* will be able to eliminate this.
* o Don't try to make __initdata const (the version string). This can't
* work because of the way the __initdata sectioning works.
* o Added MODULE_LICENSE tags.
* o Support for PLX (transparent PCMCIA->PCI bridge) cards.
* o Changed to using the new type-fascist min/max.
*
* v0.08 -> v0.08a - 9/10/2001 - David Gibson
* o Inserted some missing acknowledgements/info into the Changelog.
* o Fixed some bugs in the normalization of signal level reporting.
* o Fixed bad bug in WEP key handling on Intersil and Symbol firmware,
* which led to an instant crash on big-endian machines.
*
* v0.08a -> v0.08b - 20/11/2001 - David Gibson
* o Lots of cleanup and bugfixes in orinoco_plx.c
* o Cleanup to handling of Tx rate setting.
* o Removed support for old encapsulation method.
* o Removed old "dldwd" names.
* o Split RID constants into a new file hermes_rid.h
* o Renamed RID constants to match linux-wlan-ng and prism2.o
* o Bugfixes in hermes.c
* o Poke the PLX's INTCSR register, so it actually starts
* generating interrupts. These cards might actually work now.
* o Update to wireless extensions v12 (Jean II)
* o Support for tallies and inquire command (Jean II)
* o Airport updates for newer PPC kernels (BenH)
*
* v0.08b -> v0.09 - 21/12/2001 - David Gibson
* o Some new PCI IDs for PLX cards.
* o Removed broken attempt to do ALLMULTI reception. Just use
* promiscuous mode instead
* o Preliminary work for list-AP (Jean II)
* o Airport updates from (BenH)
* o Eliminated racy hw_ready stuff
* o Fixed generation of fake events in irq handler. This should
* finally kill the EIO problems (Jean II & dgibson)
* o Fixed breakage of bitrate set/get on Agere firmware (Jean II)
*
* v0.09 -> v0.09a - 2/1/2002 - David Gibson
* o Fixed stupid mistake in multicast list handling, triggering
* a BUG()
*
* v0.09a -> v0.09b - 16/1/2002 - David Gibson
* o Fixed even stupider mistake in new interrupt handling, which
* seriously broke things on big-endian machines.
* o Removed a bunch of redundant includes and exports.
* o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c
* o Don't attempt to do hardware level multicast reception on
* Intersil firmware, just go promisc instead.
* o Typo fixed in hermes_issue_cmd()
* o Eliminated WIRELESS_SPY #ifdefs
* o Status code reported on Tx exceptions
* o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC
* interrupts, which should fix the timeouts we're seeing.
*
* v0.09b -> v0.10 - 25 Feb 2002 - David Gibson
* o Removed nested structures used for header parsing, so the
* driver should now work without hackery on ARM
* o Fix for WEP handling on Intersil (Hawk Newton)
* o Eliminated the /proc/hermes/ethXX/regs debugging file. It
* was never very useful.
* o Make Rx errors less noisy.
*
* v0.10 -> v0.11 - 5 Apr 2002 - David Gibson
* o Laid the groundwork in hermes.[ch] for devices which map
* into PCI memory space rather than IO space.
* o Fixed bug in multicast handling (cleared multicast list when
* leaving promiscuous mode).
* o Relegated Tx error messages to debug.
* o Cleaned up / corrected handling of allocation lengths.
* o Set OWNSSID in IBSS mode for WinXP interoperability (jimc).
* o Change to using alloc_etherdev() for structure allocations.
* o Check for and drop undersized packets.
* o Fixed a race in stopping/waking the queue. This should fix
* the timeout problems (Pavel Roskin)
* o Reverted to netif_wake_queue() on the ALLOC event.
* o Fixes for recent Symbol firmwares which lack AP density
* (Pavel Roskin).
*
* v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
* o Handle different register spacing, necessary for Prism 2.5
* PCI adaptors (Steve Hill).
* o Cleaned up initialization of card structures in orinoco_cs
* and airport. Removed card->priv field.
* o Make response structure optional for hermes_docmd_wait()
* Pavel Roskin)
* o Added PCI id for Nortel emobility to orinoco_plx.c.
* o Cleanup to handling of Symbol's allocation bug. (Pavel Roskin)
* o Cleanups to firmware capability detection.
* o Arrange for orinoco_pci.c to override firmware detection.
* We should be able to support the PCI Intersil cards now.
* o Cleanup handling of reset_cor and hard_reset (Pavel Roskin).
* o Remove erroneous use of USER_BAP in the TxExc handler (Jouni
* Malinen).
* o Makefile changes for better integration into David Hinds
* pcmcia-cs package.
*
* v0.11a -> v0.11b - 1 May 2002 - David Gibson
* o Better error reporting in orinoco_plx_init_one()
* o Fixed multiple bad kfree() bugs introduced by the
* alloc_orinocodev() changes.
*
* v0.11b -> v0.12 - 19 Jun 2002 - David Gibson
* o Support changing the MAC address.
* o Correct display of Intersil firmware revision numbers.
* o Entirely revised locking scheme. Should be both simpler and
* better.
* o Merged some common code in orinoco_plx, orinoco_pci and
* airport by creating orinoco_default_{open,stop,reset}()
* which are used as the dev->open, dev->stop, priv->reset
* callbacks if none are specified when alloc_orinocodev() is
* called.
* o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt().
* They didn't do anything.
*
* v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
* o Some rearrangement of code.
* o Numerous fixups to locking and rest handling, particularly
* for PCMCIA.
* o This allows open and stop net_device methods to be in
* orinoco.c now, rather than in the init modules.
* o In orinoco_cs.c link->priv now points to the struct
* net_device not to the struct orinoco_private.
* o Added a check for undersized SNAP frames, which could cause
* crashes.
*
* v0.12a -> v0.12b - 11 Jul 2002 - David Gibson
* o Fix hw->num_init testing code, so num_init is actually
* incremented.
* o Fix very stupid bug in orinoco_cs which broke compile with
* CONFIG_SMP.
* o Squashed a warning.
*
* v0.12b -> v0.12c - 26 Jul 2002 - David Gibson
* o Change to C9X style designated initializers.
* o Add support for 3Com AirConnect PCI.
* o No longer ignore the hard_reset argument to
* alloc_orinocodev(). Oops.
*
* v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
* o Revert the broken 0.12* locking scheme and go to a new yet
* simpler scheme.
* o Do firmware resets only in orinoco_init() and when waking
* the card from hard sleep.
*
* v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
* o Re-introduced full resets (via schedule_task()) on Tx
* timeout.
*
* v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
* o Minor cleanups to info frame handling. Add basic support
* for linkstatus info frames.
* o Include required kernel headers in orinoco.h, to avoid
* compile problems.
*
* v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
* o Implemented hard reset for Airport cards
* o Experimental suspend/resume implementation for orinoco_pci
* o Abolished /proc debugging support, replaced with a debugging
* iwpriv. Now it's ugly and simple instead of ugly and complex.
* o Bugfix in hermes.c if the firmware returned a record length
* of 0, we could go clobbering memory.
* o Bugfix in orinoco_stop() - it used to fail if hw_unavailable
* was set, which was usually true on PCMCIA hot removes.
* o Track LINKSTATUS messages, silently drop Tx packets before
* we are connected (avoids confusing the firmware), and only
* give LINKSTATUS printk()s if the status has changed.
*
* v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
* o Cleanup: use dev instead of priv in various places.
* o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
* if we're in the middle of a (driver initiated) hard reset.
* o Bug fix: ETH_ZLEN is supposed to include the header
* (Dionysus Blazakis & Manish Karir)
* o Convert to using workqueues instead of taskqueues (and
* backwards compatibility macros for pre 2.5.41 kernels).
* o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
* airport.c
* o New orinoco_tmd.c init module from Joerg Dorchain for
* TMD7160 based PCI to PCMCIA bridges (similar to
* orinoco_plx.c).
*
* v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
* o Make hw_unavailable a counter, rather than just a flag, this
* is necessary to avoid some races (such as a card being
* removed in the middle of orinoco_reset().
* o Restore Release/RequestConfiguration in the PCMCIA event handler
* when dealing with a driver initiated hard reset. This is
* necessary to prevent hangs due to a spurious interrupt while
* the reset is in progress.
* o Clear the 802.11 header when transmitting, even though we
* don't use it. This fixes a long standing bug on some
* firmwares, which seem to get confused if that isn't done.
* o Be less eager to de-encapsulate SNAP frames, only do so if
* the OUI is 00:00:00 or 00:00:f8, leave others alone. The old
* behaviour broke CDP (Cisco Discovery Protocol).
* o Use dev instead of priv for free_irq() as well as
* request_irq() (oops).
* o Attempt to reset rather than giving up if we get too many
* IRQs.
* o Changed semantics of __orinoco_down() so it can be called
* safely with hw_unavailable set. It also now clears the
* linkstatus (since we're going to have to reassociate).
*
* v0.13d -> v0.13e - 12 May 2003 - David Gibson
* o Support for post-2.5.68 return values from irq handler.
* o Fixed bug where underlength packets would be double counted
* in the rx_dropped statistics.
* o Provided a module parameter to suppress linkstatus messages.
*
* v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson
* o Replaced priv->connected logic with netif_carrier_on/off()
* calls.
* o Remove has_ibss_any and never set the CREATEIBSS RID when
* the ESSID is empty. Too many firmwares break if we do.
* o 2.6 merges: Replace pdev->slot_name with pci_name(), remove
* __devinitdata from PCI ID tables, use free_netdev().
* o Enabled shared-key authentication for Agere firmware (from
* Robert J. Moore <Robert.J.Moore AT allanbank.com>
* o Move netif_wake_queue() (back) to the Tx completion from the
* ALLOC event. This seems to prevent/mitigate the rolling
* error -110 problems at least on some Intersil firmwares.
* Theoretically reduces performance, but I can't measure it.
* Patch from Andrew Tridgell <tridge AT samba.org>
*
* v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson
* o Correctly turn off shared-key authentication when requested
* (bugfix from Robert J. Moore).
* o Correct airport sleep interfaces for current 2.6 kernels.
* o Add code for key change without disabling/enabling the MAC
* port. This is supposed to allow 802.1x to work sanely, but
* doesn't seem to yet.
*
* TODO
* o New wireless extensions API (patch from Moustafa
* Youssef, updated by Jim Carter and Pavel Roskin).
* o Handle de-encapsulation within network layer, provide 802.11
* headers (patch from Thomas 'Dent' Mirlacher)
* o RF monitor mode support
* o Fix possible races in SPY handling.
* o Disconnect wireless extensions from fundamental configuration.
* o (maybe) Software WEP support (patch from Stano Meduna).
...
...
@@ -462,7 +89,10 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
#include <asm/uaccess.h>
#include <asm/io.h>
...
...
@@ -496,6 +126,10 @@ static int ignore_disconnect; /* = 0 */
module_param
(
ignore_disconnect
,
int
,
0644
);
MODULE_PARM_DESC
(
ignore_disconnect
,
"Don't report lost link to the network layer"
);
static
int
force_monitor
;
/* = 0 */
module_param
(
force_monitor
,
int
,
0644
);
MODULE_PARM_DESC
(
force_monitor
,
"Allow monitor mode for all firmware versions"
);
/********************************************************************/
/* Compile time configuration and compatibility stuff */
/********************************************************************/
...
...
@@ -511,6 +145,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
/* Internal constants */
/********************************************************************/
/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
static
const
u8
encaps_hdr
[]
=
{
0xaa
,
0xaa
,
0x03
,
0x00
,
0x00
,
0x00
};
#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
#define ORINOCO_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
...
...
@@ -537,6 +175,11 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
| HERMES_EV_WTERR | HERMES_EV_INFO \
| HERMES_EV_INFDROP )
#define MAX_RID_LEN 1024
static
const
struct
iw_handler_def
orinoco_handler_def
;
static
struct
ethtool_ops
orinoco_ethtool_ops
;
/********************************************************************/
/* Data tables */
/********************************************************************/
...
...
@@ -571,26 +214,45 @@ static struct {
/* Data types */
/********************************************************************/
struct
header_struct
{
/* 802.3 */
u8
dest
[
ETH_ALEN
];
u8
src
[
ETH_ALEN
];
u16
len
;
/* 802.2 */
/* Used in Event handling.
* We avoid nested structres as they break on ARM -- Moustafa */
struct
hermes_tx_descriptor_802_11
{
/* hermes_tx_descriptor */
u16
status
;
u16
reserved1
;
u16
reserved2
;
u32
sw_support
;
u8
retry_count
;
u8
tx_rate
;
u16
tx_control
;
/* ieee802_11_hdr */
u16
frame_ctl
;
u16
duration_id
;
u8
addr1
[
ETH_ALEN
];
u8
addr2
[
ETH_ALEN
];
u8
addr3
[
ETH_ALEN
];
u16
seq_ctl
;
u8
addr4
[
ETH_ALEN
];
u16
data_len
;
/* ethhdr */
unsigned
char
h_dest
[
ETH_ALEN
];
/* destination eth addr */
unsigned
char
h_source
[
ETH_ALEN
];
/* source ether addr */
unsigned
short
h_proto
;
/* packet type ID field */
/* p8022_hdr */
u8
dsap
;
u8
ssap
;
u8
ctrl
;
/* SNAP */
u8
oui
[
3
];
u16
ethertype
;
}
__attribute__
((
packed
));
/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
u8
encaps_hdr
[]
=
{
0xaa
,
0xaa
,
0x03
,
0x00
,
0x00
,
0x00
};
#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
/* Rx frame header except compatibility 802.3 header */
struct
hermes_rx_descriptor
{
/* Control */
u16
status
;
u32
time
;
u8
silence
;
...
...
@@ -598,13 +260,24 @@ struct hermes_rx_descriptor {
u8
rate
;
u8
rxflow
;
u32
reserved
;
/* 802.11 header */
u16
frame_ctl
;
u16
duration_id
;
u8
addr1
[
ETH_ALEN
];
u8
addr2
[
ETH_ALEN
];
u8
addr3
[
ETH_ALEN
];
u16
seq_ctl
;
u8
addr4
[
ETH_ALEN
];
/* Data length */
u16
data_len
;
}
__attribute__
((
packed
));
/********************************************************************/
/* Function prototypes */
/********************************************************************/
static
int
orinoco_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
);
static
int
__orinoco_program_rids
(
struct
net_device
*
dev
);
static
void
__orinoco_set_multicast_list
(
struct
net_device
*
dev
);
...
...
@@ -628,6 +301,10 @@ static inline void set_port_type(struct orinoco_private *priv)
priv
->
createibss
=
1
;
}
break
;
case
IW_MODE_MONITOR
:
priv
->
port_type
=
3
;
priv
->
createibss
=
0
;
break
;
default:
printk
(
KERN_ERR
"%s: Invalid priv->iw_mode in set_port_type()
\n
"
,
priv
->
ndev
->
name
);
...
...
@@ -814,7 +491,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return
1
;
}
if
(
!
netif_carrier_ok
(
dev
))
{
if
(
!
netif_carrier_ok
(
dev
)
||
(
priv
->
iw_mode
==
IW_MODE_MONITOR
)
)
{
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
...
...
@@ -951,26 +628,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
net_device_stats
*
stats
=
&
priv
->
stats
;
u16
fid
=
hermes_read_regn
(
hw
,
TXCOMPLFID
);
struct
hermes_tx_descriptor
desc
;
struct
hermes_tx_descriptor
_802_11
hdr
;
int
err
=
0
;
if
(
fid
==
DUMMY_FID
)
return
;
/* Nothing's really happened */
err
=
hermes_bap_pread
(
hw
,
IRQ_BAP
,
&
desc
,
sizeof
(
desc
),
fid
,
0
);
/* Read the frame header */
err
=
hermes_bap_pread
(
hw
,
IRQ_BAP
,
&
hdr
,
sizeof
(
struct
hermes_tx_descriptor
)
+
sizeof
(
struct
ieee80211_hdr
),
fid
,
0
);
hermes_write_regn
(
hw
,
TXCOMPLFID
,
DUMMY_FID
);
stats
->
tx_errors
++
;
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Unable to read descriptor on Tx error "
"(FID=%04X error %d)
\n
"
,
dev
->
name
,
fid
,
err
);
}
else
{
DEBUG
(
1
,
"%s: Tx error, status %d
\n
"
,
dev
->
name
,
le16_to_cpu
(
desc
.
status
));
return
;
}
stats
->
tx_errors
++
;
DEBUG
(
1
,
"%s: Tx error, err %d (FID=%04X)
\n
"
,
dev
->
name
,
err
,
fid
);
/* We produce a TXDROP event only for retry or lifetime
* exceeded, because that's the only status that really mean
* that this particular node went away.
* Other errors means that *we* screwed up. - Jean II */
hdr
.
status
=
le16_to_cpu
(
hdr
.
status
);
if
(
hdr
.
status
&
(
HERMES_TXSTAT_RETRYERR
|
HERMES_TXSTAT_AGEDERR
))
{
union
iwreq_data
wrqu
;
/* Copy 802.11 dest address.
* We use the 802.11 header because the frame may
* not be 802.3 or may be mangled...
* In Ad-Hoc mode, it will be the node address.
* In managed mode, it will be most likely the AP addr
* User space will figure out how to convert it to
* whatever it needs (IP address or else).
* - Jean II */
memcpy
(
wrqu
.
addr
.
sa_data
,
hdr
.
addr1
,
ETH_ALEN
);
wrqu
.
addr
.
sa_family
=
ARPHRD_ETHER
;
/* Send event to user space */
wireless_send_event
(
dev
,
IWEVTXDROP
,
&
wrqu
,
NULL
);
}
netif_wake_queue
(
dev
);
hermes_write_regn
(
hw
,
TXCOMPLFID
,
DUMMY_FID
);
}
static
void
orinoco_tx_timeout
(
struct
net_device
*
dev
)
...
...
@@ -1047,18 +753,127 @@ static void orinoco_stat_gather(struct net_device *dev,
}
}
/*
* orinoco_rx_monitor - handle received monitor frames.
*
* Arguments:
* dev network device
* rxfid received FID
* desc rx descriptor of the frame
*
* Call context: interrupt
*/
static
void
orinoco_rx_monitor
(
struct
net_device
*
dev
,
u16
rxfid
,
struct
hermes_rx_descriptor
*
desc
)
{
u32
hdrlen
=
30
;
/* return full header by default */
u32
datalen
=
0
;
u16
fc
;
int
err
;
int
len
;
struct
sk_buff
*
skb
;
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
net_device_stats
*
stats
=
&
priv
->
stats
;
hermes_t
*
hw
=
&
priv
->
hw
;
len
=
le16_to_cpu
(
desc
->
data_len
);
/* Determine the size of the header and the data */
fc
=
le16_to_cpu
(
desc
->
frame_ctl
);
switch
(
fc
&
IEEE80211_FCTL_FTYPE
)
{
case
IEEE80211_FTYPE_DATA
:
if
((
fc
&
IEEE80211_FCTL_TODS
)
&&
(
fc
&
IEEE80211_FCTL_FROMDS
))
hdrlen
=
30
;
else
hdrlen
=
24
;
datalen
=
len
;
break
;
case
IEEE80211_FTYPE_MGMT
:
hdrlen
=
24
;
datalen
=
len
;
break
;
case
IEEE80211_FTYPE_CTL
:
switch
(
fc
&
IEEE80211_FCTL_STYPE
)
{
case
IEEE80211_STYPE_PSPOLL
:
case
IEEE80211_STYPE_RTS
:
case
IEEE80211_STYPE_CFEND
:
case
IEEE80211_STYPE_CFENDACK
:
hdrlen
=
16
;
break
;
case
IEEE80211_STYPE_CTS
:
case
IEEE80211_STYPE_ACK
:
hdrlen
=
10
;
break
;
}
break
;
default:
/* Unknown frame type */
break
;
}
/* sanity check the length */
if
(
datalen
>
IEEE80211_DATA_LEN
+
12
)
{
printk
(
KERN_DEBUG
"%s: oversized monitor frame, "
"data length = %d
\n
"
,
dev
->
name
,
datalen
);
err
=
-
EIO
;
stats
->
rx_length_errors
++
;
goto
update_stats
;
}
skb
=
dev_alloc_skb
(
hdrlen
+
datalen
);
if
(
!
skb
)
{
printk
(
KERN_WARNING
"%s: Cannot allocate skb for monitor frame
\n
"
,
dev
->
name
);
err
=
-
ENOMEM
;
goto
drop
;
}
/* Copy the 802.11 header to the skb */
memcpy
(
skb_put
(
skb
,
hdrlen
),
&
(
desc
->
frame_ctl
),
hdrlen
);
skb
->
mac
.
raw
=
skb
->
data
;
/* If any, copy the data from the card to the skb */
if
(
datalen
>
0
)
{
err
=
hermes_bap_pread
(
hw
,
IRQ_BAP
,
skb_put
(
skb
,
datalen
),
ALIGN
(
datalen
,
2
),
rxfid
,
HERMES_802_2_OFFSET
);
if
(
err
)
{
printk
(
KERN_ERR
"%s: error %d reading monitor frame
\n
"
,
dev
->
name
,
err
);
goto
drop
;
}
}
skb
->
dev
=
dev
;
skb
->
ip_summed
=
CHECKSUM_NONE
;
skb
->
pkt_type
=
PACKET_OTHERHOST
;
skb
->
protocol
=
__constant_htons
(
ETH_P_802_2
);
dev
->
last_rx
=
jiffies
;
stats
->
rx_packets
++
;
stats
->
rx_bytes
+=
skb
->
len
;
netif_rx
(
skb
);
return
;
drop:
dev_kfree_skb_irq
(
skb
);
update_stats:
stats
->
rx_errors
++
;
stats
->
rx_dropped
++
;
}
static
void
__orinoco_ev_rx
(
struct
net_device
*
dev
,
hermes_t
*
hw
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
net_device_stats
*
stats
=
&
priv
->
stats
;
struct
iw_statistics
*
wstats
=
&
priv
->
wstats
;
struct
sk_buff
*
skb
=
NULL
;
u16
rxfid
,
status
;
int
length
,
data_len
,
data_off
;
char
*
p
;
u16
rxfid
,
status
,
fc
;
int
length
;
struct
hermes_rx_descriptor
desc
;
struct
header_struct
hdr
;
struct
ethhdr
*
eh
;
struct
ethhdr
*
hdr
;
int
err
;
rxfid
=
hermes_read_regn
(
hw
,
RXFID
);
...
...
@@ -1068,53 +883,46 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if
(
err
)
{
printk
(
KERN_ERR
"%s: error %d reading Rx descriptor. "
"Frame dropped.
\n
"
,
dev
->
name
,
err
);
stats
->
rx_errors
++
;
goto
drop
;
goto
update_stats
;
}
status
=
le16_to_cpu
(
desc
.
status
);
if
(
status
&
HERMES_RXSTAT_ERR
)
{
if
(
status
&
HERMES_RXSTAT_UNDECRYPTABLE
)
{
wstats
->
discard
.
code
++
;
DEBUG
(
1
,
"%s: Undecryptable frame on Rx. Frame dropped.
\n
"
,
if
(
status
&
HERMES_RXSTAT_BADCRC
)
{
DEBUG
(
1
,
"%s: Bad CRC on Rx. Frame dropped.
\n
"
,
dev
->
name
);
}
else
{
stats
->
rx_crc_errors
++
;
DEBUG
(
1
,
"%s: Bad CRC on Rx. Frame dropped.
\n
"
,
dev
->
name
);
}
stats
->
rx_errors
++
;
goto
drop
;
goto
update_stats
;
}
/* For now we ignore the 802.11 header completely, assuming
that the card's firmware has handled anything vital */
/* Handle frames in monitor mode */
if
(
priv
->
iw_mode
==
IW_MODE_MONITOR
)
{
orinoco_rx_monitor
(
dev
,
rxfid
,
&
desc
);
return
;
}
err
=
hermes_bap_pread
(
hw
,
IRQ_BAP
,
&
hdr
,
sizeof
(
hdr
),
rxfid
,
HERMES_802_3_OFFSET
);
if
(
err
)
{
printk
(
KERN_ERR
"%s: error %d reading frame header. "
"Frame dropped.
\n
"
,
dev
->
name
,
err
);
stats
->
rx_errors
++
;
goto
drop
;
if
(
status
&
HERMES_RXSTAT_UNDECRYPTABLE
)
{
DEBUG
(
1
,
"%s: Undecryptable frame on Rx. Frame dropped.
\n
"
,
dev
->
name
);
wstats
->
discard
.
code
++
;
goto
update_stats
;
}
length
=
ntohs
(
hdr
.
len
);
length
=
le16_to_cpu
(
desc
.
data_len
);
fc
=
le16_to_cpu
(
desc
.
frame_ctl
);
/* Sanity checks */
if
(
length
<
3
)
{
/* No for even an 802.2 LLC header */
/* At least on Symbol firmware with PCF we get quite a
lot of these legitimately - Poll frames with no
data. */
stats
->
rx_dropped
++
;
goto
drop
;
return
;
}
if
(
length
>
IEEE802_11_DATA_LEN
)
{
printk
(
KERN_WARNING
"%s: Oversized frame received (%d bytes)
\n
"
,
dev
->
name
,
length
);
stats
->
rx_length_errors
++
;
stats
->
rx_errors
++
;
goto
drop
;
goto
update_stats
;
}
/* We need space for the packet data itself, plus an ethernet
...
...
@@ -1126,60 +934,53 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if
(
!
skb
)
{
printk
(
KERN_WARNING
"%s: Can't allocate skb for Rx
\n
"
,
dev
->
name
);
goto
drop
;
goto
update_stats
;
}
skb_reserve
(
skb
,
2
);
/* This way the IP header is aligned */
/* We'll prepend the header, so reserve space for it. The worst
case is no decapsulation, when 802.3 header is prepended and
nothing is removed. 2 is for aligning the IP header. */
skb_reserve
(
skb
,
ETH_HLEN
+
2
);
err
=
hermes_bap_pread
(
hw
,
IRQ_BAP
,
skb_put
(
skb
,
length
),
ALIGN
(
length
,
2
),
rxfid
,
HERMES_802_2_OFFSET
);
if
(
err
)
{
printk
(
KERN_ERR
"%s: error %d reading frame. "
"Frame dropped.
\n
"
,
dev
->
name
,
err
);
goto
drop
;
}
/* Handle decapsulation
* In most cases, the firmware tell us about SNAP frames.
* For some reason, the SNAP frames sent by LinkSys APs
* are not properly recognised by most firmwares.
* So, check ourselves */
if
(((
status
&
HERMES_RXSTAT_MSGTYPE
)
==
HERMES_RXSTAT_1042
)
||
if
(
length
>=
ENCAPS_OVERHEAD
&&
(((
status
&
HERMES_RXSTAT_MSGTYPE
)
==
HERMES_RXSTAT_1042
)
||
((
status
&
HERMES_RXSTAT_MSGTYPE
)
==
HERMES_RXSTAT_TUNNEL
)
||
is_ethersnap
(
&
hdr
))
{
is_ethersnap
(
skb
->
data
)
))
{
/* These indicate a SNAP within 802.2 LLC within
802.11 frame which we'll need to de-encapsulate to
the original EthernetII frame. */
if
(
length
<
ENCAPS_OVERHEAD
)
{
/* No room for full LLC+SNAP */
stats
->
rx_length_errors
++
;
goto
drop
;
}
/* Remove SNAP header, reconstruct EthernetII frame */
data_len
=
length
-
ENCAPS_OVERHEAD
;
data_off
=
HERMES_802_3_OFFSET
+
sizeof
(
hdr
);
eh
=
(
struct
ethhdr
*
)
skb_put
(
skb
,
ETH_HLEN
);
memcpy
(
eh
,
&
hdr
,
2
*
ETH_ALEN
);
eh
->
h_proto
=
hdr
.
ethertype
;
hdr
=
(
struct
ethhdr
*
)
skb_push
(
skb
,
ETH_HLEN
-
ENCAPS_OVERHEAD
);
}
else
{
/* All other cases indicate a genuine 802.3 frame. No
decapsulation needed. We just throw the whole
thing in, and hope the protocol layer can deal with
it as 802.3 */
data_len
=
length
;
data_off
=
HERMES_802_3_OFFSET
;
/* FIXME: we re-read from the card data we already read here */
}
p
=
skb_put
(
skb
,
data_len
);
err
=
hermes_bap_pread
(
hw
,
IRQ_BAP
,
p
,
ALIGN
(
data_len
,
2
),
rxfid
,
data_off
);
if
(
err
)
{
printk
(
KERN_ERR
"%s: error %d reading frame. "
"Frame dropped.
\n
"
,
dev
->
name
,
err
);
stats
->
rx_errors
++
;
goto
drop
;
/* 802.3 frame - prepend 802.3 header as is */
hdr
=
(
struct
ethhdr
*
)
skb_push
(
skb
,
ETH_HLEN
);
hdr
->
h_proto
=
htons
(
length
);
}
memcpy
(
hdr
->
h_dest
,
desc
.
addr1
,
ETH_ALEN
);
if
(
fc
&
IEEE80211_FCTL_FROMDS
)
memcpy
(
hdr
->
h_source
,
desc
.
addr3
,
ETH_ALEN
);
else
memcpy
(
hdr
->
h_source
,
desc
.
addr2
,
ETH_ALEN
);
dev
->
last_rx
=
jiffies
;
skb
->
dev
=
dev
;
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
skb
->
ip_summed
=
CHECKSUM_NONE
;
if
(
fc
&
IEEE80211_FCTL_TODS
)
skb
->
pkt_type
=
PACKET_OTHERHOST
;
/* Process the wireless stats if needed */
orinoco_stat_gather
(
dev
,
skb
,
&
desc
);
...
...
@@ -1192,11 +993,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
return
;
drop:
stats
->
rx_dropped
++
;
if
(
skb
)
dev_kfree_skb_irq
(
skb
);
return
;
update_stats:
stats
->
rx_errors
++
;
stats
->
rx_dropped
++
;
}
/********************************************************************/
...
...
@@ -1240,6 +1040,99 @@ static void print_linkstatus(struct net_device *dev, u16 status)
dev
->
name
,
s
,
status
);
}
/* Search scan results for requested BSSID, join it if found */
static
void
orinoco_join_ap
(
struct
net_device
*
dev
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
hermes
*
hw
=
&
priv
->
hw
;
int
err
;
unsigned
long
flags
;
struct
join_req
{
u8
bssid
[
ETH_ALEN
];
u16
channel
;
}
__attribute__
((
packed
))
req
;
const
int
atom_len
=
offsetof
(
struct
prism2_scan_apinfo
,
atim
);
struct
prism2_scan_apinfo
*
atom
;
int
offset
=
4
;
u8
*
buf
;
u16
len
;
/* Allocate buffer for scan results */
buf
=
kmalloc
(
MAX_SCAN_LEN
,
GFP_KERNEL
);
if
(
!
buf
)
return
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
goto
out
;
/* Sanity checks in case user changed something in the meantime */
if
(
!
priv
->
bssid_fixed
)
goto
out
;
if
(
strlen
(
priv
->
desired_essid
)
==
0
)
goto
out
;
/* Read scan results from the firmware */
err
=
hermes_read_ltv
(
hw
,
USER_BAP
,
HERMES_RID_SCANRESULTSTABLE
,
MAX_SCAN_LEN
,
&
len
,
buf
);
if
(
err
)
{
printk
(
KERN_ERR
"%s: Cannot read scan results
\n
"
,
dev
->
name
);
goto
out
;
}
len
=
HERMES_RECLEN_TO_BYTES
(
len
);
/* Go through the scan results looking for the channel of the AP
* we were requested to join */
for
(;
offset
+
atom_len
<=
len
;
offset
+=
atom_len
)
{
atom
=
(
struct
prism2_scan_apinfo
*
)
(
buf
+
offset
);
if
(
memcmp
(
&
atom
->
bssid
,
priv
->
desired_bssid
,
ETH_ALEN
)
==
0
)
goto
found
;
}
DEBUG
(
1
,
"%s: Requested AP not found in scan results
\n
"
,
dev
->
name
);
goto
out
;
found:
memcpy
(
req
.
bssid
,
priv
->
desired_bssid
,
ETH_ALEN
);
req
.
channel
=
atom
->
channel
;
/* both are little-endian */
err
=
HERMES_WRITE_RECORD
(
hw
,
USER_BAP
,
HERMES_RID_CNFJOINREQUEST
,
&
req
);
if
(
err
)
printk
(
KERN_ERR
"%s: Error issuing join request
\n
"
,
dev
->
name
);
out:
kfree
(
buf
);
orinoco_unlock
(
priv
,
&
flags
);
}
/* Send new BSSID to userspace */
static
void
orinoco_send_wevents
(
struct
net_device
*
dev
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
hermes
*
hw
=
&
priv
->
hw
;
union
iwreq_data
wrqu
;
int
err
;
unsigned
long
flags
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
;
err
=
hermes_read_ltv
(
hw
,
IRQ_BAP
,
HERMES_RID_CURRENTBSSID
,
ETH_ALEN
,
NULL
,
wrqu
.
ap_addr
.
sa_data
);
if
(
err
!=
0
)
return
;
wrqu
.
ap_addr
.
sa_family
=
ARPHRD_ETHER
;
/* Send event to user space */
wireless_send_event
(
dev
,
SIOCGIWAP
,
&
wrqu
,
NULL
);
orinoco_unlock
(
priv
,
&
flags
);
}
static
void
__orinoco_ev_info
(
struct
net_device
*
dev
,
hermes_t
*
hw
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
...
...
@@ -1307,6 +1200,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
u16
newstatus
;
int
connected
;
if
(
priv
->
iw_mode
==
IW_MODE_MONITOR
)
break
;
if
(
len
!=
sizeof
(
linkstatus
))
{
printk
(
KERN_WARNING
"%s: Unexpected size for linkstatus frame (%d bytes)
\n
"
,
dev
->
name
,
len
);
...
...
@@ -1319,6 +1215,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break
;
newstatus
=
le16_to_cpu
(
linkstatus
.
linkstatus
);
/* Symbol firmware uses "out of range" to signal that
* the hostscan frame can be requested. */
if
(
newstatus
==
HERMES_LINKSTATUS_AP_OUT_OF_RANGE
&&
priv
->
firmware_type
==
FIRMWARE_TYPE_SYMBOL
&&
priv
->
has_hostscan
&&
priv
->
scan_inprogress
)
{
hermes_inquire
(
hw
,
HERMES_INQ_HOSTSCAN_SYMBOL
);
break
;
}
connected
=
(
newstatus
==
HERMES_LINKSTATUS_CONNECTED
)
||
(
newstatus
==
HERMES_LINKSTATUS_AP_CHANGE
)
||
(
newstatus
==
HERMES_LINKSTATUS_AP_IN_RANGE
);
...
...
@@ -1328,25 +1233,102 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
else
if
(
!
ignore_disconnect
)
netif_carrier_off
(
dev
);
if
(
newstatus
!=
priv
->
last_linkstatus
)
print_linkstatus
(
dev
,
newstatus
);
if
(
newstatus
!=
priv
->
last_linkstatus
)
{
priv
->
last_linkstatus
=
newstatus
;
print_linkstatus
(
dev
,
newstatus
);
/* The info frame contains only one word which is the
* status (see hermes.h). The status is pretty boring
* in itself, that's why we export the new BSSID...
* Jean II */
schedule_work
(
&
priv
->
wevent_work
);
}
}
break
;
default:
printk
(
KERN_DEBUG
"%s: Unknown information frame received: "
"type 0x%04x, length %d
\n
"
,
dev
->
name
,
type
,
len
);
/* We don't actually do anything about it */
case
HERMES_INQ_SCAN
:
if
(
!
priv
->
scan_inprogress
&&
priv
->
bssid_fixed
&&
priv
->
firmware_type
==
FIRMWARE_TYPE_INTERSIL
)
{
schedule_work
(
&
priv
->
join_work
);
break
;
}
/* fall through */
case
HERMES_INQ_HOSTSCAN
:
case
HERMES_INQ_HOSTSCAN_SYMBOL
:
{
/* Result of a scanning. Contains information about
* cells in the vicinity - Jean II */
union
iwreq_data
wrqu
;
unsigned
char
*
buf
;
/* Sanity check */
if
(
len
>
4096
)
{
printk
(
KERN_WARNING
"%s: Scan results too large (%d bytes)
\n
"
,
dev
->
name
,
len
);
break
;
}
}
static
void
__orinoco_ev_infdrop
(
struct
net_device
*
dev
,
hermes_t
*
hw
)
{
if
(
net_ratelimit
())
printk
(
KERN_DEBUG
"%s: Information frame lost.
\n
"
,
dev
->
name
);
}
/* We are a strict producer. If the previous scan results
* have not been consumed, we just have to drop this
* frame. We can't remove the previous results ourselves,
* that would be *very* racy... Jean II */
if
(
priv
->
scan_result
!=
NULL
)
{
printk
(
KERN_WARNING
"%s: Previous scan results not consumed, dropping info frame.
\n
"
,
dev
->
name
);
break
;
}
/* Allocate buffer for results */
buf
=
kmalloc
(
len
,
GFP_ATOMIC
);
if
(
buf
==
NULL
)
/* No memory, so can't printk()... */
break
;
/* Read scan data */
err
=
hermes_bap_pread
(
hw
,
IRQ_BAP
,
(
void
*
)
buf
,
len
,
infofid
,
sizeof
(
info
));
if
(
err
)
break
;
#ifdef ORINOCO_DEBUG
{
int
i
;
printk
(
KERN_DEBUG
"Scan result [%02X"
,
buf
[
0
]);
for
(
i
=
1
;
i
<
(
len
*
2
);
i
++
)
printk
(
":%02X"
,
buf
[
i
]);
printk
(
"]
\n
"
);
}
#endif
/* ORINOCO_DEBUG */
/* Allow the clients to access the results */
priv
->
scan_len
=
len
;
priv
->
scan_result
=
buf
;
/* Send an empty event to user space.
* We don't send the received data on the event because
* it would require us to do complex transcoding, and
* we want to minimise the work done in the irq handler
* Use a request to extract the data - Jean II */
wrqu
.
data
.
length
=
0
;
wrqu
.
data
.
flags
=
0
;
wireless_send_event
(
dev
,
SIOCGIWSCAN
,
&
wrqu
,
NULL
);
}
break
;
case
HERMES_INQ_SEC_STAT_AGERE
:
/* Security status (Agere specific) */
/* Ignore this frame for now */
if
(
priv
->
firmware_type
==
FIRMWARE_TYPE_AGERE
)
break
;
/* fall through */
default:
printk
(
KERN_DEBUG
"%s: Unknown information frame received: "
"type 0x%04x, length %d
\n
"
,
dev
->
name
,
type
,
len
);
/* We don't actually do anything about it */
break
;
}
}
static
void
__orinoco_ev_infdrop
(
struct
net_device
*
dev
,
hermes_t
*
hw
)
{
if
(
net_ratelimit
())
printk
(
KERN_DEBUG
"%s: Information frame lost.
\n
"
,
dev
->
name
);
}
/********************************************************************/
/* Internal hardware control routines */
...
...
@@ -1470,6 +1452,36 @@ static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
return
err
;
}
/* Set fixed AP address */
static
int
__orinoco_hw_set_wap
(
struct
orinoco_private
*
priv
)
{
int
roaming_flag
;
int
err
=
0
;
hermes_t
*
hw
=
&
priv
->
hw
;
switch
(
priv
->
firmware_type
)
{
case
FIRMWARE_TYPE_AGERE
:
/* not supported */
break
;
case
FIRMWARE_TYPE_INTERSIL
:
if
(
priv
->
bssid_fixed
)
roaming_flag
=
2
;
else
roaming_flag
=
1
;
err
=
hermes_write_wordrec
(
hw
,
USER_BAP
,
HERMES_RID_CNFROAMINGMODE
,
roaming_flag
);
break
;
case
FIRMWARE_TYPE_SYMBOL
:
err
=
HERMES_WRITE_RECORD
(
hw
,
USER_BAP
,
HERMES_RID_CNFMANDATORYBSSID_SYMBOL
,
&
priv
->
desired_bssid
);
break
;
}
return
err
;
}
/* Change the WEP keys and/or the current keys. Can be called
* either from __orinoco_hw_setup_wep() or directly from
* orinoco_ioctl_setiwencode(). In the later case the association
...
...
@@ -1655,6 +1667,13 @@ static int __orinoco_program_rids(struct net_device *dev)
}
}
/* Set the desired BSSID */
err
=
__orinoco_hw_set_wap
(
priv
);
if
(
err
)
{
printk
(
KERN_ERR
"%s: Error %d setting AP address
\n
"
,
dev
->
name
,
err
);
return
err
;
}
/* Set the desired ESSID */
idbuf
.
len
=
cpu_to_le16
(
strlen
(
priv
->
desired_essid
));
memcpy
(
&
idbuf
.
val
,
priv
->
desired_essid
,
sizeof
(
idbuf
.
val
));
...
...
@@ -1793,6 +1812,20 @@ static int __orinoco_program_rids(struct net_device *dev)
}
}
if
(
priv
->
iw_mode
==
IW_MODE_MONITOR
)
{
/* Enable monitor mode */
dev
->
type
=
ARPHRD_IEEE80211
;
err
=
hermes_docmd_wait
(
hw
,
HERMES_CMD_TEST
|
HERMES_TEST_MONITOR
,
0
,
NULL
);
}
else
{
/* Disable monitor mode */
dev
->
type
=
ARPHRD_ETHER
;
err
=
hermes_docmd_wait
(
hw
,
HERMES_CMD_TEST
|
HERMES_TEST_STOP
,
0
,
NULL
);
}
if
(
err
)
return
err
;
/* Set promiscuity / multicast*/
priv
->
promiscuous
=
0
;
priv
->
mc_count
=
0
;
...
...
@@ -1869,55 +1902,6 @@ __orinoco_set_multicast_list(struct net_device *dev)
dev
->
flags
&=
~
IFF_PROMISC
;
}
static
int
orinoco_reconfigure
(
struct
net_device
*
dev
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
hermes
*
hw
=
&
priv
->
hw
;
unsigned
long
flags
;
int
err
=
0
;
if
(
priv
->
broken_disableport
)
{
schedule_work
(
&
priv
->
reset_work
);
return
0
;
}
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
err
=
hermes_disable_port
(
hw
,
0
);
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Unable to disable port while reconfiguring card
\n
"
,
dev
->
name
);
priv
->
broken_disableport
=
1
;
goto
out
;
}
err
=
__orinoco_program_rids
(
dev
);
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Unable to reconfigure card
\n
"
,
dev
->
name
);
goto
out
;
}
err
=
hermes_enable_port
(
hw
,
0
);
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Unable to enable port while reconfiguring card
\n
"
,
dev
->
name
);
goto
out
;
}
out:
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Resetting instead...
\n
"
,
dev
->
name
);
schedule_work
(
&
priv
->
reset_work
);
err
=
0
;
}
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
/* This must be called from user context, without locks held - use
* schedule_work() */
static
void
orinoco_reset
(
struct
net_device
*
dev
)
...
...
@@ -1946,6 +1930,11 @@ static void orinoco_reset(struct net_device *dev)
orinoco_unlock
(
priv
,
&
flags
);
/* Scanning support: Cleanup of driver struct */
kfree
(
priv
->
scan_result
);
priv
->
scan_result
=
NULL
;
priv
->
scan_inprogress
=
0
;
if
(
priv
->
hard_reset
)
{
err
=
(
*
priv
->
hard_reset
)(
priv
);
if
(
err
)
{
...
...
@@ -2184,6 +2173,8 @@ static int determine_firmware(struct net_device *dev)
priv
->
has_mwo
=
(
firmver
>=
0x60000
);
priv
->
has_pm
=
(
firmver
>=
0x40020
);
/* Don't work in 7.52 ? */
priv
->
ibss_port
=
1
;
priv
->
has_hostscan
=
(
firmver
>=
0x8000a
);
priv
->
broken_monitor
=
(
firmver
>=
0x80000
);
/* Tested with Agere firmware :
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
...
...
@@ -2229,6 +2220,8 @@ static int determine_firmware(struct net_device *dev)
priv
->
ibss_port
=
4
;
priv
->
broken_disableport
=
(
firmver
==
0x25013
)
||
(
firmver
>=
0x30000
&&
firmver
<=
0x31000
);
priv
->
has_hostscan
=
(
firmver
>=
0x31001
)
||
(
firmver
>=
0x29057
&&
firmver
<
0x30000
);
/* Tested with Intel firmware : 0x20015 => Jean II */
/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
break
;
...
...
@@ -2248,6 +2241,7 @@ static int determine_firmware(struct net_device *dev)
priv
->
has_ibss
=
(
firmver
>=
0x000700
);
/* FIXME */
priv
->
has_big_wep
=
priv
->
has_wep
=
(
firmver
>=
0x000800
);
priv
->
has_pm
=
(
firmver
>=
0x000700
);
priv
->
has_hostscan
=
(
firmver
>=
0x010301
);
if
(
firmver
>=
0x000800
)
priv
->
ibss_port
=
0
;
...
...
@@ -2456,8 +2450,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
dev
->
tx_timeout
=
orinoco_tx_timeout
;
dev
->
watchdog_timeo
=
HZ
;
/* 1 second timeout */
dev
->
get_stats
=
orinoco_get_stats
;
dev
->
ethtool_ops
=
&
orinoco_ethtool_ops
;
dev
->
get_wireless_stats
=
orinoco_get_wireless_stats
;
dev
->
do_ioctl
=
orinoco_ioctl
;
dev
->
wireless_handlers
=
(
struct
iw_handler_def
*
)
&
orinoco_handler_def
;
dev
->
change_mtu
=
orinoco_change_mtu
;
dev
->
set_multicast_list
=
orinoco_set_multicast_list
;
/* we use the default eth_mac_addr for setting the MAC addr */
...
...
@@ -2473,6 +2468,8 @@ struct net_device *alloc_orinocodev(int sizeof_card,
* before anything else touches the
* hardware */
INIT_WORK
(
&
priv
->
reset_work
,
(
void
(
*
)(
void
*
))
orinoco_reset
,
dev
);
INIT_WORK
(
&
priv
->
join_work
,
(
void
(
*
)(
void
*
))
orinoco_join_ap
,
dev
);
INIT_WORK
(
&
priv
->
wevent_work
,
(
void
(
*
)(
void
*
))
orinoco_send_wevents
,
dev
);
netif_carrier_off
(
dev
);
priv
->
last_linkstatus
=
0xffff
;
...
...
@@ -2483,6 +2480,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
void
free_orinocodev
(
struct
net_device
*
dev
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
kfree
(
priv
->
scan_result
);
free_netdev
(
dev
);
}
...
...
@@ -2490,24 +2490,6 @@ void free_orinocodev(struct net_device *dev)
/* Wireless extensions */
/********************************************************************/
static
int
orinoco_hw_get_bssid
(
struct
orinoco_private
*
priv
,
char
buf
[
ETH_ALEN
])
{
hermes_t
*
hw
=
&
priv
->
hw
;
int
err
=
0
;
unsigned
long
flags
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
err
=
hermes_read_ltv
(
hw
,
USER_BAP
,
HERMES_RID_CURRENTBSSID
,
ETH_ALEN
,
NULL
,
buf
);
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
static
int
orinoco_hw_get_essid
(
struct
orinoco_private
*
priv
,
int
*
active
,
char
buf
[
IW_ESSID_MAX_SIZE
+
1
])
{
...
...
@@ -2633,140 +2615,271 @@ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
return
0
;
}
static
int
orinoco_ioctl_getiwrange
(
struct
net_device
*
dev
,
struct
iw_point
*
rrq
)
static
int
orinoco_ioctl_getname
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
char
*
name
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
err
=
0
;
int
mode
;
struct
iw_range
range
;
int
numrates
;
int
i
,
k
;
int
err
;
err
=
orinoco_hw_get_bitratelist
(
priv
,
&
numrates
,
NULL
,
0
);
if
(
!
err
&&
(
numrates
>
2
))
strcpy
(
name
,
"IEEE 802.11b"
);
else
strcpy
(
name
,
"IEEE 802.11-DS"
);
return
0
;
}
static
int
orinoco_ioctl_setwap
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
sockaddr
*
ap_addr
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
err
=
-
EINPROGRESS
;
/* Call commit handler */
unsigned
long
flags
;
static
const
u8
off_addr
[]
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
const
u8
any_addr
[]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
TRACE_ENTER
(
dev
->
name
);
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
/* Enable automatic roaming - no sanity checks are needed */
if
(
memcmp
(
&
ap_addr
->
sa_data
,
off_addr
,
ETH_ALEN
)
==
0
||
memcmp
(
&
ap_addr
->
sa_data
,
any_addr
,
ETH_ALEN
)
==
0
)
{
priv
->
bssid_fixed
=
0
;
memset
(
priv
->
desired_bssid
,
0
,
ETH_ALEN
);
/* "off" means keep existing connection */
if
(
ap_addr
->
sa_data
[
0
]
==
0
)
{
__orinoco_hw_set_wap
(
priv
);
err
=
0
;
}
goto
out
;
}
if
(
priv
->
firmware_type
==
FIRMWARE_TYPE_AGERE
)
{
printk
(
KERN_WARNING
"%s: Lucent/Agere firmware doesn't "
"support manual roaming
\n
"
,
dev
->
name
);
err
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
priv
->
iw_mode
!=
IW_MODE_INFRA
)
{
printk
(
KERN_WARNING
"%s: Manual roaming supported only in "
"managed mode
\n
"
,
dev
->
name
);
err
=
-
EOPNOTSUPP
;
goto
out
;
}
/* Intersil firmware hangs without Desired ESSID */
if
(
priv
->
firmware_type
==
FIRMWARE_TYPE_INTERSIL
&&
strlen
(
priv
->
desired_essid
)
==
0
)
{
printk
(
KERN_WARNING
"%s: Desired ESSID must be set for "
"manual roaming
\n
"
,
dev
->
name
);
err
=
-
EOPNOTSUPP
;
goto
out
;
}
/* Finally, enable manual roaming */
priv
->
bssid_fixed
=
1
;
memcpy
(
priv
->
desired_bssid
,
&
ap_addr
->
sa_data
,
ETH_ALEN
);
out:
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
static
int
orinoco_ioctl_getwap
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
sockaddr
*
ap_addr
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
hermes_t
*
hw
=
&
priv
->
hw
;
int
err
=
0
;
unsigned
long
flags
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
ap_addr
->
sa_family
=
ARPHRD_ETHER
;
err
=
hermes_read_ltv
(
hw
,
USER_BAP
,
HERMES_RID_CURRENTBSSID
,
ETH_ALEN
,
NULL
,
ap_addr
->
sa_data
);
orinoco_unlock
(
priv
,
&
flags
);
if
(
!
access_ok
(
VERIFY_WRITE
,
rrq
->
pointer
,
sizeof
(
range
)))
return
-
EFAULT
;
return
err
;
}
static
int
orinoco_ioctl_setmode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
u32
*
mode
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
err
=
-
EINPROGRESS
;
/* Call commit handler */
unsigned
long
flags
;
rrq
->
length
=
sizeof
(
range
);
if
(
priv
->
iw_mode
==
*
mode
)
return
0
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
mode
=
priv
->
iw_mode
;
switch
(
*
mode
)
{
case
IW_MODE_ADHOC
:
if
(
!
priv
->
has_ibss
&&
!
priv
->
has_port3
)
err
=
-
EOPNOTSUPP
;
break
;
case
IW_MODE_INFRA
:
break
;
case
IW_MODE_MONITOR
:
if
(
priv
->
broken_monitor
&&
!
force_monitor
)
{
printk
(
KERN_WARNING
"%s: Monitor mode support is "
"buggy in this firmware, not enabling
\n
"
,
dev
->
name
);
err
=
-
EOPNOTSUPP
;
}
break
;
default:
err
=
-
EOPNOTSUPP
;
break
;
}
if
(
err
==
-
EINPROGRESS
)
{
priv
->
iw_mode
=
*
mode
;
set_port_type
(
priv
);
}
orinoco_unlock
(
priv
,
&
flags
);
memset
(
&
range
,
0
,
sizeof
(
range
));
return
err
;
}
static
int
orinoco_ioctl_getmode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
u32
*
mode
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
*
mode
=
priv
->
iw_mode
;
return
0
;
}
static
int
orinoco_ioctl_getiwrange
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
rrq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
err
=
0
;
struct
iw_range
*
range
=
(
struct
iw_range
*
)
extra
;
int
numrates
;
int
i
,
k
;
TRACE_ENTER
(
dev
->
name
);
/* Much of this shamelessly taken from wvlan_cs.c. No idea
* what it all means -dgibson */
range
.
we_version_compiled
=
WIRELESS_EXT
;
range
.
we_version_source
=
11
;
rrq
->
length
=
sizeof
(
struct
iw_range
);
memset
(
range
,
0
,
sizeof
(
struct
iw_range
));
range
.
min_nwid
=
range
.
max_nwid
=
0
;
/* We don't use nwids */
range
->
we_version_compiled
=
WIRELESS_EXT
;
range
->
we_version_source
=
14
;
/* Set available channels/frequencies */
range
.
num_channels
=
NUM_CHANNELS
;
range
->
num_channels
=
NUM_CHANNELS
;
k
=
0
;
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
if
(
priv
->
channel_mask
&
(
1
<<
i
))
{
range
.
freq
[
k
].
i
=
i
+
1
;
range
.
freq
[
k
].
m
=
channel_frequency
[
i
]
*
100000
;
range
.
freq
[
k
].
e
=
1
;
range
->
freq
[
k
].
i
=
i
+
1
;
range
->
freq
[
k
].
m
=
channel_frequency
[
i
]
*
100000
;
range
->
freq
[
k
].
e
=
1
;
k
++
;
}
if
(
k
>=
IW_MAX_FREQUENCIES
)
break
;
}
range
.
num_frequency
=
k
;
range
->
num_frequency
=
k
;
range
->
sensitivity
=
3
;
if
(
priv
->
has_wep
)
{
range
->
max_encoding_tokens
=
ORINOCO_MAX_KEYS
;
range
->
encoding_size
[
0
]
=
SMALL_KEY_SIZE
;
range
->
num_encoding_sizes
=
1
;
range
.
sensitivity
=
3
;
if
(
priv
->
has_big_wep
)
{
range
->
encoding_size
[
1
]
=
LARGE_KEY_SIZE
;
range
->
num_encoding_sizes
=
2
;
}
}
if
((
mode
==
IW_MODE_ADHOC
)
&&
(
priv
->
spy_number
==
0
)){
if
((
priv
->
iw_
mode
==
IW_MODE_ADHOC
)
&&
(
priv
->
spy_number
==
0
)){
/* Quality stats meaningless in ad-hoc mode */
range
.
max_qual
.
qual
=
0
;
range
.
max_qual
.
level
=
0
;
range
.
max_qual
.
noise
=
0
;
range
.
avg_qual
.
qual
=
0
;
range
.
avg_qual
.
level
=
0
;
range
.
avg_qual
.
noise
=
0
;
}
else
{
range
.
max_qual
.
qual
=
0x8b
-
0x2f
;
range
.
max_qual
.
level
=
0x2f
-
0x95
-
1
;
range
.
max_qual
.
noise
=
0x2f
-
0x95
-
1
;
range
->
max_qual
.
qual
=
0x8b
-
0x2f
;
range
->
max_qual
.
level
=
0x2f
-
0x95
-
1
;
range
->
max_qual
.
noise
=
0x2f
-
0x95
-
1
;
/* Need to get better values */
range
.
avg_qual
.
qual
=
0x24
;
range
.
avg_qual
.
level
=
0xC2
;
range
.
avg_qual
.
noise
=
0x9E
;
range
->
avg_qual
.
qual
=
0x24
;
range
->
avg_qual
.
level
=
0xC2
;
range
->
avg_qual
.
noise
=
0x9E
;
}
err
=
orinoco_hw_get_bitratelist
(
priv
,
&
numrates
,
range
.
bitrate
,
IW_MAX_BITRATES
);
range
->
bitrate
,
IW_MAX_BITRATES
);
if
(
err
)
return
err
;
range
.
num_bitrates
=
numrates
;
range
->
num_bitrates
=
numrates
;
/* Set an indication of the max TCP throughput in bit/s that we can
* expect using this interface. May be use for QoS stuff...
* Jean II */
if
(
numrates
>
2
)
range
.
throughput
=
5
*
1000
*
1000
;
/* ~5 Mb/s */
if
(
numrates
>
2
)
range
->
throughput
=
5
*
1000
*
1000
;
/* ~5 Mb/s */
else
range
.
throughput
=
1
.
5
*
1000
*
1000
;
/* ~1.5 Mb/s */
range
.
min_rts
=
0
;
range
.
max_rts
=
2347
;
range
.
min_frag
=
256
;
range
.
max_frag
=
2346
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
if
(
priv
->
has_wep
)
{
range
.
max_encoding_tokens
=
ORINOCO_MAX_KEYS
;
range
.
encoding_size
[
0
]
=
SMALL_KEY_SIZE
;
range
.
num_encoding_sizes
=
1
;
if
(
priv
->
has_big_wep
)
{
range
.
encoding_size
[
1
]
=
LARGE_KEY_SIZE
;
range
.
num_encoding_sizes
=
2
;
}
}
else
{
range
.
num_encoding_sizes
=
0
;
range
.
max_encoding_tokens
=
0
;
}
orinoco_unlock
(
priv
,
&
flags
);
range
.
min_pmp
=
0
;
range
.
max_pmp
=
65535000
;
range
.
min_pmt
=
0
;
range
.
max_pmt
=
65535
*
1000
;
/* ??? */
range
.
pmp_flags
=
IW_POWER_PERIOD
;
range
.
pmt_flags
=
IW_POWER_TIMEOUT
;
range
.
pm_capa
=
IW_POWER_PERIOD
|
IW_POWER_TIMEOUT
|
IW_POWER_UNICAST_R
;
range
.
num_txpower
=
1
;
range
.
txpower
[
0
]
=
15
;
/* 15dBm */
range
.
txpower_capa
=
IW_TXPOW_DBM
;
range
.
retry_capa
=
IW_RETRY_LIMIT
|
IW_RETRY_LIFETIME
;
range
.
retry_flags
=
IW_RETRY_LIMIT
;
range
.
r_time_flags
=
IW_RETRY_LIFETIME
;
range
.
min_retry
=
0
;
range
.
max_retry
=
65535
;
/* ??? */
range
.
min_r_time
=
0
;
range
.
max_r_time
=
65535
*
1000
;
/* ??? */
if
(
copy_to_user
(
rrq
->
pointer
,
&
range
,
sizeof
(
range
)))
return
-
EFAULT
;
range
->
throughput
=
1
.
5
*
1000
*
1000
;
/* ~1.5 Mb/s */
range
->
min_rts
=
0
;
range
->
max_rts
=
2347
;
range
->
min_frag
=
256
;
range
->
max_frag
=
2346
;
range
->
min_pmp
=
0
;
range
->
max_pmp
=
65535000
;
range
->
min_pmt
=
0
;
range
->
max_pmt
=
65535
*
1000
;
/* ??? */
range
->
pmp_flags
=
IW_POWER_PERIOD
;
range
->
pmt_flags
=
IW_POWER_TIMEOUT
;
range
->
pm_capa
=
IW_POWER_PERIOD
|
IW_POWER_TIMEOUT
|
IW_POWER_UNICAST_R
;
range
->
retry_capa
=
IW_RETRY_LIMIT
|
IW_RETRY_LIFETIME
;
range
->
retry_flags
=
IW_RETRY_LIMIT
;
range
->
r_time_flags
=
IW_RETRY_LIFETIME
;
range
->
min_retry
=
0
;
range
->
max_retry
=
65535
;
/* ??? */
range
->
min_r_time
=
0
;
range
->
max_r_time
=
65535
*
1000
;
/* ??? */
TRACE_EXIT
(
dev
->
name
);
return
0
;
}
static
int
orinoco_ioctl_setiwencode
(
struct
net_device
*
dev
,
struct
iw_point
*
erq
)
static
int
orinoco_ioctl_setiwencode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
erq
,
char
*
keybuf
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
index
=
(
erq
->
flags
&
IW_ENCODE_INDEX
)
-
1
;
...
...
@@ -2774,8 +2887,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
int
enable
=
priv
->
wep_on
;
int
restricted
=
priv
->
wep_restrict
;
u16
xlen
=
0
;
int
err
=
0
;
char
keybuf
[
ORINOCO_MAX_KEY_SIZE
];
int
err
=
-
EINPROGRESS
;
/* Call commit handler */
unsigned
long
flags
;
if
(
!
priv
->
has_wep
)
...
...
@@ -2788,9 +2900,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
if
(
(
erq
->
length
>
SMALL_KEY_SIZE
)
&&
!
priv
->
has_big_wep
)
return
-
E2BIG
;
if
(
copy_from_user
(
keybuf
,
erq
->
pointer
,
erq
->
length
))
return
-
EFAULT
;
}
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
...
...
@@ -2864,12 +2973,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
return
err
;
}
static
int
orinoco_ioctl_getiwencode
(
struct
net_device
*
dev
,
struct
iw_point
*
erq
)
static
int
orinoco_ioctl_getiwencode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
erq
,
char
*
keybuf
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
index
=
(
erq
->
flags
&
IW_ENCODE_INDEX
)
-
1
;
u16
xlen
=
0
;
char
keybuf
[
ORINOCO_MAX_KEY_SIZE
];
unsigned
long
flags
;
if
(
!
priv
->
has_wep
)
...
...
@@ -2898,51 +3009,47 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *er
memcpy
(
keybuf
,
priv
->
keys
[
index
].
data
,
ORINOCO_MAX_KEY_SIZE
);
orinoco_unlock
(
priv
,
&
flags
);
if
(
erq
->
pointer
)
{
if
(
copy_to_user
(
erq
->
pointer
,
keybuf
,
xlen
))
return
-
EFAULT
;
}
return
0
;
}
static
int
orinoco_ioctl_setessid
(
struct
net_device
*
dev
,
struct
iw_point
*
erq
)
static
int
orinoco_ioctl_setessid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
erq
,
char
*
essidbuf
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
char
essidbuf
[
IW_ESSID_MAX_SIZE
+
1
];
unsigned
long
flags
;
/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
* anyway... - Jean II */
memset
(
&
essidbuf
,
0
,
sizeof
(
essidbuf
));
if
(
erq
->
flags
)
{
/* iwconfig includes the NUL in the specified length */
if
(
erq
->
length
>
IW_ESSID_MAX_SIZE
+
1
)
/* Hum... Should not use Wireless Extension constant (may change),
* should use our own... - Jean II */
if
(
erq
->
length
>
IW_ESSID_MAX_SIZE
)
return
-
E2BIG
;
if
(
copy_from_user
(
&
essidbuf
,
erq
->
pointer
,
erq
->
length
))
return
-
EFAULT
;
essidbuf
[
IW_ESSID_MAX_SIZE
]
=
'\0'
;
}
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
memcpy
(
priv
->
desired_essid
,
essidbuf
,
sizeof
(
priv
->
desired_essid
));
/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
memset
(
priv
->
desired_essid
,
0
,
sizeof
(
priv
->
desired_essid
));
/* If not ANY, get the new ESSID */
if
(
erq
->
flags
)
{
memcpy
(
priv
->
desired_essid
,
essidbuf
,
erq
->
length
);
}
orinoco_unlock
(
priv
,
&
flags
);
return
0
;
return
-
EINPROGRESS
;
/* Call commit handler */
}
static
int
orinoco_ioctl_getessid
(
struct
net_device
*
dev
,
struct
iw_point
*
erq
)
static
int
orinoco_ioctl_getessid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
erq
,
char
*
essidbuf
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
char
essidbuf
[
IW_ESSID_MAX_SIZE
+
1
];
int
active
;
int
err
=
0
;
unsigned
long
flags
;
...
...
@@ -2956,51 +3063,46 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
}
else
{
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
memcpy
(
essidbuf
,
priv
->
desired_essid
,
sizeof
(
essidbuf
)
);
memcpy
(
essidbuf
,
priv
->
desired_essid
,
IW_ESSID_MAX_SIZE
+
1
);
orinoco_unlock
(
priv
,
&
flags
);
}
erq
->
flags
=
1
;
erq
->
length
=
strlen
(
essidbuf
)
+
1
;
if
(
erq
->
pointer
)
if
(
copy_to_user
(
erq
->
pointer
,
essidbuf
,
erq
->
length
))
return
-
EFAULT
;
TRACE_EXIT
(
dev
->
name
);
return
0
;
}
static
int
orinoco_ioctl_setnick
(
struct
net_device
*
dev
,
struct
iw_point
*
nrq
)
static
int
orinoco_ioctl_setnick
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
nrq
,
char
*
nickbuf
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
char
nickbuf
[
IW_ESSID_MAX_SIZE
+
1
];
unsigned
long
flags
;
if
(
nrq
->
length
>
IW_ESSID_MAX_SIZE
)
return
-
E2BIG
;
memset
(
nickbuf
,
0
,
sizeof
(
nickbuf
));
if
(
copy_from_user
(
nickbuf
,
nrq
->
pointer
,
nrq
->
length
))
return
-
EFAULT
;
nickbuf
[
nrq
->
length
]
=
'\0'
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
memcpy
(
priv
->
nick
,
nickbuf
,
sizeof
(
priv
->
nick
));
memset
(
priv
->
nick
,
0
,
sizeof
(
priv
->
nick
));
memcpy
(
priv
->
nick
,
nickbuf
,
nrq
->
length
);
orinoco_unlock
(
priv
,
&
flags
);
return
0
;
return
-
EINPROGRESS
;
/* Call commit handler */
}
static
int
orinoco_ioctl_getnick
(
struct
net_device
*
dev
,
struct
iw_point
*
nrq
)
static
int
orinoco_ioctl_getnick
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
nrq
,
char
*
nickbuf
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
char
nickbuf
[
IW_ESSID_MAX_SIZE
+
1
];
unsigned
long
flags
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
...
...
@@ -3011,23 +3113,22 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
nrq
->
length
=
strlen
(
nickbuf
)
+
1
;
if
(
copy_to_user
(
nrq
->
pointer
,
nickbuf
,
sizeof
(
nickbuf
)))
return
-
EFAULT
;
return
0
;
}
static
int
orinoco_ioctl_setfreq
(
struct
net_device
*
dev
,
struct
iw_freq
*
frq
)
static
int
orinoco_ioctl_setfreq
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_freq
*
frq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
chan
=
-
1
;
unsigned
long
flags
;
int
err
=
-
EINPROGRESS
;
/* Call commit handler */
/* We can only use this in Ad-Hoc demo mode to set the operating
* frequency, or in IBSS mode to set the frequency where the IBSS
* will be created - Jean II */
if
(
priv
->
iw_mode
!=
IW_MODE_ADHOC
)
return
-
EOPNOTSUPP
;
/* In infrastructure mode the AP sets the channel */
if
(
priv
->
iw_mode
==
IW_MODE_INFRA
)
return
-
EBUSY
;
if
(
(
frq
->
e
==
0
)
&&
(
frq
->
m
<=
1000
)
)
{
/* Setting by channel number */
...
...
@@ -3051,13 +3152,44 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
priv
->
channel
=
chan
;
if
(
priv
->
iw_mode
==
IW_MODE_MONITOR
)
{
/* Fast channel change - no commit if successful */
hermes_t
*
hw
=
&
priv
->
hw
;
err
=
hermes_docmd_wait
(
hw
,
HERMES_CMD_TEST
|
HERMES_TEST_SET_CHANNEL
,
chan
,
NULL
);
}
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
static
int
orinoco_ioctl_getfreq
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_freq
*
frq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
tmp
;
/* Locking done in there */
tmp
=
orinoco_hw_get_freq
(
priv
);
if
(
tmp
<
0
)
{
return
tmp
;
}
frq
->
m
=
tmp
;
frq
->
e
=
1
;
return
0
;
}
static
int
orinoco_ioctl_getsens
(
struct
net_device
*
dev
,
struct
iw_param
*
srq
)
static
int
orinoco_ioctl_getsens
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
srq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
hermes_t
*
hw
=
&
priv
->
hw
;
...
...
@@ -3083,7 +3215,10 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
return
0
;
}
static
int
orinoco_ioctl_setsens
(
struct
net_device
*
dev
,
struct
iw_param
*
srq
)
static
int
orinoco_ioctl_setsens
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
srq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
val
=
srq
->
value
;
...
...
@@ -3100,10 +3235,13 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
priv
->
ap_density
=
val
;
orinoco_unlock
(
priv
,
&
flags
);
return
0
;
return
-
EINPROGRESS
;
/* Call commit handler */
}
static
int
orinoco_ioctl_setrts
(
struct
net_device
*
dev
,
struct
iw_param
*
rrq
)
static
int
orinoco_ioctl_setrts
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
rrq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
val
=
rrq
->
value
;
...
...
@@ -3121,13 +3259,30 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
priv
->
rts_thresh
=
val
;
orinoco_unlock
(
priv
,
&
flags
);
return
-
EINPROGRESS
;
/* Call commit handler */
}
static
int
orinoco_ioctl_getrts
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
rrq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
rrq
->
value
=
priv
->
rts_thresh
;
rrq
->
disabled
=
(
rrq
->
value
==
2347
);
rrq
->
fixed
=
1
;
return
0
;
}
static
int
orinoco_ioctl_setfrag
(
struct
net_device
*
dev
,
struct
iw_param
*
frq
)
static
int
orinoco_ioctl_setfrag
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
frq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
err
=
0
;
int
err
=
-
EINPROGRESS
;
/* Call commit handler */
unsigned
long
flags
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
...
...
@@ -3159,11 +3314,14 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
return
err
;
}
static
int
orinoco_ioctl_getfrag
(
struct
net_device
*
dev
,
struct
iw_param
*
frq
)
static
int
orinoco_ioctl_getfrag
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
frq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
hermes_t
*
hw
=
&
priv
->
hw
;
int
err
=
0
;
int
err
;
u16
val
;
unsigned
long
flags
;
...
...
@@ -3196,10 +3354,12 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
return
err
;
}
static
int
orinoco_ioctl_setrate
(
struct
net_device
*
dev
,
struct
iw_param
*
rrq
)
static
int
orinoco_ioctl_setrate
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
rrq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
err
=
0
;
int
ratemode
=
-
1
;
int
bitrate
;
/* 100s of kilobits */
int
i
;
...
...
@@ -3235,10 +3395,13 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
priv
->
bitratemode
=
ratemode
;
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
return
-
EINPROGRESS
;
}
static
int
orinoco_ioctl_getrate
(
struct
net_device
*
dev
,
struct
iw_param
*
rrq
)
static
int
orinoco_ioctl_getrate
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
rrq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
hermes_t
*
hw
=
&
priv
->
hw
;
...
...
@@ -3303,10 +3466,13 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
return
err
;
}
static
int
orinoco_ioctl_setpower
(
struct
net_device
*
dev
,
struct
iw_param
*
prq
)
static
int
orinoco_ioctl_setpower
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
prq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
err
=
0
;
int
err
=
-
EINPROGRESS
;
/* Call commit handler */
unsigned
long
flags
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
...
...
@@ -3355,7 +3521,10 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
return
err
;
}
static
int
orinoco_ioctl_getpower
(
struct
net_device
*
dev
,
struct
iw_param
*
prq
)
static
int
orinoco_ioctl_getpower
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
prq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
hermes_t
*
hw
=
&
priv
->
hw
;
...
...
@@ -3403,7 +3572,10 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
return
err
;
}
static
int
orinoco_ioctl_getretry
(
struct
net_device
*
dev
,
struct
iw_param
*
rrq
)
static
int
orinoco_ioctl_getretry
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
rrq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
hermes_t
*
hw
=
&
priv
->
hw
;
...
...
@@ -3454,10 +3626,38 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
return
err
;
}
static
int
orinoco_ioctl_setibssport
(
struct
net_device
*
dev
,
struct
iwreq
*
wrq
)
static
int
orinoco_ioctl_reset
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
void
*
wrqu
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
info
->
cmd
==
(
SIOCIWFIRSTPRIV
+
0x1
))
{
printk
(
KERN_DEBUG
"%s: Forcing reset!
\n
"
,
dev
->
name
);
/* Firmware reset */
orinoco_reset
(
dev
);
}
else
{
printk
(
KERN_DEBUG
"%s: Force scheduling reset!
\n
"
,
dev
->
name
);
schedule_work
(
&
priv
->
reset_work
);
}
return
0
;
}
static
int
orinoco_ioctl_setibssport
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
void
*
wrqu
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
val
=
*
(
(
int
*
)
wrq
->
u
.
name
);
int
val
=
*
(
(
int
*
)
extra
);
unsigned
long
flags
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
...
...
@@ -3469,28 +3669,28 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
set_port_type
(
priv
);
orinoco_unlock
(
priv
,
&
flags
);
return
0
;
return
-
EINPROGRESS
;
/* Call commit handler */
}
static
int
orinoco_ioctl_getibssport
(
struct
net_device
*
dev
,
struct
iwreq
*
wrq
)
static
int
orinoco_ioctl_getibssport
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
void
*
wrqu
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
*
val
=
(
int
*
)
wrq
->
u
.
name
;
unsigned
long
flags
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
int
*
val
=
(
int
*
)
extra
;
*
val
=
priv
->
ibss_port
;
orinoco_unlock
(
priv
,
&
flags
);
return
0
;
}
static
int
orinoco_ioctl_setport3
(
struct
net_device
*
dev
,
struct
iwreq
*
wrq
)
static
int
orinoco_ioctl_setport3
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
void
*
wrqu
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
val
=
*
(
(
int
*
)
wrq
->
u
.
name
);
int
val
=
*
(
(
int
*
)
extra
);
int
err
=
0
;
unsigned
long
flags
;
...
...
@@ -3519,51 +3719,131 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
err
=
-
EINVAL
;
}
if
(
!
err
)
if
(
!
err
)
{
/* Actually update the mode we are using */
set_port_type
(
priv
);
err
=
-
EINPROGRESS
;
}
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
static
int
orinoco_ioctl_getport3
(
struct
net_device
*
dev
,
struct
iwreq
*
wrq
)
static
int
orinoco_ioctl_getport3
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
void
*
wrqu
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
*
val
=
(
int
*
)
extra
;
*
val
=
priv
->
prefer_port3
;
return
0
;
}
static
int
orinoco_ioctl_setpreamble
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
void
*
wrqu
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
*
val
=
(
int
*
)
wrq
->
u
.
name
;
unsigned
long
flags
;
int
val
;
if
(
!
priv
->
has_preamble
)
return
-
EOPNOTSUPP
;
/* 802.11b has recently defined some short preamble.
* Basically, the Phy header has been reduced in size.
* This increase performance, especially at high rates
* (the preamble is transmitted at 1Mb/s), unfortunately
* this give compatibility troubles... - Jean II */
val
=
*
(
(
int
*
)
extra
);
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
*
val
=
priv
->
prefer_port3
;
if
(
val
)
priv
->
preamble
=
1
;
else
priv
->
preamble
=
0
;
orinoco_unlock
(
priv
,
&
flags
);
return
-
EINPROGRESS
;
/* Call commit handler */
}
static
int
orinoco_ioctl_getpreamble
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
void
*
wrqu
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
*
val
=
(
int
*
)
extra
;
if
(
!
priv
->
has_preamble
)
return
-
EOPNOTSUPP
;
*
val
=
priv
->
preamble
;
return
0
;
}
/* ioctl interface to hermes_read_ltv()
* To use with iwpriv, pass the RID as the token argument, e.g.
* iwpriv get_rid [0xfc00]
* At least Wireless Tools 25 is required to use iwpriv.
* For Wireless Tools 25 and 26 append "dummy" are the end. */
static
int
orinoco_ioctl_getrid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
data
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
hermes_t
*
hw
=
&
priv
->
hw
;
int
rid
=
data
->
flags
;
u16
length
;
int
err
;
unsigned
long
flags
;
/* It's a "get" function, but we don't want users to access the
* WEP key and other raw firmware data */
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
rid
<
0xfc00
||
rid
>
0xffff
)
return
-
EINVAL
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
err
=
hermes_read_ltv
(
hw
,
USER_BAP
,
rid
,
MAX_RID_LEN
,
&
length
,
extra
);
if
(
err
)
goto
out
;
data
->
length
=
min_t
(
u16
,
HERMES_RECLEN_TO_BYTES
(
length
),
MAX_RID_LEN
);
out:
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
/* Spy is used for link quality/strength measurements in Ad-Hoc mode
* Jean II */
static
int
orinoco_ioctl_setspy
(
struct
net_device
*
dev
,
struct
iw_point
*
srq
)
static
int
orinoco_ioctl_setspy
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
srq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
sockaddr
address
[
IW_MAX_SPY
]
;
struct
sockaddr
*
address
=
(
struct
sockaddr
*
)
extra
;
int
number
=
srq
->
length
;
int
i
;
int
err
=
0
;
unsigned
long
flags
;
/* Check the number of addresses */
if
(
number
>
IW_MAX_SPY
)
return
-
E2BIG
;
/* Get the data in the driver */
if
(
srq
->
pointer
)
{
if
(
copy_from_user
(
address
,
srq
->
pointer
,
sizeof
(
struct
sockaddr
)
*
number
))
return
-
EFAULT
;
}
/* Make sure nobody mess with the structure while we do */
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
...
...
@@ -3587,14 +3867,17 @@ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
/* Now, let the others play */
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
/* Do NOT call commit handler */
return
0
;
}
static
int
orinoco_ioctl_getspy
(
struct
net_device
*
dev
,
struct
iw_point
*
srq
)
static
int
orinoco_ioctl_getspy
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
srq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
sockaddr
address
[
IW_MAX_SPY
];
struct
iw_quality
spy_stat
[
IW_MAX_SPY
];
struct
sockaddr
*
address
=
(
struct
sockaddr
*
)
extra
;
int
number
;
int
i
;
unsigned
long
flags
;
...
...
@@ -3603,7 +3886,12 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
return
-
EBUSY
;
number
=
priv
->
spy_number
;
if
((
number
>
0
)
&&
(
srq
->
pointer
))
{
/* Create address struct */
for
(
i
=
0
;
i
<
number
;
i
++
)
{
memcpy
(
address
[
i
].
sa_data
,
priv
->
spy_address
[
i
],
ETH_ALEN
);
address
[
i
].
sa_family
=
AF_UNIX
;
}
if
(
number
>
0
)
{
/* Create address struct */
for
(
i
=
0
;
i
<
number
;
i
++
)
{
memcpy
(
address
[
i
].
sa_data
,
priv
->
spy_address
[
i
],
...
...
@@ -3614,344 +3902,503 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
/* In theory, we should disable irqs while copying the stats
* because the rx path might update it in the middle...
* Bah, who care ? - Jean II */
memcpy
(
&
spy_stat
,
priv
->
spy_stat
,
sizeof
(
struct
iw_quality
)
*
IW_MAX_SPY
);
for
(
i
=
0
;
i
<
number
;
i
++
)
priv
->
spy_stat
[
i
].
updated
=
0
;
memcpy
(
extra
+
(
sizeof
(
struct
sockaddr
)
*
number
),
priv
->
spy_stat
,
sizeof
(
struct
iw_quality
)
*
number
);
}
/* Reset updated flags. */
for
(
i
=
0
;
i
<
number
;
i
++
)
priv
->
spy_stat
[
i
].
updated
=
0
;
orinoco_unlock
(
priv
,
&
flags
);
/* Push stuff to user space */
srq
->
length
=
number
;
if
(
copy_to_user
(
srq
->
pointer
,
address
,
sizeof
(
struct
sockaddr
)
*
number
))
return
-
EFAULT
;
if
(
copy_to_user
(
srq
->
pointer
+
(
sizeof
(
struct
sockaddr
)
*
number
),
&
spy_stat
,
sizeof
(
struct
iw_quality
)
*
number
))
return
-
EFAULT
;
return
0
;
}
static
int
orinoco_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
/* Trigger a scan (look for other cells in the vicinity */
static
int
orinoco_ioctl_setscan
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_param
*
srq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
iwreq
*
wrq
=
(
struct
iwreq
*
)
rq
;
hermes_t
*
hw
=
&
priv
->
hw
;
int
err
=
0
;
int
tmp
;
int
changed
=
0
;
unsigned
long
flags
;
TRACE_ENTER
(
dev
->
name
);
/* In theory, we could allow most of the the SET stuff to be
* done. In practice, the lapse of time at startup when the
* card is not ready is very short, so why bother... Note
* that netif_device_present is different from up/down
* (ifconfig), when the device is not yet up, it is usually
* already ready... Jean II */
if
(
!
netif_device_present
(
dev
))
return
-
ENODEV
;
switch
(
cmd
)
{
case
SIOCGIWNAME
:
strcpy
(
wrq
->
u
.
name
,
"IEEE 802.11-DS"
);
break
;
case
SIOCGIWAP
:
wrq
->
u
.
ap_addr
.
sa_family
=
ARPHRD_ETHER
;
err
=
orinoco_hw_get_bssid
(
priv
,
wrq
->
u
.
ap_addr
.
sa_data
);
break
;
case
SIOCGIWRANGE
:
err
=
orinoco_ioctl_getiwrange
(
dev
,
&
wrq
->
u
.
data
);
break
;
/* Note : you may have realised that, as this is a SET operation,
* this is priviledged and therefore a normal user can't
* perform scanning.
* This is not an error, while the device perform scanning,
* traffic doesn't flow, so it's a perfect DoS...
* Jean II */
case
SIOCSIWMODE
:
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
switch
(
wrq
->
u
.
mode
)
{
case
IW_MODE_ADHOC
:
if
(
!
(
priv
->
has_ibss
||
priv
->
has_port3
)
)
err
=
-
EINVAL
;
else
{
priv
->
iw_mode
=
IW_MODE_ADHOC
;
changed
=
1
;
}
break
;
case
IW_MODE_INFRA
:
priv
->
iw_mode
=
IW_MODE_INFRA
;
changed
=
1
;
break
;
default:
err
=
-
EINVAL
;
break
;
/* Scanning with port 0 disabled would fail */
if
(
!
netif_running
(
dev
))
{
err
=
-
ENETDOWN
;
goto
out
;
}
set_port_type
(
priv
);
orinoco_unlock
(
priv
,
&
flags
);
break
;
case
SIOCGIWMODE
:
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
wrq
->
u
.
mode
=
priv
->
iw_mode
;
orinoco_unlock
(
priv
,
&
flags
);
break
;
/* In monitor mode, the scan results are always empty.
* Probe responses are passed to the driver as received
* frames and could be processed in software. */
if
(
priv
->
iw_mode
==
IW_MODE_MONITOR
)
{
err
=
-
EOPNOTSUPP
;
goto
out
;
}
case
SIOCSIWENCODE
:
err
=
orinoco_ioctl_setiwencode
(
dev
,
&
wrq
->
u
.
encoding
);
if
(
!
err
)
changed
=
1
;
break
;
/* Note : because we don't lock out the irq handler, the way
* we access scan variables in priv is critical.
* o scan_inprogress : not touched by irq handler
* o scan_mode : not touched by irq handler
* o scan_result : irq is strict producer, non-irq is strict
* consumer.
* o scan_len : synchronised with scan_result
* Before modifying anything on those variables, please think hard !
* Jean II */
case
SIOCGIWENCODE
:
if
(
!
capable
(
CAP_NET_ADMIN
))
{
err
=
-
EPERM
;
break
;
/* If there is still some left-over scan results, get rid of it */
if
(
priv
->
scan_result
!=
NULL
)
{
/* What's likely is that a client did crash or was killed
* between triggering the scan request and reading the
* results, so we need to reset everything.
* Some clients that are too slow may suffer from that...
* Jean II */
kfree
(
priv
->
scan_result
);
priv
->
scan_result
=
NULL
;
}
err
=
orinoco_ioctl_getiwencode
(
dev
,
&
wrq
->
u
.
encoding
);
break
;
/* Save flags */
priv
->
scan_mode
=
srq
->
flags
;
case
SIOCSIWESSID
:
err
=
orinoco_ioctl_setessid
(
dev
,
&
wrq
->
u
.
essid
);
if
(
!
err
)
changed
=
1
;
break
;
/* Always trigger scanning, even if it's in progress.
* This way, if the info frame get lost, we will recover somewhat
* gracefully - Jean II */
case
SIOCGIWESSID
:
err
=
orinoco_ioctl_getessid
(
dev
,
&
wrq
->
u
.
essid
);
if
(
priv
->
has_hostscan
)
{
switch
(
priv
->
firmware_type
)
{
case
FIRMWARE_TYPE_SYMBOL
:
err
=
hermes_write_wordrec
(
hw
,
USER_BAP
,
HERMES_RID_CNFHOSTSCAN_SYMBOL
,
HERMES_HOSTSCAN_SYMBOL_ONCE
|
HERMES_HOSTSCAN_SYMBOL_BCAST
);
break
;
case
FIRMWARE_TYPE_INTERSIL
:
{
u16
req
[
3
];
case
SIOCSIWNICKN
:
err
=
orinoco_ioctl_setnick
(
dev
,
&
wrq
->
u
.
data
);
if
(
!
err
)
changed
=
1
;
req
[
0
]
=
cpu_to_le16
(
0x3fff
);
/* All channels */
req
[
1
]
=
cpu_to_le16
(
0x0001
);
/* rate 1 Mbps */
req
[
2
]
=
0
;
/* Any ESSID */
err
=
HERMES_WRITE_RECORD
(
hw
,
USER_BAP
,
HERMES_RID_CNFHOSTSCAN
,
&
req
);
}
break
;
case
SIOCGIWNICKN
:
err
=
orinoco_ioctl_getnick
(
dev
,
&
wrq
->
u
.
data
);
case
FIRMWARE_TYPE_AGERE
:
err
=
hermes_write_wordrec
(
hw
,
USER_BAP
,
HERMES_RID_CNFSCANSSID_AGERE
,
0
);
/* Any ESSID */
if
(
err
)
break
;
case
SIOCGIWFREQ
:
tmp
=
orinoco_hw_get_freq
(
priv
);
if
(
tmp
<
0
)
{
err
=
tmp
;
}
else
{
wrq
->
u
.
freq
.
m
=
tmp
;
wrq
->
u
.
freq
.
e
=
1
;
}
err
=
hermes_inquire
(
hw
,
HERMES_INQ_SCAN
);
break
;
}
}
else
err
=
hermes_inquire
(
hw
,
HERMES_INQ_SCAN
);
case
SIOCSIWFREQ
:
err
=
orinoco_ioctl_setfreq
(
dev
,
&
wrq
->
u
.
freq
);
/* One more client */
if
(
!
err
)
changed
=
1
;
break
;
priv
->
scan_inprogress
=
1
;
case
SIOCGIWSENS
:
err
=
orinoco_ioctl_getsens
(
dev
,
&
wrq
->
u
.
sens
);
break
;
out:
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
case
SIOCSIWSENS
:
err
=
orinoco_ioctl_setsens
(
dev
,
&
wrq
->
u
.
sens
);
if
(
!
err
)
changed
=
1
;
break
;
/* Translate scan data returned from the card to a card independant
* format that the Wireless Tools will understand - Jean II */
static
inline
int
orinoco_translate_scan
(
struct
net_device
*
dev
,
char
*
buffer
,
char
*
scan
,
int
scan_len
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
offset
;
/* In the scan data */
union
hermes_scan_info
*
atom
;
int
atom_len
;
u16
capabilities
;
u16
channel
;
struct
iw_event
iwe
;
/* Temporary buffer */
char
*
current_ev
=
buffer
;
char
*
end_buf
=
buffer
+
IW_SCAN_MAX_DATA
;
case
SIOCGIWRTS
:
wrq
->
u
.
rts
.
value
=
priv
->
rts_thresh
;
wrq
->
u
.
rts
.
disabled
=
(
wrq
->
u
.
rts
.
value
==
2347
);
wrq
->
u
.
rts
.
fixed
=
1
;
switch
(
priv
->
firmware_type
)
{
case
FIRMWARE_TYPE_AGERE
:
atom_len
=
sizeof
(
struct
agere_scan_apinfo
);
offset
=
0
;
break
;
case
SIOCSIWRTS
:
err
=
orinoco_ioctl_setrts
(
dev
,
&
wrq
->
u
.
rts
);
if
(
!
err
)
changed
=
1
;
case
FIRMWARE_TYPE_SYMBOL
:
/* Lack of documentation necessitates this hack.
* Different firmwares have 68 or 76 byte long atoms.
* We try modulo first. If the length divides by both,
* we check what would be the channel in the second
* frame for a 68-byte atom. 76-byte atoms have 0 there.
* Valid channel cannot be 0. */
if
(
scan_len
%
76
)
atom_len
=
68
;
else
if
(
scan_len
%
68
)
atom_len
=
76
;
else
if
(
scan_len
>=
1292
&&
scan
[
68
]
==
0
)
atom_len
=
76
;
else
atom_len
=
68
;
offset
=
0
;
break
;
case
SIOCSIWFRAG
:
err
=
orinoco_ioctl_setfrag
(
dev
,
&
wrq
->
u
.
frag
);
if
(
!
err
)
changed
=
1
;
case
FIRMWARE_TYPE_INTERSIL
:
offset
=
4
;
if
(
priv
->
has_hostscan
)
atom_len
=
scan
[
0
]
+
(
scan
[
1
]
<<
8
);
else
atom_len
=
offsetof
(
struct
prism2_scan_apinfo
,
atim
);
break
;
default:
return
0
;
}
case
SIOCGIWFRAG
:
err
=
orinoco_ioctl_getfrag
(
dev
,
&
wrq
->
u
.
frag
);
break
;
/* Check that we got an whole number of atoms */
if
((
scan_len
-
offset
)
%
atom_len
)
{
printk
(
KERN_ERR
"%s: Unexpected scan data length %d, "
"atom_len %d, offset %d
\n
"
,
dev
->
name
,
scan_len
,
atom_len
,
offset
);
return
0
;
}
case
SIOCSIWRATE
:
err
=
orinoco_ioctl_setrate
(
dev
,
&
wrq
->
u
.
bitrate
);
if
(
!
err
)
changed
=
1
;
break
;
/* Read the entries one by one */
for
(;
offset
+
atom_len
<=
scan_len
;
offset
+=
atom_len
)
{
/* Get next atom */
atom
=
(
union
hermes_scan_info
*
)
(
scan
+
offset
);
/* First entry *MUST* be the AP MAC address */
iwe
.
cmd
=
SIOCGIWAP
;
iwe
.
u
.
ap_addr
.
sa_family
=
ARPHRD_ETHER
;
memcpy
(
iwe
.
u
.
ap_addr
.
sa_data
,
atom
->
a
.
bssid
,
ETH_ALEN
);
current_ev
=
iwe_stream_add_event
(
current_ev
,
end_buf
,
&
iwe
,
IW_EV_ADDR_LEN
);
/* Other entries will be displayed in the order we give them */
/* Add the ESSID */
iwe
.
u
.
data
.
length
=
le16_to_cpu
(
atom
->
a
.
essid_len
);
if
(
iwe
.
u
.
data
.
length
>
32
)
iwe
.
u
.
data
.
length
=
32
;
iwe
.
cmd
=
SIOCGIWESSID
;
iwe
.
u
.
data
.
flags
=
1
;
current_ev
=
iwe_stream_add_point
(
current_ev
,
end_buf
,
&
iwe
,
atom
->
a
.
essid
);
/* Add mode */
iwe
.
cmd
=
SIOCGIWMODE
;
capabilities
=
le16_to_cpu
(
atom
->
a
.
capabilities
);
if
(
capabilities
&
0x3
)
{
if
(
capabilities
&
0x1
)
iwe
.
u
.
mode
=
IW_MODE_MASTER
;
else
iwe
.
u
.
mode
=
IW_MODE_ADHOC
;
current_ev
=
iwe_stream_add_event
(
current_ev
,
end_buf
,
&
iwe
,
IW_EV_UINT_LEN
);
}
channel
=
atom
->
s
.
channel
;
if
(
(
channel
>=
1
)
&&
(
channel
<=
NUM_CHANNELS
)
)
{
/* Add frequency */
iwe
.
cmd
=
SIOCGIWFREQ
;
iwe
.
u
.
freq
.
m
=
channel_frequency
[
channel
-
1
]
*
100000
;
iwe
.
u
.
freq
.
e
=
1
;
current_ev
=
iwe_stream_add_event
(
current_ev
,
end_buf
,
&
iwe
,
IW_EV_FREQ_LEN
);
}
/* Add quality statistics */
iwe
.
cmd
=
IWEVQUAL
;
iwe
.
u
.
qual
.
updated
=
0x10
;
/* no link quality */
iwe
.
u
.
qual
.
level
=
(
__u8
)
le16_to_cpu
(
atom
->
a
.
level
)
-
0x95
;
iwe
.
u
.
qual
.
noise
=
(
__u8
)
le16_to_cpu
(
atom
->
a
.
noise
)
-
0x95
;
/* Wireless tools prior to 27.pre22 will show link quality
* anyway, so we provide a reasonable value. */
if
(
iwe
.
u
.
qual
.
level
>
iwe
.
u
.
qual
.
noise
)
iwe
.
u
.
qual
.
qual
=
iwe
.
u
.
qual
.
level
-
iwe
.
u
.
qual
.
noise
;
else
iwe
.
u
.
qual
.
qual
=
0
;
current_ev
=
iwe_stream_add_event
(
current_ev
,
end_buf
,
&
iwe
,
IW_EV_QUAL_LEN
);
case
SIOCGIWRATE
:
err
=
orinoco_ioctl_getrate
(
dev
,
&
wrq
->
u
.
bitrate
);
break
;
/* Add encryption capability */
iwe
.
cmd
=
SIOCGIWENCODE
;
if
(
capabilities
&
0x10
)
iwe
.
u
.
data
.
flags
=
IW_ENCODE_ENABLED
|
IW_ENCODE_NOKEY
;
else
iwe
.
u
.
data
.
flags
=
IW_ENCODE_DISABLED
;
iwe
.
u
.
data
.
length
=
0
;
current_ev
=
iwe_stream_add_point
(
current_ev
,
end_buf
,
&
iwe
,
atom
->
a
.
essid
);
case
SIOCSIWPOWER
:
err
=
orinoco_ioctl_setpower
(
dev
,
&
wrq
->
u
.
power
);
if
(
!
err
)
changed
=
1
;
break
;
/* Bit rate is not available in Lucent/Agere firmwares */
if
(
priv
->
firmware_type
!=
FIRMWARE_TYPE_AGERE
)
{
char
*
current_val
=
current_ev
+
IW_EV_LCP_LEN
;
int
i
;
int
step
;
case
SIOCGIWPOWER
:
err
=
orinoco_ioctl_getpower
(
dev
,
&
wrq
->
u
.
power
);
if
(
priv
->
firmware_type
==
FIRMWARE_TYPE_SYMBOL
)
step
=
2
;
else
step
=
1
;
iwe
.
cmd
=
SIOCGIWRATE
;
/* Those two flags are ignored... */
iwe
.
u
.
bitrate
.
fixed
=
iwe
.
u
.
bitrate
.
disabled
=
0
;
/* Max 10 values */
for
(
i
=
0
;
i
<
10
;
i
+=
step
)
{
/* NULL terminated */
if
(
atom
->
p
.
rates
[
i
]
==
0x0
)
break
;
/* Bit rate given in 500 kb/s units (+ 0x80) */
iwe
.
u
.
bitrate
.
value
=
((
atom
->
p
.
rates
[
i
]
&
0x7f
)
*
500000
);
current_val
=
iwe_stream_add_value
(
current_ev
,
current_val
,
end_buf
,
&
iwe
,
IW_EV_PARAM_LEN
);
}
/* Check if we added any event */
if
((
current_val
-
current_ev
)
>
IW_EV_LCP_LEN
)
current_ev
=
current_val
;
}
case
SIOCGIWTXPOW
:
/* The card only supports one tx power, so this is easy */
wrq
->
u
.
txpower
.
value
=
15
;
/* dBm */
wrq
->
u
.
txpower
.
fixed
=
1
;
wrq
->
u
.
txpower
.
disabled
=
0
;
wrq
->
u
.
txpower
.
flags
=
IW_TXPOW_DBM
;
break
;
/* The other data in the scan result are not really
* interesting, so for now drop it - Jean II */
}
return
current_ev
-
buffer
;
}
case
SIOCSIWRETRY
:
err
=
-
EOPNOTSUPP
;
break
;
/* Return results of a scan */
static
int
orinoco_ioctl_getscan
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_point
*
srq
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
int
err
=
0
;
unsigned
long
flags
;
case
SIOCGIWRETRY
:
err
=
orinoco_ioctl_getretry
(
dev
,
&
wrq
->
u
.
retry
);
break
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
case
SIOCSIWSPY
:
err
=
orinoco_ioctl_setspy
(
dev
,
&
wrq
->
u
.
data
);
break
;
/* If no results yet, ask to try again later */
if
(
priv
->
scan_result
==
NULL
)
{
if
(
priv
->
scan_inprogress
)
/* Important note : we don't want to block the caller
* until results are ready for various reasons.
* First, managing wait queues is complex and racy.
* Second, we grab some rtnetlink lock before comming
* here (in dev_ioctl()).
* Third, we generate an Wireless Event, so the
* caller can wait itself on that - Jean II */
err
=
-
EAGAIN
;
else
/* Client error, no scan results...
* The caller need to restart the scan. */
err
=
-
ENODATA
;
}
else
{
/* We have some results to push back to user space */
case
SIOCGIWSPY
:
err
=
orinoco_ioctl_getspy
(
dev
,
&
wrq
->
u
.
data
);
break
;
/* Translate to WE format */
srq
->
length
=
orinoco_translate_scan
(
dev
,
extra
,
priv
->
scan_result
,
priv
->
scan_len
);
case
SIOCGIWPRIV
:
if
(
wrq
->
u
.
data
.
pointer
)
{
struct
iw_priv_args
privtab
[]
=
{
{
SIOCIWFIRSTPRIV
+
0x0
,
0
,
0
,
"force_reset"
},
{
SIOCIWFIRSTPRIV
+
0x1
,
0
,
0
,
"card_reset"
},
{
SIOCIWFIRSTPRIV
+
0x2
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"set_port3"
},
{
SIOCIWFIRSTPRIV
+
0x3
,
0
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
"get_port3"
},
{
SIOCIWFIRSTPRIV
+
0x4
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"set_preamble"
},
{
SIOCIWFIRSTPRIV
+
0x5
,
0
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
"get_preamble"
},
{
SIOCIWFIRSTPRIV
+
0x6
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"set_ibssport"
},
{
SIOCIWFIRSTPRIV
+
0x7
,
0
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
"get_ibssport"
},
};
/* Return flags */
srq
->
flags
=
(
__u16
)
priv
->
scan_mode
;
wrq
->
u
.
data
.
length
=
sizeof
(
privtab
)
/
sizeof
(
privtab
[
0
]);
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
privtab
,
sizeof
(
privtab
)))
err
=
-
EFAULT
;
}
break
;
/* Results are here, so scan no longer in progress */
priv
->
scan_inprogress
=
0
;
case
SIOCIWFIRSTPRIV
+
0x0
:
/* force_reset */
case
SIOCIWFIRSTPRIV
+
0x1
:
/* card_reset */
if
(
!
capable
(
CAP_NET_ADMIN
))
{
err
=
-
EPERM
;
break
;
/* In any case, Scan results will be cleaned up in the
* reset function and when exiting the driver.
* The person triggering the scanning may never come to
* pick the results, so we need to do it in those places.
* Jean II */
#ifdef SCAN_SINGLE_READ
/* If you enable this option, only one client (the first
* one) will be able to read the result (and only one
* time). If there is multiple concurent clients that
* want to read scan results, this behavior is not
* advisable - Jean II */
kfree
(
priv
->
scan_result
);
priv
->
scan_result
=
NULL
;
#endif
/* SCAN_SINGLE_READ */
/* Here, if too much time has elapsed since last scan,
* we may want to clean up scan results... - Jean II */
}
printk
(
KERN_DEBUG
"%s: Force scheduling reset!
\n
"
,
dev
->
name
);
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
schedule_work
(
&
priv
->
reset_work
);
break
;
/* Commit handler, called after set operations */
static
int
orinoco_ioctl_commit
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
void
*
wrqu
,
char
*
extra
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
hermes
*
hw
=
&
priv
->
hw
;
unsigned
long
flags
;
int
err
=
0
;
case
SIOCIWFIRSTPRIV
+
0x2
:
/* set_port3 */
if
(
!
capable
(
CAP_NET_ADMIN
))
{
err
=
-
EPERM
;
break
;
if
(
!
priv
->
open
)
return
0
;
if
(
priv
->
broken_disableport
)
{
orinoco_reset
(
dev
);
return
0
;
}
err
=
orinoco_ioctl_setport3
(
dev
,
wrq
);
if
(
!
err
)
changed
=
1
;
break
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
err
;
case
SIOCIWFIRSTPRIV
+
0x3
:
/* get_port3 */
err
=
orinoco_ioctl_getport3
(
dev
,
wrq
);
break
;
err
=
hermes_disable_port
(
hw
,
0
);
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Unable to disable port "
"while reconfiguring card
\n
"
,
dev
->
name
);
priv
->
broken_disableport
=
1
;
goto
out
;
}
case
SIOCIWFIRSTPRIV
+
0x4
:
/* set_preamble */
if
(
!
capable
(
CAP_NET_ADMIN
))
{
err
=
-
EPERM
;
break
;
err
=
__orinoco_program_rids
(
dev
);
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Unable to reconfigure card
\n
"
,
dev
->
name
);
goto
out
;
}
/* 802.11b has recently defined some short preamble.
* Basically, the Phy header has been reduced in size.
* This increase performance, especially at high rates
* (the preamble is transmitted at 1Mb/s), unfortunately
* this give compatibility troubles... - Jean II */
if
(
priv
->
has_preamble
)
{
int
val
=
*
(
(
int
*
)
wrq
->
u
.
name
);
err
=
hermes_enable_port
(
hw
,
0
);
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Unable to enable port while reconfiguring card
\n
"
,
dev
->
name
);
goto
out
;
}
out:
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Resetting instead...
\n
"
,
dev
->
name
);
schedule_work
(
&
priv
->
reset_work
);
err
=
0
;
}
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
if
(
val
)
priv
->
preamble
=
1
;
else
priv
->
preamble
=
0
;
orinoco_unlock
(
priv
,
&
flags
);
changed
=
1
;
}
else
err
=
-
EOPNOTSUPP
;
break
;
return
err
;
}
case
SIOCIWFIRSTPRIV
+
0x5
:
/* get_preamble */
if
(
priv
->
has_preamble
)
{
int
*
val
=
(
int
*
)
wrq
->
u
.
name
;
static
const
struct
iw_priv_args
orinoco_privtab
[]
=
{
{
SIOCIWFIRSTPRIV
+
0x0
,
0
,
0
,
"force_reset"
},
{
SIOCIWFIRSTPRIV
+
0x1
,
0
,
0
,
"card_reset"
},
{
SIOCIWFIRSTPRIV
+
0x2
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"set_port3"
},
{
SIOCIWFIRSTPRIV
+
0x3
,
0
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
"get_port3"
},
{
SIOCIWFIRSTPRIV
+
0x4
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"set_preamble"
},
{
SIOCIWFIRSTPRIV
+
0x5
,
0
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
"get_preamble"
},
{
SIOCIWFIRSTPRIV
+
0x6
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"set_ibssport"
},
{
SIOCIWFIRSTPRIV
+
0x7
,
0
,
IW_PRIV_TYPE_INT
|
IW_PRIV_SIZE_FIXED
|
1
,
"get_ibssport"
},
{
SIOCIWFIRSTPRIV
+
0x9
,
0
,
IW_PRIV_TYPE_BYTE
|
MAX_RID_LEN
,
"get_rid"
},
};
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
*
val
=
priv
->
preamble
;
orinoco_unlock
(
priv
,
&
flags
);
}
else
err
=
-
EOPNOTSUPP
;
break
;
case
SIOCIWFIRSTPRIV
+
0x6
:
/* set_ibssport */
if
(
!
capable
(
CAP_NET_ADMIN
))
{
err
=
-
EPERM
;
break
;
}
err
=
orinoco_ioctl_setibssport
(
dev
,
wrq
);
if
(
!
err
)
changed
=
1
;
break
;
/*
* Structures to export the Wireless Handlers
*/
case
SIOCIWFIRSTPRIV
+
0x7
:
/* get_ibssport */
err
=
orinoco_ioctl_getibssport
(
dev
,
wrq
);
break
;
static
const
iw_handler
orinoco_handler
[]
=
{
[
SIOCSIWCOMMIT
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_commit
,
[
SIOCGIWNAME
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getname
,
[
SIOCSIWFREQ
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setfreq
,
[
SIOCGIWFREQ
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getfreq
,
[
SIOCSIWMODE
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setmode
,
[
SIOCGIWMODE
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getmode
,
[
SIOCSIWSENS
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setsens
,
[
SIOCGIWSENS
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getsens
,
[
SIOCGIWRANGE
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getiwrange
,
[
SIOCSIWSPY
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setspy
,
[
SIOCGIWSPY
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getspy
,
[
SIOCSIWAP
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setwap
,
[
SIOCGIWAP
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getwap
,
[
SIOCSIWSCAN
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setscan
,
[
SIOCGIWSCAN
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getscan
,
[
SIOCSIWESSID
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setessid
,
[
SIOCGIWESSID
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getessid
,
[
SIOCSIWNICKN
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setnick
,
[
SIOCGIWNICKN
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getnick
,
[
SIOCSIWRATE
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setrate
,
[
SIOCGIWRATE
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getrate
,
[
SIOCSIWRTS
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setrts
,
[
SIOCGIWRTS
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getrts
,
[
SIOCSIWFRAG
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setfrag
,
[
SIOCGIWFRAG
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getfrag
,
[
SIOCGIWRETRY
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getretry
,
[
SIOCSIWENCODE
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setiwencode
,
[
SIOCGIWENCODE
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getiwencode
,
[
SIOCSIWPOWER
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setpower
,
[
SIOCGIWPOWER
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getpower
,
};
default:
err
=
-
EOPNOTSUPP
;
}
if
(
!
err
&&
changed
&&
netif_running
(
dev
))
{
err
=
orinoco_reconfigure
(
dev
);
}
/*
Added typecasting since we no longer use iwreq_data -- Moustafa
*/
static
const
iw_handler
orinoco_private_handler
[]
=
{
[
0
]
(
iw_handler
)
orinoco_ioctl_reset
,
[
1
]
(
iw_handler
)
orinoco_ioctl_reset
,
[
2
]
(
iw_handler
)
orinoco_ioctl_setport3
,
[
3
]
(
iw_handler
)
orinoco_ioctl_getport3
,
[
4
]
(
iw_handler
)
orinoco_ioctl_setpreamble
,
[
5
]
(
iw_handler
)
orinoco_ioctl_getpreamble
,
[
6
]
(
iw_handler
)
orinoco_ioctl_setibssport
,
[
7
]
(
iw_handler
)
orinoco_ioctl_getibssport
,
[
9
]
(
iw_handler
)
orinoco_ioctl_getrid
,
};
TRACE_EXIT
(
dev
->
name
);
static
const
struct
iw_handler_def
orinoco_handler_def
=
{
.
num_standard
=
ARRAY_SIZE
(
orinoco_handler
),
.
num_private
=
ARRAY_SIZE
(
orinoco_private_handler
),
.
num_private_args
=
ARRAY_SIZE
(
orinoco_privtab
),
.
standard
=
orinoco_handler
,
.
private
=
orinoco_private_handler
,
.
private_args
=
orinoco_privtab
,
};
return
err
;
static
void
orinoco_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
strncpy
(
info
->
driver
,
DRIVER_NAME
,
sizeof
(
info
->
driver
)
-
1
);
strncpy
(
info
->
version
,
DRIVER_VERSION
,
sizeof
(
info
->
version
)
-
1
);
strncpy
(
info
->
fw_version
,
priv
->
fw_name
,
sizeof
(
info
->
fw_version
)
-
1
);
if
(
dev
->
class_dev
.
dev
)
strncpy
(
info
->
bus_info
,
dev
->
class_dev
.
dev
->
bus_id
,
sizeof
(
info
->
bus_info
)
-
1
);
else
snprintf
(
info
->
bus_info
,
sizeof
(
info
->
bus_info
)
-
1
,
"PCMCIA %p"
,
priv
->
hw
.
iobase
);
}
static
struct
ethtool_ops
orinoco_ethtool_ops
=
{
.
get_drvinfo
=
orinoco_get_drvinfo
,
.
get_link
=
ethtool_op_get_link
,
};
/********************************************************************/
/* Debugging */
...
...
drivers/net/wireless/orinoco.h
View file @
9758d0f0
...
...
@@ -7,7 +7,7 @@
#ifndef _ORINOCO_H
#define _ORINOCO_H
#define DRIVER_VERSION "0.1
4alpha
2"
#define DRIVER_VERSION "0.1
5rc
2"
#include <linux/types.h>
#include <linux/spinlock.h>
...
...
@@ -22,6 +22,8 @@
#define WIRELESS_SPY // enable iwspy support
#define MAX_SCAN_LEN 4096
#define ORINOCO_MAX_KEY_SIZE 14
#define ORINOCO_MAX_KEYS 4
...
...
@@ -30,6 +32,20 @@ struct orinoco_key {
char
data
[
ORINOCO_MAX_KEY_SIZE
];
}
__attribute__
((
packed
));
struct
header_struct
{
/* 802.3 */
u8
dest
[
ETH_ALEN
];
u8
src
[
ETH_ALEN
];
u16
len
;
/* 802.2 */
u8
dsap
;
u8
ssap
;
u8
ctrl
;
/* SNAP */
u8
oui
[
3
];
u16
ethertype
;
}
__attribute__
((
packed
));
typedef
enum
{
FIRMWARE_TYPE_AGERE
,
FIRMWARE_TYPE_INTERSIL
,
...
...
@@ -48,6 +64,8 @@ struct orinoco_private {
/* driver state */
int
open
;
u16
last_linkstatus
;
struct
work_struct
join_work
;
struct
work_struct
wevent_work
;
/* Net device stuff */
struct
net_device
*
ndev
;
...
...
@@ -74,7 +92,9 @@ struct orinoco_private {
unsigned
int
has_pm
:
1
;
unsigned
int
has_preamble
:
1
;
unsigned
int
has_sensitivity
:
1
;
unsigned
int
has_hostscan
:
1
;
unsigned
int
broken_disableport
:
1
;
unsigned
int
broken_monitor
:
1
;
/* Configuration paramaters */
u32
iw_mode
;
...
...
@@ -84,6 +104,8 @@ struct orinoco_private {
int
bitratemode
;
char
nick
[
IW_ESSID_MAX_SIZE
+
1
];
char
desired_essid
[
IW_ESSID_MAX_SIZE
+
1
];
char
desired_bssid
[
ETH_ALEN
];
int
bssid_fixed
;
u16
frag_thresh
,
mwo_robust
;
u16
channel
;
u16
ap_density
,
rts_thresh
;
...
...
@@ -98,6 +120,12 @@ struct orinoco_private {
/* Configuration dependent variables */
int
port_type
,
createibss
;
int
promiscuous
,
mc_count
;
/* Scanning support */
int
scan_inprogress
;
/* Scan pending... */
u32
scan_mode
;
/* Type of scan done */
char
*
scan_result
;
/* Result of previous scan */
int
scan_len
;
/* Lenght of result */
};
#ifdef ORINOCO_DEBUG
...
...
include/net/ieee80211.h
0 → 100644
View file @
9758d0f0
/*
* Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
* remains copyright by the original authors
*
* Portions of the merged code are based on Host AP (software wireless
* LAN access point) driver for Intersil Prism2/2.5/3.
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
*
* Adaption to a generic IEEE 802.11 stack by James Ketrenos
* <jketreno@linux.intel.com>
* Copyright (c) 2004, Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See README and COPYING for
* more details.
*/
#ifndef IEEE80211_H
#define IEEE80211_H
#include <linux/if_ether.h>
/* ETH_ALEN */
#include <linux/kernel.h>
/* ARRAY_SIZE */
#if WIRELESS_EXT < 17
#define IW_QUAL_QUAL_INVALID 0x10
#define IW_QUAL_LEVEL_INVALID 0x20
#define IW_QUAL_NOISE_INVALID 0x40
#define IW_QUAL_QUAL_UPDATED 0x1
#define IW_QUAL_LEVEL_UPDATED 0x2
#define IW_QUAL_NOISE_UPDATED 0x4
#endif
#define IEEE80211_DATA_LEN 2304
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
6.2.1.1.2.
The figure in section 7.1.2 suggests a body size of up to 2312
bytes is allowed, which is a bit confusing, I suspect this
represents the 2304 bytes of real data, plus a possible 8 bytes of
WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
#define IEEE80211_HLEN 30
#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
struct
ieee80211_hdr
{
u16
frame_ctl
;
u16
duration_id
;
u8
addr1
[
ETH_ALEN
];
u8
addr2
[
ETH_ALEN
];
u8
addr3
[
ETH_ALEN
];
u16
seq_ctl
;
u8
addr4
[
ETH_ALEN
];
}
__attribute__
((
packed
));
struct
ieee80211_hdr_3addr
{
u16
frame_ctl
;
u16
duration_id
;
u8
addr1
[
ETH_ALEN
];
u8
addr2
[
ETH_ALEN
];
u8
addr3
[
ETH_ALEN
];
u16
seq_ctl
;
}
__attribute__
((
packed
));
enum
eap_type
{
EAP_PACKET
=
0
,
EAPOL_START
,
EAPOL_LOGOFF
,
EAPOL_KEY
,
EAPOL_ENCAP_ASF_ALERT
};
static
const
char
*
eap_types
[]
=
{
[
EAP_PACKET
]
=
"EAP-Packet"
,
[
EAPOL_START
]
=
"EAPOL-Start"
,
[
EAPOL_LOGOFF
]
=
"EAPOL-Logoff"
,
[
EAPOL_KEY
]
=
"EAPOL-Key"
,
[
EAPOL_ENCAP_ASF_ALERT
]
=
"EAPOL-Encap-ASF-Alert"
};
static
inline
const
char
*
eap_get_type
(
int
type
)
{
return
(
type
>=
ARRAY_SIZE
(
eap_types
))
?
"Unknown"
:
eap_types
[
type
];
}
struct
eapol
{
u8
snap
[
6
];
u16
ethertype
;
u8
version
;
u8
type
;
u16
length
;
}
__attribute__
((
packed
));
#define IEEE80211_3ADDR_LEN 24
#define IEEE80211_4ADDR_LEN 30
#define IEEE80211_FCS_LEN 4
#define MIN_FRAG_THRESHOLD 256U
#define MAX_FRAG_THRESHOLD 2346U
/* Frame control field constants */
#define IEEE80211_FCTL_VERS 0x0002
#define IEEE80211_FCTL_FTYPE 0x000c
#define IEEE80211_FCTL_STYPE 0x00f0
#define IEEE80211_FCTL_TODS 0x0100
#define IEEE80211_FCTL_FROMDS 0x0200
#define IEEE80211_FCTL_MOREFRAGS 0x0400
#define IEEE80211_FCTL_RETRY 0x0800
#define IEEE80211_FCTL_PM 0x1000
#define IEEE80211_FCTL_MOREDATA 0x2000
#define IEEE80211_FCTL_WEP 0x4000
#define IEEE80211_FCTL_ORDER 0x8000
#define IEEE80211_FTYPE_MGMT 0x0000
#define IEEE80211_FTYPE_CTL 0x0004
#define IEEE80211_FTYPE_DATA 0x0008
/* management */
#define IEEE80211_STYPE_ASSOC_REQ 0x0000
#define IEEE80211_STYPE_ASSOC_RESP 0x0010
#define IEEE80211_STYPE_REASSOC_REQ 0x0020
#define IEEE80211_STYPE_REASSOC_RESP 0x0030
#define IEEE80211_STYPE_PROBE_REQ 0x0040
#define IEEE80211_STYPE_PROBE_RESP 0x0050
#define IEEE80211_STYPE_BEACON 0x0080
#define IEEE80211_STYPE_ATIM 0x0090
#define IEEE80211_STYPE_DISASSOC 0x00A0
#define IEEE80211_STYPE_AUTH 0x00B0
#define IEEE80211_STYPE_DEAUTH 0x00C0
/* control */
#define IEEE80211_STYPE_PSPOLL 0x00A0
#define IEEE80211_STYPE_RTS 0x00B0
#define IEEE80211_STYPE_CTS 0x00C0
#define IEEE80211_STYPE_ACK 0x00D0
#define IEEE80211_STYPE_CFEND 0x00E0
#define IEEE80211_STYPE_CFENDACK 0x00F0
/* data */
#define IEEE80211_STYPE_DATA 0x0000
#define IEEE80211_STYPE_DATA_CFACK 0x0010
#define IEEE80211_STYPE_DATA_CFPOLL 0x0020
#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
#define IEEE80211_STYPE_NULLFUNC 0x0040
#define IEEE80211_STYPE_CFACK 0x0050
#define IEEE80211_STYPE_CFPOLL 0x0060
#define IEEE80211_STYPE_CFACKPOLL 0x0070
#define IEEE80211_SCTL_FRAG 0x000F
#define IEEE80211_SCTL_SEQ 0xFFF0
/* debug macros */
#ifdef CONFIG_IEEE80211_DEBUG
extern
u32
ieee80211_debug_level
;
#define IEEE80211_DEBUG(level, fmt, args...) \
do { if (ieee80211_debug_level & (level)) \
printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
#else
#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
#endif
/* CONFIG_IEEE80211_DEBUG */
/*
* To use the debug system;
*
* If you are defining a new debug classification, simply add it to the #define
* list here in the form of:
*
* #define IEEE80211_DL_xxxx VALUE
*
* shifting value to the left one bit from the previous entry. xxxx should be
* the name of the classification (for example, WEP)
*
* You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your
* classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want
* to send output to that classification.
*
* To add your debug level to the list of levels seen when you perform
*
* % cat /proc/net/ipw/debug_level
*
* you simply need to add your entry to the ipw_debug_levels array.
*
* If you do not see debug_level in /proc/net/ipw then you do not have
* CONFIG_IEEE80211_DEBUG defined in your kernel configuration
*
*/
#define IEEE80211_DL_INFO (1<<0)
#define IEEE80211_DL_WX (1<<1)
#define IEEE80211_DL_SCAN (1<<2)
#define IEEE80211_DL_STATE (1<<3)
#define IEEE80211_DL_MGMT (1<<4)
#define IEEE80211_DL_FRAG (1<<5)
#define IEEE80211_DL_EAP (1<<6)
#define IEEE80211_DL_DROP (1<<7)
#define IEEE80211_DL_TX (1<<8)
#define IEEE80211_DL_RX (1<<9)
#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a)
#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a)
#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a)
#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <linux/if_arp.h>
/* ARPHRD_ETHER */
#ifndef WIRELESS_SPY
#define WIRELESS_SPY // enable iwspy support
#endif
#include <net/iw_handler.h> // new driver API
#ifndef ETH_P_PAE
#define ETH_P_PAE 0x888E
/* Port Access Entity (IEEE 802.1X) */
#endif
/* ETH_P_PAE */
#define ETH_P_PREAUTH 0x88C7
/* IEEE 802.11i pre-authentication */
#ifndef ETH_P_80211_RAW
#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
#endif
/* IEEE 802.11 defines */
#define P80211_OUI_LEN 3
struct
ieee80211_snap_hdr
{
u8
dsap
;
/* always 0xAA */
u8
ssap
;
/* always 0xAA */
u8
ctrl
;
/* always 0x03 */
u8
oui
[
P80211_OUI_LEN
];
/* organizational universal id */
}
__attribute__
((
packed
));
#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ)
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_CHALLENGE_LEN 128
#define WLAN_CAPABILITY_BSS (1<<0)
#define WLAN_CAPABILITY_IBSS (1<<1)
#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
#define WLAN_CAPABILITY_PRIVACY (1<<4)
#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
#define WLAN_CAPABILITY_PBCC (1<<6)
#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
/* Status codes */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_CAPS_UNSUPPORTED 10
#define WLAN_STATUS_REASSOC_NO_ASSOC 11
#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
#define WLAN_STATUS_CHALLENGE_FAIL 15
#define WLAN_STATUS_AUTH_TIMEOUT 16
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
#define WLAN_STATUS_ASSOC_DENIED_RATES 18
/* 802.11b */
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
/* Reason codes */
#define WLAN_REASON_UNSPECIFIED 1
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
#define WLAN_REASON_DEAUTH_LEAVING 3
#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
#define WLAN_REASON_DISASSOC_AP_BUSY 5
#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
/* Information Element IDs */
#define WLAN_EID_SSID 0
#define WLAN_EID_SUPP_RATES 1
#define WLAN_EID_FH_PARAMS 2
#define WLAN_EID_DS_PARAMS 3
#define WLAN_EID_CF_PARAMS 4
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
#define WLAN_EID_CHALLENGE 16
#define WLAN_EID_RSN 48
#define WLAN_EID_GENERIC 221
#define IEEE80211_MGMT_HDR_LEN 24
#define IEEE80211_DATA_HDR3_LEN 24
#define IEEE80211_DATA_HDR4_LEN 30
#define IEEE80211_STATMASK_SIGNAL (1<<0)
#define IEEE80211_STATMASK_RSSI (1<<1)
#define IEEE80211_STATMASK_NOISE (1<<2)
#define IEEE80211_STATMASK_RATE (1<<3)
#define IEEE80211_STATMASK_WEMASK 0x7
#define IEEE80211_CCK_MODULATION (1<<0)
#define IEEE80211_OFDM_MODULATION (1<<1)
#define IEEE80211_24GHZ_BAND (1<<0)
#define IEEE80211_52GHZ_BAND (1<<1)
#define IEEE80211_CCK_RATE_1MB 0x02
#define IEEE80211_CCK_RATE_2MB 0x04
#define IEEE80211_CCK_RATE_5MB 0x0B
#define IEEE80211_CCK_RATE_11MB 0x16
#define IEEE80211_OFDM_RATE_6MB 0x0C
#define IEEE80211_OFDM_RATE_9MB 0x12
#define IEEE80211_OFDM_RATE_12MB 0x18
#define IEEE80211_OFDM_RATE_18MB 0x24
#define IEEE80211_OFDM_RATE_24MB 0x30
#define IEEE80211_OFDM_RATE_36MB 0x48
#define IEEE80211_OFDM_RATE_48MB 0x60
#define IEEE80211_OFDM_RATE_54MB 0x6C
#define IEEE80211_BASIC_RATE_MASK 0x80
#define IEEE80211_CCK_RATE_1MB_MASK (1<<0)
#define IEEE80211_CCK_RATE_2MB_MASK (1<<1)
#define IEEE80211_CCK_RATE_5MB_MASK (1<<2)
#define IEEE80211_CCK_RATE_11MB_MASK (1<<3)
#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4)
#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5)
#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6)
#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7)
#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8)
#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9)
#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10)
#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11)
#define IEEE80211_CCK_RATES_MASK 0x0000000F
#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
IEEE80211_CCK_RATE_2MB_MASK)
#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \
IEEE80211_CCK_RATE_5MB_MASK | \
IEEE80211_CCK_RATE_11MB_MASK)
#define IEEE80211_OFDM_RATES_MASK 0x00000FF0
#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \
IEEE80211_OFDM_RATE_12MB_MASK | \
IEEE80211_OFDM_RATE_24MB_MASK)
#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \
IEEE80211_OFDM_RATE_9MB_MASK | \
IEEE80211_OFDM_RATE_18MB_MASK | \
IEEE80211_OFDM_RATE_36MB_MASK | \
IEEE80211_OFDM_RATE_48MB_MASK | \
IEEE80211_OFDM_RATE_54MB_MASK)
#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
IEEE80211_CCK_DEFAULT_RATES_MASK)
#define IEEE80211_NUM_OFDM_RATES 8
#define IEEE80211_NUM_CCK_RATES 4
#define IEEE80211_OFDM_SHIFT_MASK_A 4
/* NOTE: This data is for statistical purposes; not all hardware provides this
* information for frames received. Not setting these will not cause
* any adverse affects. */
struct
ieee80211_rx_stats
{
u32
mac_time
;
s8
rssi
;
u8
signal
;
u8
noise
;
u16
rate
;
/* in 100 kbps */
u8
received_channel
;
u8
control
;
u8
mask
;
u8
freq
;
u16
len
;
};
/* IEEE 802.11 requires that STA supports concurrent reception of at least
* three fragmented frames. This define can be increased to support more
* concurrent frames, but it should be noted that each entry can consume about
* 2 kB of RAM and increasing cache size will slow down frame reassembly. */
#define IEEE80211_FRAG_CACHE_LEN 4
struct
ieee80211_frag_entry
{
unsigned
long
first_frag_time
;
unsigned
int
seq
;
unsigned
int
last_frag
;
struct
sk_buff
*
skb
;
u8
src_addr
[
ETH_ALEN
];
u8
dst_addr
[
ETH_ALEN
];
};
struct
ieee80211_stats
{
unsigned
int
tx_unicast_frames
;
unsigned
int
tx_multicast_frames
;
unsigned
int
tx_fragments
;
unsigned
int
tx_unicast_octets
;
unsigned
int
tx_multicast_octets
;
unsigned
int
tx_deferred_transmissions
;
unsigned
int
tx_single_retry_frames
;
unsigned
int
tx_multiple_retry_frames
;
unsigned
int
tx_retry_limit_exceeded
;
unsigned
int
tx_discards
;
unsigned
int
rx_unicast_frames
;
unsigned
int
rx_multicast_frames
;
unsigned
int
rx_fragments
;
unsigned
int
rx_unicast_octets
;
unsigned
int
rx_multicast_octets
;
unsigned
int
rx_fcs_errors
;
unsigned
int
rx_discards_no_buffer
;
unsigned
int
tx_discards_wrong_sa
;
unsigned
int
rx_discards_undecryptable
;
unsigned
int
rx_message_in_msg_fragments
;
unsigned
int
rx_message_in_bad_msg_fragments
;
};
struct
ieee80211_device
;
#define SEC_KEY_1 (1<<0)
#define SEC_KEY_2 (1<<1)
#define SEC_KEY_3 (1<<2)
#define SEC_KEY_4 (1<<3)
#define SEC_ACTIVE_KEY (1<<4)
#define SEC_AUTH_MODE (1<<5)
#define SEC_UNICAST_GROUP (1<<6)
#define SEC_LEVEL (1<<7)
#define SEC_ENABLED (1<<8)
#define SEC_LEVEL_0 0
/* None */
#define SEC_LEVEL_1 1
/* WEP 40 and 104 bit */
#define SEC_LEVEL_2 2
/* Level 1 + TKIP */
#define SEC_LEVEL_2_CKIP 3
/* Level 1 + CKIP */
#define SEC_LEVEL_3 4
/* Level 2 + CCMP */
#define WEP_KEYS 4
#define WEP_KEY_LEN 13
struct
ieee80211_security
{
u16
active_key
:
2
,
enabled:
1
,
auth_mode:
2
,
auth_algo:
4
,
unicast_uses_group:
1
;
u8
key_sizes
[
WEP_KEYS
];
u8
keys
[
WEP_KEYS
][
WEP_KEY_LEN
];
u8
level
;
u16
flags
;
}
__attribute__
((
packed
));
/*
802.11 data frame from AP
,-------------------------------------------------------------------.
Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
|------|------|---------|---------|---------|------|---------|------|
Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
| | tion | (BSSID) | | | ence | data | |
`-------------------------------------------------------------------'
Total: 28-2340 bytes
*/
struct
ieee80211_header_data
{
u16
frame_ctl
;
u16
duration_id
;
u8
addr1
[
6
];
u8
addr2
[
6
];
u8
addr3
[
6
];
u16
seq_ctrl
;
};
#define BEACON_PROBE_SSID_ID_POSITION 12
/* Management Frame Information Element Types */
#define MFIE_TYPE_SSID 0
#define MFIE_TYPE_RATES 1
#define MFIE_TYPE_FH_SET 2
#define MFIE_TYPE_DS_SET 3
#define MFIE_TYPE_CF_SET 4
#define MFIE_TYPE_TIM 5
#define MFIE_TYPE_IBSS_SET 6
#define MFIE_TYPE_CHALLENGE 16
#define MFIE_TYPE_RSN 48
#define MFIE_TYPE_RATES_EX 50
#define MFIE_TYPE_GENERIC 221
struct
ieee80211_info_element_hdr
{
u8
id
;
u8
len
;
}
__attribute__
((
packed
));
struct
ieee80211_info_element
{
u8
id
;
u8
len
;
u8
data
[
0
];
}
__attribute__
((
packed
));
/*
* These are the data types that can make up management packets
*
u16 auth_algorithm;
u16 auth_sequence;
u16 beacon_interval;
u16 capability;
u8 current_ap[ETH_ALEN];
u16 listen_interval;
struct {
u16 association_id:14, reserved:2;
} __attribute__ ((packed));
u32 time_stamp[2];
u16 reason;
u16 status;
*/
struct
ieee80211_authentication
{
struct
ieee80211_header_data
header
;
u16
algorithm
;
u16
transaction
;
u16
status
;
struct
ieee80211_info_element
info_element
;
}
__attribute__
((
packed
));
struct
ieee80211_probe_response
{
struct
ieee80211_header_data
header
;
u32
time_stamp
[
2
];
u16
beacon_interval
;
u16
capability
;
struct
ieee80211_info_element
info_element
;
}
__attribute__
((
packed
));
struct
ieee80211_assoc_request_frame
{
u16
capability
;
u16
listen_interval
;
u8
current_ap
[
ETH_ALEN
];
struct
ieee80211_info_element
info_element
;
}
__attribute__
((
packed
));
struct
ieee80211_assoc_response_frame
{
struct
ieee80211_hdr_3addr
header
;
u16
capability
;
u16
status
;
u16
aid
;
struct
ieee80211_info_element
info_element
;
/* supported rates */
}
__attribute__
((
packed
));
struct
ieee80211_txb
{
u8
nr_frags
;
u8
encrypted
;
u16
reserved
;
u16
frag_size
;
u16
payload_size
;
struct
sk_buff
*
fragments
[
0
];
};
/* SWEEP TABLE ENTRIES NUMBER*/
#define MAX_SWEEP_TAB_ENTRIES 42
#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
* only use 8, and then use extended rates for the remaining supported
* rates. Other APs, however, stick all of their supported rates on the
* main rates information element... */
#define MAX_RATES_LENGTH ((u8)12)
#define MAX_RATES_EX_LENGTH ((u8)16)
#define MAX_NETWORK_COUNT 128
#define CRC_LENGTH 4U
#define MAX_WPA_IE_LEN 64
#define NETWORK_EMPTY_ESSID (1<<0)
#define NETWORK_HAS_OFDM (1<<1)
#define NETWORK_HAS_CCK (1<<2)
struct
ieee80211_network
{
/* These entries are used to identify a unique network */
u8
bssid
[
ETH_ALEN
];
u8
channel
;
/* Ensure null-terminated for any debug msgs */
u8
ssid
[
IW_ESSID_MAX_SIZE
+
1
];
u8
ssid_len
;
/* These are network statistics */
struct
ieee80211_rx_stats
stats
;
u16
capability
;
u8
rates
[
MAX_RATES_LENGTH
];
u8
rates_len
;
u8
rates_ex
[
MAX_RATES_EX_LENGTH
];
u8
rates_ex_len
;
unsigned
long
last_scanned
;
u8
mode
;
u8
flags
;
u32
last_associate
;
u32
time_stamp
[
2
];
u16
beacon_interval
;
u16
listen_interval
;
u16
atim_window
;
u8
wpa_ie
[
MAX_WPA_IE_LEN
];
size_t
wpa_ie_len
;
u8
rsn_ie
[
MAX_WPA_IE_LEN
];
size_t
rsn_ie_len
;
struct
list_head
list
;
};
enum
ieee80211_state
{
IEEE80211_UNINITIALIZED
=
0
,
IEEE80211_INITIALIZED
,
IEEE80211_ASSOCIATING
,
IEEE80211_ASSOCIATED
,
IEEE80211_AUTHENTICATING
,
IEEE80211_AUTHENTICATED
,
IEEE80211_SHUTDOWN
};
#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
#define DEFAULT_FTS 2346
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
extern
inline
int
is_broadcast_ether_addr
(
const
u8
*
addr
)
{
return
((
addr
[
0
]
==
0xff
)
&&
(
addr
[
1
]
==
0xff
)
&&
(
addr
[
2
]
==
0xff
)
&&
\
(
addr
[
3
]
==
0xff
)
&&
(
addr
[
4
]
==
0xff
)
&&
(
addr
[
5
]
==
0xff
));
}
#define CFG_IEEE80211_RESERVE_FCS (1<<0)
#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
struct
ieee80211_device
{
struct
net_device
*
dev
;
/* Bookkeeping structures */
struct
net_device_stats
stats
;
struct
ieee80211_stats
ieee_stats
;
/* Probe / Beacon management */
struct
list_head
network_free_list
;
struct
list_head
network_list
;
struct
ieee80211_network
*
networks
;
int
scans
;
int
scan_age
;
int
iw_mode
;
/* operating mode (IW_MODE_*) */
spinlock_t
lock
;
int
tx_headroom
;
/* Set to size of any additional room needed at front
* of allocated Tx SKBs */
u32
config
;
/* WEP and other encryption related settings at the device level */
int
open_wep
;
/* Set to 1 to allow unencrypted frames */
int
reset_on_keychange
;
/* Set to 1 if the HW needs to be reset on
* WEP key changes */
/* If the host performs {en,de}cryption, then set to 1 */
int
host_encrypt
;
int
host_decrypt
;
int
ieee802_1x
;
/* is IEEE 802.1X used */
/* WPA data */
int
wpa_enabled
;
int
drop_unencrypted
;
int
tkip_countermeasures
;
int
privacy_invoked
;
size_t
wpa_ie_len
;
u8
*
wpa_ie
;
struct
list_head
crypt_deinit_list
;
struct
ieee80211_crypt_data
*
crypt
[
WEP_KEYS
];
int
tx_keyidx
;
/* default TX key index (crypt[tx_keyidx]) */
struct
timer_list
crypt_deinit_timer
;
int
bcrx_sta_key
;
/* use individual keys to override default keys even
* with RX of broad/multicast frames */
/* Fragmentation structures */
struct
ieee80211_frag_entry
frag_cache
[
IEEE80211_FRAG_CACHE_LEN
];
unsigned
int
frag_next_idx
;
u16
fts
;
/* Fragmentation Threshold */
/* Association info */
u8
bssid
[
ETH_ALEN
];
enum
ieee80211_state
state
;
int
mode
;
/* A, B, G */
int
modulation
;
/* CCK, OFDM */
int
freq_band
;
/* 2.4Ghz, 5.2Ghz, Mixed */
int
abg_ture
;
/* ABG flag */
/* Callback functions */
void
(
*
set_security
)(
struct
net_device
*
dev
,
struct
ieee80211_security
*
sec
);
int
(
*
hard_start_xmit
)(
struct
ieee80211_txb
*
txb
,
struct
net_device
*
dev
);
int
(
*
reset_port
)(
struct
net_device
*
dev
);
/* This must be the last item so that it points to the data
* allocated beyond this structure by alloc_ieee80211 */
u8
priv
[
0
];
};
#define IEEE_A (1<<0)
#define IEEE_B (1<<1)
#define IEEE_G (1<<2)
#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
extern
inline
void
*
ieee80211_priv
(
struct
net_device
*
dev
)
{
return
((
struct
ieee80211_device
*
)
netdev_priv
(
dev
))
->
priv
;
}
extern
inline
int
ieee80211_is_empty_essid
(
const
char
*
essid
,
int
essid_len
)
{
/* Single white space is for Linksys APs */
if
(
essid_len
==
1
&&
essid
[
0
]
==
' '
)
return
1
;
/* Otherwise, if the entire essid is 0, we assume it is hidden */
while
(
essid_len
)
{
essid_len
--
;
if
(
essid
[
essid_len
]
!=
'\0'
)
return
0
;
}
return
1
;
}
extern
inline
int
ieee80211_is_valid_mode
(
struct
ieee80211_device
*
ieee
,
int
mode
)
{
/*
* It is possible for both access points and our device to support
* combinations of modes, so as long as there is one valid combination
* of ap/device supported modes, then return success
*
*/
if
((
mode
&
IEEE_A
)
&&
(
ieee
->
modulation
&
IEEE80211_OFDM_MODULATION
)
&&
(
ieee
->
freq_band
&
IEEE80211_52GHZ_BAND
))
return
1
;
if
((
mode
&
IEEE_G
)
&&
(
ieee
->
modulation
&
IEEE80211_OFDM_MODULATION
)
&&
(
ieee
->
freq_band
&
IEEE80211_24GHZ_BAND
))
return
1
;
if
((
mode
&
IEEE_B
)
&&
(
ieee
->
modulation
&
IEEE80211_CCK_MODULATION
)
&&
(
ieee
->
freq_band
&
IEEE80211_24GHZ_BAND
))
return
1
;
return
0
;
}
extern
inline
int
ieee80211_get_hdrlen
(
u16
fc
)
{
int
hdrlen
=
24
;
switch
(
WLAN_FC_GET_TYPE
(
fc
))
{
case
IEEE80211_FTYPE_DATA
:
if
((
fc
&
IEEE80211_FCTL_FROMDS
)
&&
(
fc
&
IEEE80211_FCTL_TODS
))
hdrlen
=
30
;
/* Addr4 */
break
;
case
IEEE80211_FTYPE_CTL
:
switch
(
WLAN_FC_GET_STYPE
(
fc
))
{
case
IEEE80211_STYPE_CTS
:
case
IEEE80211_STYPE_ACK
:
hdrlen
=
10
;
break
;
default:
hdrlen
=
16
;
break
;
}
break
;
}
return
hdrlen
;
}
/* ieee80211.c */
extern
void
free_ieee80211
(
struct
net_device
*
dev
);
extern
struct
net_device
*
alloc_ieee80211
(
int
sizeof_priv
);
extern
int
ieee80211_set_encryption
(
struct
ieee80211_device
*
ieee
);
/* ieee80211_tx.c */
extern
int
ieee80211_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
extern
void
ieee80211_txb_free
(
struct
ieee80211_txb
*
);
/* ieee80211_rx.c */
extern
int
ieee80211_rx
(
struct
ieee80211_device
*
ieee
,
struct
sk_buff
*
skb
,
struct
ieee80211_rx_stats
*
rx_stats
);
extern
void
ieee80211_rx_mgt
(
struct
ieee80211_device
*
ieee
,
struct
ieee80211_hdr
*
header
,
struct
ieee80211_rx_stats
*
stats
);
/* iee80211_wx.c */
extern
int
ieee80211_wx_get_scan
(
struct
ieee80211_device
*
ieee
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
key
);
extern
int
ieee80211_wx_set_encode
(
struct
ieee80211_device
*
ieee
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
key
);
extern
int
ieee80211_wx_get_encode
(
struct
ieee80211_device
*
ieee
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
key
);
extern
inline
void
ieee80211_increment_scans
(
struct
ieee80211_device
*
ieee
)
{
ieee
->
scans
++
;
}
extern
inline
int
ieee80211_get_scans
(
struct
ieee80211_device
*
ieee
)
{
return
ieee
->
scans
;
}
static
inline
const
char
*
escape_essid
(
const
char
*
essid
,
u8
essid_len
)
{
static
char
escaped
[
IW_ESSID_MAX_SIZE
*
2
+
1
];
const
char
*
s
=
essid
;
char
*
d
=
escaped
;
if
(
ieee80211_is_empty_essid
(
essid
,
essid_len
))
{
memcpy
(
escaped
,
"<hidden>"
,
sizeof
(
"<hidden>"
));
return
escaped
;
}
essid_len
=
min
(
essid_len
,
(
u8
)
IW_ESSID_MAX_SIZE
);
while
(
essid_len
--
)
{
if
(
*
s
==
'\0'
)
{
*
d
++
=
'\\'
;
*
d
++
=
'0'
;
s
++
;
}
else
{
*
d
++
=
*
s
++
;
}
}
*
d
=
'\0'
;
return
escaped
;
}
#endif
/* IEEE80211_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment