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
98c4cae1
Commit
98c4cae1
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: monitor mode support
Patch from Pavel Roskin
parent
8f2abf44
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
180 additions
and
29 deletions
+180
-29
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.c
+179
-29
drivers/net/wireless/orinoco.h
drivers/net/wireless/orinoco.h
+1
-0
No files found.
drivers/net/wireless/orinoco.c
View file @
98c4cae1
...
@@ -499,6 +499,10 @@ static int ignore_disconnect; /* = 0 */
...
@@ -499,6 +499,10 @@ static int ignore_disconnect; /* = 0 */
module_param
(
ignore_disconnect
,
int
,
0644
);
module_param
(
ignore_disconnect
,
int
,
0644
);
MODULE_PARM_DESC
(
ignore_disconnect
,
"Don't report lost link to the network layer"
);
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 */
/* Compile time configuration and compatibility stuff */
/********************************************************************/
/********************************************************************/
...
@@ -670,6 +674,10 @@ static inline void set_port_type(struct orinoco_private *priv)
...
@@ -670,6 +674,10 @@ static inline void set_port_type(struct orinoco_private *priv)
priv
->
createibss
=
1
;
priv
->
createibss
=
1
;
}
}
break
;
break
;
case
IW_MODE_MONITOR
:
priv
->
port_type
=
3
;
priv
->
createibss
=
0
;
break
;
default:
default:
printk
(
KERN_ERR
"%s: Invalid priv->iw_mode in set_port_type()
\n
"
,
printk
(
KERN_ERR
"%s: Invalid priv->iw_mode in set_port_type()
\n
"
,
priv
->
ndev
->
name
);
priv
->
ndev
->
name
);
...
@@ -856,7 +864,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -856,7 +864,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return
1
;
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,
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
silently drop the packet (this seems to be the
safest approach). */
safest approach). */
...
@@ -1118,6 +1126,117 @@ static void orinoco_stat_gather(struct net_device *dev,
...
@@ -1118,6 +1126,117 @@ 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
)
static
void
__orinoco_ev_rx
(
struct
net_device
*
dev
,
hermes_t
*
hw
)
{
{
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
struct
orinoco_private
*
priv
=
netdev_priv
(
dev
);
...
@@ -1137,24 +1256,29 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
...
@@ -1137,24 +1256,29 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if
(
err
)
{
if
(
err
)
{
printk
(
KERN_ERR
"%s: error %d reading Rx descriptor. "
printk
(
KERN_ERR
"%s: error %d reading Rx descriptor. "
"Frame dropped.
\n
"
,
dev
->
name
,
err
);
"Frame dropped.
\n
"
,
dev
->
name
,
err
);
stats
->
rx_errors
++
;
goto
update_stats
;
goto
drop
;
}
}
status
=
le16_to_cpu
(
desc
.
status
);
status
=
le16_to_cpu
(
desc
.
status
);
if
(
status
&
HERMES_RXSTAT_ERR
)
{
if
(
status
&
HERMES_RXSTAT_BADCRC
)
{
if
(
status
&
HERMES_RXSTAT_UNDECRYPTABLE
)
{
DEBUG
(
1
,
"%s: Bad CRC on Rx. Frame dropped.
\n
"
,
wstats
->
discard
.
code
++
;
dev
->
name
);
DEBUG
(
1
,
"%s: Undecryptable frame on Rx. Frame dropped.
\n
"
,
stats
->
rx_crc_errors
++
;
dev
->
name
);
goto
update_stats
;
}
else
{
}
stats
->
rx_crc_errors
++
;
DEBUG
(
1
,
"%s: Bad CRC on Rx. Frame dropped.
\n
"
,
dev
->
name
);
}
stats
->
rx_errors
++
;
/* Handle frames in monitor mode */
goto
drop
;
if
(
priv
->
iw_mode
==
IW_MODE_MONITOR
)
{
orinoco_rx_monitor
(
dev
,
rxfid
,
&
desc
);
return
;
}
if
(
status
&
HERMES_RXSTAT_UNDECRYPTABLE
)
{
DEBUG
(
1
,
"%s: Undecryptable frame on Rx. Frame dropped.
\n
"
,
dev
->
name
);
wstats
->
discard
.
code
++
;
goto
update_stats
;
}
}
length
=
le16_to_cpu
(
desc
.
data_len
);
length
=
le16_to_cpu
(
desc
.
data_len
);
...
@@ -1165,15 +1289,13 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
...
@@ -1165,15 +1289,13 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
/* At least on Symbol firmware with PCF we get quite a
/* At least on Symbol firmware with PCF we get quite a
lot of these legitimately - Poll frames with no
lot of these legitimately - Poll frames with no
data. */
data. */
stats
->
rx_dropped
++
;
return
;
goto
drop
;
}
}
if
(
length
>
IEEE802_11_DATA_LEN
)
{
if
(
length
>
IEEE802_11_DATA_LEN
)
{
printk
(
KERN_WARNING
"%s: Oversized frame received (%d bytes)
\n
"
,
printk
(
KERN_WARNING
"%s: Oversized frame received (%d bytes)
\n
"
,
dev
->
name
,
length
);
dev
->
name
,
length
);
stats
->
rx_length_errors
++
;
stats
->
rx_length_errors
++
;
stats
->
rx_errors
++
;
goto
update_stats
;
goto
drop
;
}
}
/* We need space for the packet data itself, plus an ethernet
/* We need space for the packet data itself, plus an ethernet
...
@@ -1185,7 +1307,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
...
@@ -1185,7 +1307,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if
(
!
skb
)
{
if
(
!
skb
)
{
printk
(
KERN_WARNING
"%s: Can't allocate skb for Rx
\n
"
,
printk
(
KERN_WARNING
"%s: Can't allocate skb for Rx
\n
"
,
dev
->
name
);
dev
->
name
);
goto
drop
;
goto
update_stats
;
}
}
/* We'll prepend the header, so reserve space for it. The worst
/* We'll prepend the header, so reserve space for it. The worst
...
@@ -1199,7 +1321,6 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
...
@@ -1199,7 +1321,6 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if
(
err
)
{
if
(
err
)
{
printk
(
KERN_ERR
"%s: error %d reading frame. "
printk
(
KERN_ERR
"%s: error %d reading frame. "
"Frame dropped.
\n
"
,
dev
->
name
,
err
);
"Frame dropped.
\n
"
,
dev
->
name
,
err
);
stats
->
rx_errors
++
;
goto
drop
;
goto
drop
;
}
}
...
@@ -1245,11 +1366,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
...
@@ -1245,11 +1366,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
return
;
return
;
drop:
drop:
dev_kfree_skb_irq
(
skb
);
update_stats:
stats
->
rx_errors
++
;
stats
->
rx_dropped
++
;
stats
->
rx_dropped
++
;
if
(
skb
)
dev_kfree_skb_irq
(
skb
);
return
;
}
}
/********************************************************************/
/********************************************************************/
...
@@ -2065,6 +2185,20 @@ static int __orinoco_program_rids(struct net_device *dev)
...
@@ -2065,6 +2185,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*/
/* Set promiscuity / multicast*/
priv
->
promiscuous
=
0
;
priv
->
promiscuous
=
0
;
priv
->
mc_count
=
0
;
priv
->
mc_count
=
0
;
...
@@ -2413,6 +2547,7 @@ static int determine_firmware(struct net_device *dev)
...
@@ -2413,6 +2547,7 @@ static int determine_firmware(struct net_device *dev)
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
);
priv
->
has_hostscan
=
(
firmver
>=
0x8000a
);
priv
->
broken_monitor
=
(
firmver
>=
0x80000
);
/* 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
...
@@ -2980,6 +3115,15 @@ static int orinoco_ioctl_setmode(struct net_device *dev,
...
@@ -2980,6 +3115,15 @@ static int orinoco_ioctl_setmode(struct net_device *dev,
case
IW_MODE_INFRA
:
case
IW_MODE_INFRA
:
break
;
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:
default:
err
=
-
EOPNOTSUPP
;
err
=
-
EOPNOTSUPP
;
break
;
break
;
...
@@ -3355,11 +3499,9 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
...
@@ -3355,11 +3499,9 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
unsigned
long
flags
;
unsigned
long
flags
;
int
err
=
-
EINPROGRESS
;
/* Call commit handler */
int
err
=
-
EINPROGRESS
;
/* Call commit handler */
/* We can only use this in Ad-Hoc demo mode to set the operating
/* In infrastructure mode the AP sets the channel */
* frequency, or in IBSS mode to set the frequency where the IBSS
if
(
priv
->
iw_mode
==
IW_MODE_INFRA
)
* will be created - Jean II */
return
-
EBUSY
;
if
(
priv
->
iw_mode
!=
IW_MODE_ADHOC
)
return
-
EOPNOTSUPP
;
if
(
(
frq
->
e
==
0
)
&&
(
frq
->
m
<=
1000
)
)
{
if
(
(
frq
->
e
==
0
)
&&
(
frq
->
m
<=
1000
)
)
{
/* Setting by channel number */
/* Setting by channel number */
...
@@ -3383,7 +3525,15 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
...
@@ -3383,7 +3525,15 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
if
(
orinoco_lock
(
priv
,
&
flags
)
!=
0
)
return
-
EBUSY
;
return
-
EBUSY
;
priv
->
channel
=
chan
;
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
);
orinoco_unlock
(
priv
,
&
flags
);
return
err
;
return
err
;
...
...
drivers/net/wireless/orinoco.h
View file @
98c4cae1
...
@@ -94,6 +94,7 @@ struct orinoco_private {
...
@@ -94,6 +94,7 @@ struct orinoco_private {
unsigned
int
has_sensitivity
:
1
;
unsigned
int
has_sensitivity
:
1
;
unsigned
int
has_hostscan
:
1
;
unsigned
int
has_hostscan
:
1
;
unsigned
int
broken_disableport
:
1
;
unsigned
int
broken_disableport
:
1
;
unsigned
int
broken_monitor
:
1
;
/* Configuration paramaters */
/* Configuration paramaters */
u32
iw_mode
;
u32
iw_mode
;
...
...
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