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