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
95dd91fb
Commit
95dd91fb
authored
Jun 19, 2005
by
Christoph Hellwig
Committed by
Jeff Garzik
Jun 27, 2005
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] orinoco: scanning support
Patch from Pavel Roskin
parent
16739b06
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
544 additions
and
21 deletions
+544
-21
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.c
+522
-21
drivers/net/wireless/orinoco.h
drivers/net/wireless/orinoco.h
+22
-0
No files found.
drivers/net/wireless/orinoco.c
View file @
95dd91fb
...
@@ -514,6 +514,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
...
@@ -514,6 +514,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
/* Internal constants */
/* 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_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
...
@@ -579,25 +583,42 @@ static struct {
...
@@ -579,25 +583,42 @@ static struct {
/* Data types */
/* Data types */
/********************************************************************/
/********************************************************************/
struct
header_struct
{
/* Used in Event handling.
/* 802.3 */
* We avoid nested structres as they break on ARM -- Moustafa */
u8
dest
[
ETH_ALEN
];
struct
hermes_tx_descriptor_802_11
{
u8
src
[
ETH_ALEN
];
/* hermes_tx_descriptor */
u16
len
;
u16
status
;
/* 802.2 */
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
dsap
;
u8
ssap
;
u8
ssap
;
u8
ctrl
;
u8
ctrl
;
/* SNAP */
u8
oui
[
3
];
u8
oui
[
3
];
u16
ethertype
;
u16
ethertype
;
}
__attribute__
((
packed
));
}
__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)
struct
hermes_rx_descriptor
{
struct
hermes_rx_descriptor
{
u16
status
;
u16
status
;
u32
time
;
u32
time
;
...
@@ -958,26 +979,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
...
@@ -958,26 +979,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
net_device_stats
*
stats
=
&
priv
->
stats
;
struct
net_device_stats
*
stats
=
&
priv
->
stats
;
u16
fid
=
hermes_read_regn
(
hw
,
TXCOMPLFID
);
u16
fid
=
hermes_read_regn
(
hw
,
TXCOMPLFID
);
struct
hermes_tx_descriptor
desc
;
struct
hermes_tx_descriptor
_802_11
hdr
;
int
err
=
0
;
int
err
=
0
;
if
(
fid
==
DUMMY_FID
)
if
(
fid
==
DUMMY_FID
)
return
;
/* Nothing's really happened */
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
)
{
if
(
err
)
{
printk
(
KERN_WARNING
"%s: Unable to read descriptor on Tx error "
printk
(
KERN_WARNING
"%s: Unable to read descriptor on Tx error "
"(FID=%04X error %d)
\n
"
,
"(FID=%04X error %d)
\n
"
,
dev
->
name
,
fid
,
err
);
dev
->
name
,
fid
,
err
);
}
else
{
return
;
DEBUG
(
1
,
"%s: Tx error, status %d
\n
"
,
dev
->
name
,
le16_to_cpu
(
desc
.
status
));
}
}
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
);
netif_wake_queue
(
dev
);
hermes_write_regn
(
hw
,
TXCOMPLFID
,
DUMMY_FID
);
}
}
static
void
orinoco_tx_timeout
(
struct
net_device
*
dev
)
static
void
orinoco_tx_timeout
(
struct
net_device
*
dev
)
...
@@ -1316,6 +1366,30 @@ static void orinoco_join_ap(struct net_device *dev)
...
@@ -1316,6 +1366,30 @@ static void orinoco_join_ap(struct net_device *dev)
orinoco_unlock
(
priv
,
&
flags
);
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
)
static
void
__orinoco_ev_info
(
struct
net_device
*
dev
,
hermes_t
*
hw
)
{
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
...
@@ -1395,6 +1469,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
...
@@ -1395,6 +1469,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break
;
break
;
newstatus
=
le16_to_cpu
(
linkstatus
.
linkstatus
);
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
)
connected
=
(
newstatus
==
HERMES_LINKSTATUS_CONNECTED
)
||
(
newstatus
==
HERMES_LINKSTATUS_AP_CHANGE
)
||
(
newstatus
==
HERMES_LINKSTATUS_AP_CHANGE
)
||
(
newstatus
==
HERMES_LINKSTATUS_AP_IN_RANGE
);
||
(
newstatus
==
HERMES_LINKSTATUS_AP_IN_RANGE
);
...
@@ -1404,12 +1487,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
...
@@ -1404,12 +1487,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
else
if
(
!
ignore_disconnect
)
else
if
(
!
ignore_disconnect
)
netif_carrier_off
(
dev
);
netif_carrier_off
(
dev
);
if
(
newstatus
!=
priv
->
last_linkstatus
)
if
(
newstatus
!=
priv
->
last_linkstatus
)
{
priv
->
last_linkstatus
=
newstatus
;
print_linkstatus
(
dev
,
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
;
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
;
}
priv
->
last_linkstatus
=
newstatus
;
/* 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
;
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:
default:
printk
(
KERN_DEBUG
"%s: Unknown information frame received: "
printk
(
KERN_DEBUG
"%s: Unknown information frame received: "
"type 0x%04x, length %d
\n
"
,
dev
->
name
,
type
,
len
);
"type 0x%04x, length %d
\n
"
,
dev
->
name
,
type
,
len
);
...
@@ -2010,6 +2170,11 @@ static void orinoco_reset(struct net_device *dev)
...
@@ -2010,6 +2170,11 @@ static void orinoco_reset(struct net_device *dev)
orinoco_unlock
(
priv
,
&
flags
);
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
)
{
if
(
priv
->
hard_reset
)
{
err
=
(
*
priv
->
hard_reset
)(
priv
);
err
=
(
*
priv
->
hard_reset
)(
priv
);
if
(
err
)
{
if
(
err
)
{
...
@@ -2248,6 +2413,7 @@ static int determine_firmware(struct net_device *dev)
...
@@ -2248,6 +2413,7 @@ static int determine_firmware(struct net_device *dev)
priv
->
has_mwo
=
(
firmver
>=
0x60000
);
priv
->
has_mwo
=
(
firmver
>=
0x60000
);
priv
->
has_pm
=
(
firmver
>=
0x40020
);
/* Don't work in 7.52 ? */
priv
->
has_pm
=
(
firmver
>=
0x40020
);
/* Don't work in 7.52 ? */
priv
->
ibss_port
=
1
;
priv
->
ibss_port
=
1
;
priv
->
has_hostscan
=
(
firmver
>=
0x8000a
);
/* Tested with Agere firmware :
/* Tested with Agere firmware :
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
...
@@ -2293,6 +2459,8 @@ static int determine_firmware(struct net_device *dev)
...
@@ -2293,6 +2459,8 @@ static int determine_firmware(struct net_device *dev)
priv
->
ibss_port
=
4
;
priv
->
ibss_port
=
4
;
priv
->
broken_disableport
=
(
firmver
==
0x25013
)
||
priv
->
broken_disableport
=
(
firmver
==
0x25013
)
||
(
firmver
>=
0x30000
&&
firmver
<=
0x31000
);
(
firmver
>=
0x30000
&&
firmver
<=
0x31000
);
priv
->
has_hostscan
=
(
firmver
>=
0x31001
)
||
(
firmver
>=
0x29057
&&
firmver
<
0x30000
);
/* Tested with Intel firmware : 0x20015 => Jean II */
/* Tested with Intel firmware : 0x20015 => Jean II */
/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
break
;
break
;
...
@@ -2312,6 +2480,7 @@ static int determine_firmware(struct net_device *dev)
...
@@ -2312,6 +2480,7 @@ static int determine_firmware(struct net_device *dev)
priv
->
has_ibss
=
(
firmver
>=
0x000700
);
/* FIXME */
priv
->
has_ibss
=
(
firmver
>=
0x000700
);
/* FIXME */
priv
->
has_big_wep
=
priv
->
has_wep
=
(
firmver
>=
0x000800
);
priv
->
has_big_wep
=
priv
->
has_wep
=
(
firmver
>=
0x000800
);
priv
->
has_pm
=
(
firmver
>=
0x000700
);
priv
->
has_pm
=
(
firmver
>=
0x000700
);
priv
->
has_hostscan
=
(
firmver
>=
0x010301
);
if
(
firmver
>=
0x000800
)
if
(
firmver
>=
0x000800
)
priv
->
ibss_port
=
0
;
priv
->
ibss_port
=
0
;
...
@@ -2539,6 +2708,7 @@ struct net_device *alloc_orinocodev(int sizeof_card,
...
@@ -2539,6 +2708,7 @@ struct net_device *alloc_orinocodev(int sizeof_card,
* hardware */
* hardware */
INIT_WORK
(
&
priv
->
reset_work
,
(
void
(
*
)(
void
*
))
orinoco_reset
,
dev
);
INIT_WORK
(
&
priv
->
reset_work
,
(
void
(
*
)(
void
*
))
orinoco_reset
,
dev
);
INIT_WORK
(
&
priv
->
join_work
,
(
void
(
*
)(
void
*
))
orinoco_join_ap
,
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
);
netif_carrier_off
(
dev
);
priv
->
last_linkstatus
=
0xffff
;
priv
->
last_linkstatus
=
0xffff
;
...
@@ -2549,6 +2719,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
...
@@ -2549,6 +2719,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
void
free_orinocodev
(
struct
net_device
*
dev
)
void
free_orinocodev
(
struct
net_device
*
dev
)
{
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
kfree
(
priv
->
scan_result
);
free_netdev
(
dev
);
free_netdev
(
dev
);
}
}
...
@@ -3967,6 +4140,332 @@ static int orinoco_ioctl_getspy(struct net_device *dev,
...
@@ -3967,6 +4140,332 @@ static int orinoco_ioctl_getspy(struct net_device *dev,
return
0
;
return
0
;
}
}
/* 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
);
hermes_t
*
hw
=
&
priv
->
hw
;
int
err
=
0
;
unsigned
long
flags
;
/* 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 */
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
/* Scanning with port 0 disabled would fail */
if
(
!
netif_running
(
dev
))
{
err
=
-
ENETDOWN
;
goto
out
;
}
/* 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
;
}
/* 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 */
/* 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
;
}
/* Save flags */
priv
->
scan_mode
=
srq
->
flags
;
/* Always trigger scanning, even if it's in progress.
* This way, if the info frame get lost, we will recover somewhat
* gracefully - Jean II */
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
];
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
FIRMWARE_TYPE_AGERE
:
err
=
hermes_write_wordrec
(
hw
,
USER_BAP
,
HERMES_RID_CNFSCANSSID_AGERE
,
0
);
/* Any ESSID */
if
(
err
)
break
;
err
=
hermes_inquire
(
hw
,
HERMES_INQ_SCAN
);
break
;
}
}
else
err
=
hermes_inquire
(
hw
,
HERMES_INQ_SCAN
);
/* One more client */
if
(
!
err
)
priv
->
scan_inprogress
=
1
;
out:
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
/* 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
;
switch
(
priv
->
firmware_type
)
{
case
FIRMWARE_TYPE_AGERE
:
atom_len
=
sizeof
(
struct
agere_scan_apinfo
);
offset
=
0
;
break
;
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
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
;
}
/* 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
;
}
/* 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
);
/* 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
);
/* 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
;
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
;
}
/* The other data in the scan result are not really
* interesting, so for now drop it - Jean II */
}
return
current_ev
-
buffer
;
}
/* 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
;
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
/* 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 */
/* Translate to WE format */
srq
->
length
=
orinoco_translate_scan
(
dev
,
extra
,
priv
->
scan_result
,
priv
->
scan_len
);
/* Return flags */
srq
->
flags
=
(
__u16
)
priv
->
scan_mode
;
/* Results are here, so scan no longer in progress */
priv
->
scan_inprogress
=
0
;
/* 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 */
}
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
}
/* Commit handler, called after set operations */
/* Commit handler, called after set operations */
static
int
orinoco_ioctl_commit
(
struct
net_device
*
dev
,
static
int
orinoco_ioctl_commit
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
struct
iw_request_info
*
info
,
...
@@ -4060,6 +4559,8 @@ static const iw_handler orinoco_handler[] = {
...
@@ -4060,6 +4559,8 @@ static const iw_handler orinoco_handler[] = {
[
SIOCGIWSPY
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getspy
,
[
SIOCGIWSPY
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getspy
,
[
SIOCSIWAP
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setwap
,
[
SIOCSIWAP
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setwap
,
[
SIOCGIWAP
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getwap
,
[
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
,
[
SIOCSIWESSID
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setessid
,
[
SIOCGIWESSID
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getessid
,
[
SIOCGIWESSID
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_getessid
,
[
SIOCSIWNICKN
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setnick
,
[
SIOCSIWNICKN
-
SIOCIWFIRST
]
(
iw_handler
)
orinoco_ioctl_setnick
,
...
...
drivers/net/wireless/orinoco.h
View file @
95dd91fb
...
@@ -32,6 +32,20 @@ struct orinoco_key {
...
@@ -32,6 +32,20 @@ struct orinoco_key {
char
data
[
ORINOCO_MAX_KEY_SIZE
];
char
data
[
ORINOCO_MAX_KEY_SIZE
];
}
__attribute__
((
packed
));
}
__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
{
typedef
enum
{
FIRMWARE_TYPE_AGERE
,
FIRMWARE_TYPE_AGERE
,
FIRMWARE_TYPE_INTERSIL
,
FIRMWARE_TYPE_INTERSIL
,
...
@@ -51,6 +65,7 @@ struct orinoco_private {
...
@@ -51,6 +65,7 @@ struct orinoco_private {
int
open
;
int
open
;
u16
last_linkstatus
;
u16
last_linkstatus
;
struct
work_struct
join_work
;
struct
work_struct
join_work
;
struct
work_struct
wevent_work
;
/* Net device stuff */
/* Net device stuff */
struct
net_device
*
ndev
;
struct
net_device
*
ndev
;
...
@@ -77,6 +92,7 @@ struct orinoco_private {
...
@@ -77,6 +92,7 @@ struct orinoco_private {
unsigned
int
has_pm
:
1
;
unsigned
int
has_pm
:
1
;
unsigned
int
has_preamble
:
1
;
unsigned
int
has_preamble
:
1
;
unsigned
int
has_sensitivity
:
1
;
unsigned
int
has_sensitivity
:
1
;
unsigned
int
has_hostscan
:
1
;
unsigned
int
broken_disableport
:
1
;
unsigned
int
broken_disableport
:
1
;
/* Configuration paramaters */
/* Configuration paramaters */
...
@@ -103,6 +119,12 @@ struct orinoco_private {
...
@@ -103,6 +119,12 @@ struct orinoco_private {
/* Configuration dependent variables */
/* Configuration dependent variables */
int
port_type
,
createibss
;
int
port_type
,
createibss
;
int
promiscuous
,
mc_count
;
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
#ifdef ORINOCO_DEBUG
...
...
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