Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
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