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
a5220ff4
Commit
a5220ff4
authored
Feb 20, 2002
by
Jean Tourrilhes
Committed by
Jeff Garzik
Feb 20, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update (ancient) wireless net drivers netwave_cs, wavelan,
and wavelan_cs to new wireless API.
parent
74a4e27a
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
2199 additions
and
1085 deletions
+2199
-1085
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/netwave_cs.c
+350
-124
drivers/net/wireless/wavelan.c
drivers/net/wireless/wavelan.c
+651
-453
drivers/net/wireless/wavelan.p.h
drivers/net/wireless/wavelan.p.h
+10
-5
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/wavelan_cs.c
+1166
-500
drivers/net/wireless/wavelan_cs.p.h
drivers/net/wireless/wavelan_cs.p.h
+22
-3
No files found.
drivers/net/wireless/netwave_cs.c
View file @
a5220ff4
...
...
@@ -63,6 +63,9 @@
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h>
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif
/* WIRELESS_EXT > 12 */
#endif
#include <pcmcia/version.h>
...
...
@@ -269,6 +272,16 @@ static dev_link_t *dev_list;
because they generally can't be allocated dynamically.
*/
#if WIRELESS_EXT <= 12
/* Wireless extensions backward compatibility */
/* Part of iw_handler prototype we need */
struct
iw_request_info
{
__u16
cmd
;
/* Wireless Extension command */
__u16
flags
;
/* More to come ;-) */
};
/* Wireless Extension Backward compatibility - Jean II
* If the new wireless device private ioctl range is not defined,
* default to standard device private ioctl range */
...
...
@@ -276,8 +289,11 @@ static dev_link_t *dev_list;
#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
#endif
/* SIOCIWFIRSTPRIV */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV
/* Site Survey Snapshot */
/*#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1*/
#else
/* WIRELESS_EXT <= 12 */
static
const
struct
iw_handler_def
netwave_handler_def
;
#endif
/* WIRELESS_EXT <= 12 */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1
/* Site Survey Snapshot */
#define MAX_ESA 10
...
...
@@ -483,7 +499,10 @@ static dev_link_t *netwave_attach(void)
/* wireless extensions */
#ifdef WIRELESS_EXT
dev
->
get_wireless_stats
=
&
netwave_get_wireless_stats
;
#endif
#if WIRELESS_EXT > 12
dev
->
wireless_handlers
=
(
struct
iw_handler_def
*
)
&
netwave_handler_def
;
#endif
/* WIRELESS_EXT > 12 */
#endif
/* WIRELESS_EXT */
dev
->
do_ioctl
=
&
netwave_ioctl
;
dev
->
tx_timeout
=
&
netwave_watchdog
;
...
...
@@ -595,6 +614,303 @@ static void netwave_flush_stale_links(void)
}
}
/* netwave_flush_stale_links */
/*
* Wireless Handler : get protocol name
*/
static
int
netwave_get_name
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
strcpy
(
wrqu
->
name
,
"Netwave"
);
return
0
;
}
/*
* Wireless Handler : set Network ID
*/
static
int
netwave_set_nwid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
flags
;
ioaddr_t
iobase
=
dev
->
base_addr
;
netwave_private
*
priv
=
(
netwave_private
*
)
dev
->
priv
;
u_char
*
ramBase
=
priv
->
ramBase
;
/* Disable interrupts & save flags */
save_flags
(
flags
);
cli
();
#if WIRELESS_EXT > 8
if
(
!
wrqu
->
nwid
.
disabled
)
{
domain
=
wrqu
->
nwid
.
value
;
#else
/* WIRELESS_EXT > 8 */
if
(
wrqu
->
nwid
.
on
)
{
domain
=
wrqu
->
nwid
.
nwid
;
#endif
/* WIRELESS_EXT > 8 */
printk
(
KERN_DEBUG
"Setting domain to 0x%x%02x
\n
"
,
(
domain
>>
8
)
&
0x01
,
domain
&
0xff
);
wait_WOC
(
iobase
);
writeb
(
NETWAVE_CMD_SMD
,
ramBase
+
NETWAVE_EREG_CB
+
0
);
writeb
(
domain
&
0xff
,
ramBase
+
NETWAVE_EREG_CB
+
1
);
writeb
((
domain
>>
8
)
&
0x01
,
ramBase
+
NETWAVE_EREG_CB
+
2
);
writeb
(
NETWAVE_CMD_EOC
,
ramBase
+
NETWAVE_EREG_CB
+
3
);
}
/* ReEnable interrupts & restore flags */
restore_flags
(
flags
);
return
0
;
}
/*
* Wireless Handler : get Network ID
*/
static
int
netwave_get_nwid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
#if WIRELESS_EXT > 8
wrqu
->
nwid
.
value
=
domain
;
wrqu
->
nwid
.
disabled
=
0
;
wrqu
->
nwid
.
fixed
=
1
;
#else
/* WIRELESS_EXT > 8 */
wrqu
->
nwid
.
nwid
=
domain
;
wrqu
->
nwid
.
on
=
1
;
#endif
/* WIRELESS_EXT > 8 */
return
0
;
}
/*
* Wireless Handler : set scramble key
*/
static
int
netwave_set_scramble
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
key
)
{
unsigned
long
flags
;
ioaddr_t
iobase
=
dev
->
base_addr
;
netwave_private
*
priv
=
(
netwave_private
*
)
dev
->
priv
;
u_char
*
ramBase
=
priv
->
ramBase
;
/* Disable interrupts & save flags */
save_flags
(
flags
);
cli
();
scramble_key
=
(
key
[
0
]
<<
8
)
|
key
[
1
];
wait_WOC
(
iobase
);
writeb
(
NETWAVE_CMD_SSK
,
ramBase
+
NETWAVE_EREG_CB
+
0
);
writeb
(
scramble_key
&
0xff
,
ramBase
+
NETWAVE_EREG_CB
+
1
);
writeb
((
scramble_key
>>
8
)
&
0xff
,
ramBase
+
NETWAVE_EREG_CB
+
2
);
writeb
(
NETWAVE_CMD_EOC
,
ramBase
+
NETWAVE_EREG_CB
+
3
);
/* ReEnable interrupts & restore flags */
restore_flags
(
flags
);
return
0
;
}
/*
* Wireless Handler : get scramble key
*/
static
int
netwave_get_scramble
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
key
)
{
key
[
1
]
=
scramble_key
&
0xff
;
key
[
0
]
=
(
scramble_key
>>
8
)
&
0xff
;
#if WIRELESS_EXT > 8
wrqu
->
encoding
.
flags
=
IW_ENCODE_ENABLED
;
wrqu
->
encoding
.
length
=
2
;
#else
/* WIRELESS_EXT > 8 */
wrqu
->
encoding
.
method
=
1
;
#endif
/* WIRELESS_EXT > 8 */
return
0
;
}
#if WIRELESS_EXT > 8
/*
* Wireless Handler : get mode
*/
static
int
netwave_get_mode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
if
(
domain
&
0x100
)
wrqu
->
mode
=
IW_MODE_INFRA
;
else
wrqu
->
mode
=
IW_MODE_ADHOC
;
return
0
;
}
#endif
/* WIRELESS_EXT > 8 */
/*
* Wireless Handler : get range info
*/
static
int
netwave_get_range
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
struct
iw_range
*
range
=
(
struct
iw_range
*
)
extra
;
int
ret
=
0
;
/* Set the length (very important for backward compatibility) */
wrqu
->
data
.
length
=
sizeof
(
struct
iw_range
);
/* Set all the info we don't care or don't know about to zero */
memset
(
range
,
0
,
sizeof
(
struct
iw_range
));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range
->
we_version_compiled
=
WIRELESS_EXT
;
range
->
we_version_source
=
9
;
/* Nothing for us in v10 and v11 */
#endif
/* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range
->
throughput
=
450
*
1000
;
/* don't argue on this ! */
range
->
min_nwid
=
0x0000
;
range
->
max_nwid
=
0x01FF
;
range
->
num_channels
=
range
->
num_frequency
=
0
;
range
->
sensitivity
=
0x3F
;
range
->
max_qual
.
qual
=
255
;
range
->
max_qual
.
level
=
255
;
range
->
max_qual
.
noise
=
0
;
#if WIRELESS_EXT > 7
range
->
num_bitrates
=
1
;
range
->
bitrate
[
0
]
=
1000000
;
/* 1 Mb/s */
#endif
/* WIRELESS_EXT > 7 */
#if WIRELESS_EXT > 8
range
->
encoding_size
[
0
]
=
2
;
/* 16 bits scrambling */
range
->
num_encoding_sizes
=
1
;
range
->
max_encoding_tokens
=
1
;
/* Only one key possible */
#endif
/* WIRELESS_EXT > 8 */
return
ret
;
}
/*
* Wireless Private Handler : get snapshot
*/
static
int
netwave_get_snap
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
flags
;
ioaddr_t
iobase
=
dev
->
base_addr
;
netwave_private
*
priv
=
(
netwave_private
*
)
dev
->
priv
;
u_char
*
ramBase
=
priv
->
ramBase
;
/* Disable interrupts & save flags */
save_flags
(
flags
);
cli
();
/* Take snapshot of environment */
netwave_snapshot
(
priv
,
ramBase
,
iobase
);
wrqu
->
data
.
length
=
priv
->
nss
.
length
;
memcpy
(
extra
,
(
u_char
*
)
&
priv
->
nss
,
sizeof
(
struct
site_survey
));
priv
->
lastExec
=
jiffies
;
/* ReEnable interrupts & restore flags */
restore_flags
(
flags
);
return
(
0
);
}
/*
* Structures to export the Wireless Handlers
* This is the stuff that are treated the wireless extensions (iwconfig)
*/
static
const
struct
iw_priv_args
netwave_private_args
[]
=
{
/*{ cmd, set_args, get_args, name } */
{
SIOCGIPSNAP
,
0
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
sizeof
(
struct
site_survey
),
"getsitesurvey"
},
};
#if WIRELESS_EXT > 12
static
const
iw_handler
netwave_handler
[]
=
{
NULL
,
/* SIOCSIWNAME */
netwave_get_name
,
/* SIOCGIWNAME */
netwave_set_nwid
,
/* SIOCSIWNWID */
netwave_get_nwid
,
/* SIOCGIWNWID */
NULL
,
/* SIOCSIWFREQ */
NULL
,
/* SIOCGIWFREQ */
NULL
,
/* SIOCSIWMODE */
netwave_get_mode
,
/* SIOCGIWMODE */
NULL
,
/* SIOCSIWSENS */
NULL
,
/* SIOCGIWSENS */
NULL
,
/* SIOCSIWRANGE */
netwave_get_range
,
/* SIOCGIWRANGE */
NULL
,
/* SIOCSIWPRIV */
NULL
,
/* SIOCGIWPRIV */
NULL
,
/* SIOCSIWSTATS */
NULL
,
/* SIOCGIWSTATS */
NULL
,
/* SIOCSIWSPY */
NULL
,
/* SIOCGIWSPY */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCSIWAP */
NULL
,
/* SIOCGIWAP */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCGIWAPLIST */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCSIWESSID */
NULL
,
/* SIOCGIWESSID */
NULL
,
/* SIOCSIWNICKN */
NULL
,
/* SIOCGIWNICKN */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCSIWRATE */
NULL
,
/* SIOCGIWRATE */
NULL
,
/* SIOCSIWRTS */
NULL
,
/* SIOCGIWRTS */
NULL
,
/* SIOCSIWFRAG */
NULL
,
/* SIOCGIWFRAG */
NULL
,
/* SIOCSIWTXPOW */
NULL
,
/* SIOCGIWTXPOW */
NULL
,
/* SIOCSIWRETRY */
NULL
,
/* SIOCGIWRETRY */
netwave_set_scramble
,
/* SIOCSIWENCODE */
netwave_get_scramble
,
/* SIOCGIWENCODE */
};
static
const
iw_handler
netwave_private_handler
[]
=
{
NULL
,
/* SIOCIWFIRSTPRIV */
netwave_get_snap
,
/* SIOCIWFIRSTPRIV + 1 */
};
static
const
struct
iw_handler_def
netwave_handler_def
=
{
num_standard:
sizeof
(
netwave_handler
)
/
sizeof
(
iw_handler
),
num_private:
sizeof
(
netwave_private_handler
)
/
sizeof
(
iw_handler
),
num_private_args:
sizeof
(
netwave_private_args
)
/
sizeof
(
struct
iw_priv_args
),
standard:
(
iw_handler
*
)
netwave_handler
,
private:
(
iw_handler
*
)
netwave_private_handler
,
private_args:
(
struct
iw_priv_args
*
)
netwave_private_args
,
};
#endif
/* WIRELESS_EXT > 12 */
/*
* Function netwave_ioctl (dev, rq, cmd)
*
...
...
@@ -606,56 +922,28 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
struct
ifreq
*
rq
,
/* Data passed */
int
cmd
)
/* Ioctl number */
{
unsigned
long
flags
;
int
ret
=
0
;
#ifdef WIRELESS_EXT
ioaddr_t
iobase
=
dev
->
base_addr
;
netwave_private
*
priv
=
(
netwave_private
*
)
dev
->
priv
;
u_char
*
ramBase
=
priv
->
ramBase
;
#if WIRELESS_EXT <= 12
struct
iwreq
*
wrq
=
(
struct
iwreq
*
)
rq
;
#endif
#endif
DEBUG
(
0
,
"%s: ->netwave_ioctl(cmd=0x%X)
\n
"
,
dev
->
name
,
cmd
);
/* Disable interrupts & save flags */
save_flags
(
flags
);
cli
();
/* Look what is the request */
switch
(
cmd
)
{
/* --------------- WIRELESS EXTENSIONS --------------- */
#ifdef WIRELESS_EXT
#if WIRELESS_EXT <= 12
case
SIOCGIWNAME
:
/* Get name */
strcpy
(
wrq
->
u
.
name
,
"Netwave"
);
netwave_get_name
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCSIWNWID
:
/* Set domain */
#if WIRELESS_EXT > 8
if
(
!
wrq
->
u
.
nwid
.
disabled
)
{
domain
=
wrq
->
u
.
nwid
.
value
;
#else
/* WIRELESS_EXT > 8 */
if
(
wrq
->
u
.
nwid
.
on
)
{
domain
=
wrq
->
u
.
nwid
.
nwid
;
#endif
/* WIRELESS_EXT > 8 */
printk
(
KERN_DEBUG
"Setting domain to 0x%x%02x
\n
"
,
(
domain
>>
8
)
&
0x01
,
domain
&
0xff
);
wait_WOC
(
iobase
);
writeb
(
NETWAVE_CMD_SMD
,
ramBase
+
NETWAVE_EREG_CB
+
0
);
writeb
(
domain
&
0xff
,
ramBase
+
NETWAVE_EREG_CB
+
1
);
writeb
((
domain
>>
8
)
&
0x01
,
ramBase
+
NETWAVE_EREG_CB
+
2
);
writeb
(
NETWAVE_CMD_EOC
,
ramBase
+
NETWAVE_EREG_CB
+
3
);
}
break
;
ret
=
netwave_set_nwid
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCGIWNWID
:
/* Read domain*/
#if WIRELESS_EXT > 8
wrq
->
u
.
nwid
.
value
=
domain
;
wrq
->
u
.
nwid
.
disabled
=
0
;
wrq
->
u
.
nwid
.
fixed
=
1
;
#else
/* WIRELESS_EXT > 8 */
wrq
->
u
.
nwid
.
nwid
=
domain
;
wrq
->
u
.
nwid
.
on
=
1
;
#endif
/* WIRELESS_EXT > 8 */
ret
=
netwave_get_nwid
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
#if WIRELESS_EXT > 8
/* Note : The API did change... */
case
SIOCGIWENCODE
:
...
...
@@ -663,10 +951,7 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
if
(
wrq
->
u
.
encoding
.
pointer
!=
(
caddr_t
)
0
)
{
char
key
[
2
];
key
[
1
]
=
scramble_key
&
0xff
;
key
[
0
]
=
(
scramble_key
>>
8
)
&
0xff
;
wrq
->
u
.
encoding
.
flags
=
IW_ENCODE_ENABLED
;
wrq
->
u
.
encoding
.
length
=
2
;
ret
=
netwave_get_scramble
(
dev
,
NULL
,
&
(
wrq
->
u
),
key
);
if
(
copy_to_user
(
wrq
->
u
.
encoding
.
pointer
,
key
,
2
))
ret
=
-
EFAULT
;
}
...
...
@@ -681,79 +966,31 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
ret
=
-
EFAULT
;
break
;
}
scramble_key
=
(
key
[
0
]
<<
8
)
|
key
[
1
];
wait_WOC
(
iobase
);
writeb
(
NETWAVE_CMD_SSK
,
ramBase
+
NETWAVE_EREG_CB
+
0
);
writeb
(
scramble_key
&
0xff
,
ramBase
+
NETWAVE_EREG_CB
+
1
);
writeb
((
scramble_key
>>
8
)
&
0xff
,
ramBase
+
NETWAVE_EREG_CB
+
2
);
writeb
(
NETWAVE_CMD_EOC
,
ramBase
+
NETWAVE_EREG_CB
+
3
);
ret
=
netwave_set_scramble
(
dev
,
NULL
,
&
(
wrq
->
u
),
key
);
}
break
;
case
SIOCGIWMODE
:
/* Mode of operation */
if
(
domain
&
0x100
)
wrq
->
u
.
mode
=
IW_MODE_INFRA
;
else
wrq
->
u
.
mode
=
IW_MODE_ADHOC
;
ret
=
netwave_get_mode
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
#else
/* WIRELESS_EXT > 8 */
case
SIOCGIWENCODE
:
/* Get scramble key */
wrq
->
u
.
encoding
.
code
=
scramble_key
;
wrq
->
u
.
encoding
.
method
=
1
;
ret
=
netwave_get_scramble
(
dev
,
NULL
,
&
(
wrq
->
u
),
(
char
*
)
&
wrq
->
u
.
encoding
.
code
)
;
break
;
case
SIOCSIWENCODE
:
/* Set scramble key */
scramble_key
=
wrq
->
u
.
encoding
.
code
;
wait_WOC
(
iobase
);
writeb
(
NETWAVE_CMD_SSK
,
ramBase
+
NETWAVE_EREG_CB
+
0
);
writeb
(
scramble_key
&
0xff
,
ramBase
+
NETWAVE_EREG_CB
+
1
);
writeb
((
scramble_key
>>
8
)
&
0xff
,
ramBase
+
NETWAVE_EREG_CB
+
2
);
writeb
(
NETWAVE_CMD_EOC
,
ramBase
+
NETWAVE_EREG_CB
+
3
);
ret
=
netwave_set_scramble
(
dev
,
NULL
,
&
(
wrq
->
u
),
(
char
*
)
&
wrq
->
u
.
encoding
.
code
);
break
;
#endif
/* WIRELESS_EXT > 8 */
case
SIOCGIWRANGE
:
/* Basic checking... */
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
struct
iw_range
range
;
/* Set the length (very important for backward compatibility) */
wrq
->
u
.
data
.
length
=
sizeof
(
struct
iw_range
);
/* Set all the info we don't care or don't know about to zero */
memset
(
&
range
,
0
,
sizeof
(
range
));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range
.
we_version_compiled
=
WIRELESS_EXT
;
range
.
we_version_source
=
9
;
/* Nothing for us in v10 and v11 */
#endif
/* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range
.
throughput
=
450
*
1000
;
/* don't argue on this ! */
range
.
min_nwid
=
0x0000
;
range
.
max_nwid
=
0x01FF
;
range
.
num_channels
=
range
.
num_frequency
=
0
;
range
.
sensitivity
=
0x3F
;
range
.
max_qual
.
qual
=
255
;
range
.
max_qual
.
level
=
255
;
range
.
max_qual
.
noise
=
0
;
#if WIRELESS_EXT > 7
range
.
num_bitrates
=
1
;
range
.
bitrate
[
0
]
=
1000000
;
/* 1 Mb/s */
#endif
/* WIRELESS_EXT > 7 */
#if WIRELESS_EXT > 8
range
.
encoding_size
[
0
]
=
2
;
/* 16 bits scrambling */
range
.
num_encoding_sizes
=
1
;
range
.
max_encoding_tokens
=
1
;
/* Only one key possible */
#endif
/* WIRELESS_EXT > 8 */
/* Copy structure to the user buffer */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
&
range
,
ret
=
netwave_get_range
(
dev
,
NULL
,
&
(
wrq
->
u
),
(
char
*
)
&
range
);
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
&
range
,
sizeof
(
struct
iw_range
)))
ret
=
-
EFAULT
;
}
...
...
@@ -761,47 +998,36 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
case
SIOCGIWPRIV
:
/* Basic checking... */
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
struct
iw_priv_args
priv
[]
=
{
/* cmd, set_args, get_args, name */
{
SIOCGIPSNAP
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
0
,
sizeof
(
struct
site_survey
),
"getsitesurvey"
},
};
/* Set the number of ioctl available */
wrq
->
u
.
data
.
length
=
1
;
wrq
->
u
.
data
.
length
=
sizeof
(
netwave_private_args
)
/
sizeof
(
netwave_private_args
[
0
])
;
/* Copy structure to the user buffer */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
(
u_char
*
)
priv
,
sizeof
(
priv
)))
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
(
u_char
*
)
netwave_private_args
,
sizeof
(
netwave_private_args
)))
ret
=
-
EFAULT
;
}
break
;
case
SIOCGIPSNAP
:
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
/* Take snapshot of environment */
netwave_snapshot
(
priv
,
ramBase
,
iobase
);
wrq
->
u
.
data
.
length
=
priv
->
nss
.
length
;
char
buffer
[
sizeof
(
struct
site_survey
)];
ret
=
netwave_get_snap
(
dev
,
NULL
,
&
(
wrq
->
u
),
buffer
);
/* Copy structure to the user buffer */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
(
u_char
*
)
&
priv
->
nss
,
buffer
,
sizeof
(
struct
site_survey
)))
{
printk
(
KERN_DEBUG
"Bad buffer!
\n
"
);
break
;
}
priv
->
lastExec
=
jiffies
;
}
break
;
#endif
#endif
/* WIRELESS_EXT <= 12 */
#endif
/* WIRELESS_EXT */
default:
ret
=
-
EOPNOTSUPP
;
}
/* ReEnable interrupts & restore flags */
restore_flags
(
flags
);
return
ret
;
}
...
...
drivers/net/wireless/wavelan.c
View file @
a5220ff4
...
...
@@ -1786,45 +1786,41 @@ static inline void wl_his_gather(device * dev, u8 * stats)
/*------------------------------------------------------------------*/
/*
* Perform ioctl for configuration and information.
* It is here that the wireless extensions are treated (iwconfig).
* Wireless Handler : get protocol name
*/
static
int
wavelan_ioctl
(
struct
net_device
*
dev
,
/* device on which the ioctl is applied */
struct
ifreq
*
rq
,
/* data passed */
int
cmd
)
{
/* ioctl number */
static
int
wavelan_get_name
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
strcpy
(
wrqu
->
name
,
"WaveLAN"
);
return
0
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set NWID
*/
static
int
wavelan_set_nwid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
struct
iwreq
*
wrq
=
(
struct
iwreq
*
)
rq
;
psa_t
psa
;
mm_t
m
;
unsigned
long
flags
;
int
ret
=
0
;
int
err
=
0
;
#ifdef DEBUG_IOCTL_TRACE
printk
(
KERN_DEBUG
"%s: ->wavelan_ioctl(cmd=0x%X)
\n
"
,
dev
->
name
,
cmd
);
#endif
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Look what is the request */
switch
(
cmd
)
{
/* --------------- WIRELESS EXTENSIONS --------------- */
case
SIOCGIWNAME
:
strcpy
(
wrq
->
u
.
name
,
"WaveLAN"
);
break
;
case
SIOCSIWNWID
:
/* Set NWID in WaveLAN. */
if
(
!
wrq
->
u
.
nwid
.
disabled
)
{
if
(
!
wrqu
->
nwid
.
disabled
)
{
/* Set NWID in psa */
psa
.
psa_nwid
[
0
]
=
(
wrq
->
u
.
nwid
.
value
&
0xFF00
)
>>
8
;
psa
.
psa_nwid
[
1
]
=
wrq
->
u
.
nwid
.
value
&
0xFF
;
psa
.
psa_nwid
[
0
]
=
(
wrqu
->
nwid
.
value
&
0xFF00
)
>>
8
;
psa
.
psa_nwid
[
1
]
=
wrqu
->
nwid
.
value
&
0xFF
;
psa
.
psa_nwid_select
=
0x01
;
psa_write
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
psa
.
psa_nwid
-
(
char
*
)
&
psa
,
...
...
@@ -1853,29 +1849,93 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* update the Wavelan checksum */
update_psa_checksum
(
dev
,
ioaddr
,
lp
->
hacr
);
break
;
case
SIOCGIWNWID
:
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get NWID
*/
static
int
wavelan_get_nwid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Read the NWID. */
psa_read
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
psa
.
psa_nwid
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
psa
.
psa_nwid
,
3
);
wrq
->
u
.
nwid
.
value
=
(
psa
.
psa_nwid
[
0
]
<<
8
)
+
psa
.
psa_nwid
[
1
];
wrq
->
u
.
nwid
.
disabled
=
!
(
psa
.
psa_nwid_select
);
wrq
->
u
.
nwid
.
fixed
=
1
;
/* Superfluous */
break
;
wrqu
->
nwid
.
value
=
(
psa
.
psa_nwid
[
0
]
<<
8
)
+
psa
.
psa_nwid
[
1
];
wrqu
->
nwid
.
disabled
=
!
(
psa
.
psa_nwid_select
);
wrqu
->
nwid
.
fixed
=
1
;
/* Superfluous */
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set frequency
*/
static
int
wavelan_set_freq
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
unsigned
long
flags
;
int
ret
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
case
SIOCSIWFREQ
:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if
(
!
(
mmc_in
(
ioaddr
,
mmroff
(
0
,
mmr_fee_status
))
&
(
MMR_FEE_STATUS_DWLD
|
MMR_FEE_STATUS_BUSY
)))
ret
=
wv_set_frequency
(
ioaddr
,
&
(
wrq
->
u
.
freq
));
ret
=
wv_set_frequency
(
ioaddr
,
&
(
wrqu
->
freq
));
else
ret
=
-
EOPNOTSUPP
;
break
;
case
SIOCGIWFREQ
:
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get frequency
*/
static
int
wavelan_get_freq
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
* Does it work for everybody, especially old cards? */
if
(
!
(
mmc_in
(
ioaddr
,
mmroff
(
0
,
mmr_fee_status
))
&
...
...
@@ -1884,27 +1944,48 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* Ask the EEPROM to read the frequency from the first area. */
fee_read
(
ioaddr
,
0x00
,
&
freq
,
1
);
wrq
->
u
.
freq
.
m
=
((
freq
>>
5
)
*
5
+
24000L
)
*
10000
;
wrq
->
u
.
freq
.
e
=
1
;
wrqu
->
freq
.
m
=
((
freq
>>
5
)
*
5
+
24000L
)
*
10000
;
wrqu
->
freq
.
e
=
1
;
}
else
{
psa_read
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
&
psa
.
psa_subband
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_subband
,
1
);
if
(
psa
.
psa_subband
<=
4
)
{
wrq
->
u
.
freq
.
m
=
fixed_bands
[
psa
.
psa_subband
];
wrq
->
u
.
freq
.
e
=
(
psa
.
psa_subband
!=
0
);
wrqu
->
freq
.
m
=
fixed_bands
[
psa
.
psa_subband
];
wrqu
->
freq
.
e
=
(
psa
.
psa_subband
!=
0
);
}
else
ret
=
-
EOPNOTSUPP
;
}
break
;
case
SIOCSIWSENS
:
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set level threshold
*/
static
int
wavelan_set_sens
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Set the level threshold. */
/* We should complain loudly if wrq->u.
sens.fixed = 0, because we
/* We should complain loudly if wrqu->
sens.fixed = 0, because we
* can't set auto mode... */
psa
.
psa_thr_pre_set
=
wrq
->
u
.
sens
.
value
&
0x3F
;
psa
.
psa_thr_pre_set
=
wrqu
->
sens
.
value
&
0x3F
;
psa_write
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
&
psa
.
psa_thr_pre_set
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_thr_pre_set
,
1
);
...
...
@@ -1912,44 +1993,80 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
update_psa_checksum
(
dev
,
ioaddr
,
lp
->
hacr
);
mmc_out
(
ioaddr
,
mmwoff
(
0
,
mmw_thr_pre_set
),
psa
.
psa_thr_pre_set
);
break
;
case
SIOCGIWSENS
:
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get level threshold
*/
static
int
wavelan_get_sens
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Read the level threshold. */
psa_read
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
&
psa
.
psa_thr_pre_set
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_thr_pre_set
,
1
);
wrq
->
u
.
sens
.
value
=
psa
.
psa_thr_pre_set
&
0x3F
;
wrq
->
u
.
sens
.
fixed
=
1
;
break
;
wrqu
->
sens
.
value
=
psa
.
psa_thr_pre_set
&
0x3F
;
wrqu
->
sens
.
fixed
=
1
;
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set encryption key
*/
static
int
wavelan_set_encode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
unsigned
long
flags
;
psa_t
psa
;
int
ret
=
0
;
case
SIOCSIWENCODE
:
/* Set encryption key */
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Check if capable of encryption */
if
(
!
mmc_encr
(
ioaddr
))
{
ret
=
-
EOPNOTSUPP
;
break
;
}
/* Basic checking... */
if
(
wrq
->
u
.
encoding
.
pointer
!=
(
caddr_t
)
0
)
{
/* Check the size of the key */
if
(
wrq
->
u
.
encoding
.
length
!=
8
)
{
if
((
wrqu
->
encoding
.
length
!=
8
)
&&
(
wrqu
->
encoding
.
length
!=
0
)
)
{
ret
=
-
EINVAL
;
break
;
}
if
(
!
ret
)
{
/* Basic checking... */
if
(
wrqu
->
encoding
.
length
==
8
)
{
/* Copy the key in the driver */
wv_splx
(
lp
,
&
flags
);
err
=
copy_from_user
(
psa
.
psa_encryption_key
,
wrq
->
u
.
encoding
.
pointer
,
wrq
->
u
.
encoding
.
length
);
wv_splhi
(
lp
,
&
flags
);
if
(
err
)
{
ret
=
-
EFAULT
;
break
;
}
memcpy
(
psa
.
psa_encryption_key
,
extra
,
wrqu
->
encoding
.
length
);
psa
.
psa_encryption_select
=
1
;
psa_write
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
&
psa
.
psa_encryption_select
-
(
char
*
)
&
psa
,
...
...
@@ -1963,7 +2080,8 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
psa_encryption_key
,
8
);
}
if
(
wrq
->
u
.
encoding
.
flags
&
IW_ENCODE_DISABLED
)
{
/* disable encryption */
/* disable encryption */
if
(
wrqu
->
encoding
.
flags
&
IW_ENCODE_DISABLED
)
{
psa
.
psa_encryption_select
=
0
;
psa_write
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
&
psa
.
psa_encryption_select
-
...
...
@@ -1975,30 +2093,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* update the Wavelan checksum */
update_psa_checksum
(
dev
,
ioaddr
,
lp
->
hacr
);
break
;
case
SIOCGIWENCODE
:
/* Read the encryption key */
if
(
!
mmc_encr
(
ioaddr
))
{
ret
=
-
EOPNOTSUPP
;
break
;
}
/* only super-user can see encryption key */
if
(
!
capable
(
CAP_NET_ADMIN
))
{
ret
=
-
EPERM
;
break
;
}
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
/* Basic checking... */
if
(
wrq
->
u
.
encoding
.
pointer
!=
(
caddr_t
)
0
)
{
/* Verify the user buffer */
ret
=
verify_area
(
VERIFY_WRITE
,
wrq
->
u
.
encoding
.
pointer
,
8
);
if
(
ret
)
break
;
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get encryption key
*/
static
int
wavelan_get_encode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Check if encryption is available */
if
(
!
mmc_encr
(
ioaddr
))
{
ret
=
-
EOPNOTSUPP
;
}
else
{
/* Read the encryption key */
psa_read
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
&
psa
.
psa_encryption_select
-
(
char
*
)
&
psa
,
...
...
@@ -2007,168 +2132,126 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* encryption is enabled ? */
if
(
psa
.
psa_encryption_select
)
wrq
->
u
.
encoding
.
flags
=
IW_ENCODE_ENABLED
;
wrqu
->
encoding
.
flags
=
IW_ENCODE_ENABLED
;
else
wrq
->
u
.
encoding
.
flags
=
IW_ENCODE_DISABLED
;
wrq
->
u
.
encoding
.
flags
|=
mmc_encr
(
ioaddr
);
wrqu
->
encoding
.
flags
=
IW_ENCODE_DISABLED
;
wrqu
->
encoding
.
flags
|=
mmc_encr
(
ioaddr
);
/* Copy the key to the user buffer */
wrq
->
u
.
encoding
.
length
=
8
;
wv_splx
(
lp
,
&
flags
);
if
(
copy_to_user
(
wrq
->
u
.
encoding
.
pointer
,
psa
.
psa_encryption_key
,
8
))
ret
=
-
EFAULT
;
wv_splhi
(
lp
,
&
flags
);
wrqu
->
encoding
.
length
=
8
;
memcpy
(
extra
,
psa
.
psa_encryption_key
,
wrqu
->
encoding
.
length
);
}
break
;
case
SIOCGIWRANGE
:
/* basic checking */
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
struct
iw_range
range
;
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get range info
*/
static
int
wavelan_get_range
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
struct
iw_range
*
range
=
(
struct
iw_range
*
)
extra
;
unsigned
long
flags
;
int
ret
=
0
;
/* Set the length (very important for backward
* compatibility) */
wrq
->
u
.
data
.
length
=
sizeof
(
struct
iw_range
);
/* Set the length (very important for backward compatibility) */
wrqu
->
data
.
length
=
sizeof
(
struct
iw_range
);
/* Set all the info we don't care or don't know
* about to zero */
memset
(
&
range
,
0
,
sizeof
(
range
));
/* Set all the info we don't care or don't know about to zero */
memset
(
range
,
0
,
sizeof
(
struct
iw_range
));
/* Set the Wireless Extension versions */
range
.
we_version_compiled
=
WIRELESS_EXT
;
range
.
we_version_source
=
9
;
range
->
we_version_compiled
=
WIRELESS_EXT
;
range
->
we_version_source
=
9
;
/* Set information in the range struct. */
range
.
throughput
=
1
.
6
*
1000
*
1000
;
/* don't argue on this ! */
range
.
min_nwid
=
0x0000
;
range
.
max_nwid
=
0xFFFF
;
range
->
throughput
=
1
.
6
*
1000
*
1000
;
/* don't argue on this ! */
range
->
min_nwid
=
0x0000
;
range
->
max_nwid
=
0xFFFF
;
range
->
sensitivity
=
0x3F
;
range
->
max_qual
.
qual
=
MMR_SGNL_QUAL
;
range
->
max_qual
.
level
=
MMR_SIGNAL_LVL
;
range
->
max_qual
.
noise
=
MMR_SILENCE_LVL
;
range
->
avg_qual
.
qual
=
MMR_SGNL_QUAL
;
/* Always max */
/* Need to get better values for those two */
range
->
avg_qual
.
level
=
30
;
range
->
avg_qual
.
noise
=
8
;
range
->
num_bitrates
=
1
;
range
->
bitrate
[
0
]
=
2000000
;
/* 2 Mb/s */
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if
(
!
(
mmc_in
(
ioaddr
,
mmroff
(
0
,
mmr_fee_status
))
&
(
MMR_FEE_STATUS_DWLD
|
MMR_FEE_STATUS_BUSY
)))
{
range
.
num_channels
=
10
;
range
.
num_frequency
=
wv_frequency_list
(
ioaddr
,
range
.
freq
,
range
->
num_channels
=
10
;
range
->
num_frequency
=
wv_frequency_list
(
ioaddr
,
range
->
freq
,
IW_MAX_FREQUENCIES
);
}
else
range
.
num_channels
=
range
.
num_frequency
=
0
;
range
.
sensitivity
=
0x3F
;
range
.
max_qual
.
qual
=
MMR_SGNL_QUAL
;
range
.
max_qual
.
level
=
MMR_SIGNAL_LVL
;
range
.
max_qual
.
noise
=
MMR_SILENCE_LVL
;
range
.
avg_qual
.
qual
=
MMR_SGNL_QUAL
;
/* Always max */
/* Need to get better values for those two */
range
.
avg_qual
.
level
=
30
;
range
.
avg_qual
.
noise
=
8
;
range
.
num_bitrates
=
1
;
range
.
bitrate
[
0
]
=
2000000
;
/* 2 Mb/s */
range
->
num_channels
=
range
->
num_frequency
=
0
;
/* Encryption supported ? */
if
(
mmc_encr
(
ioaddr
))
{
range
.
encoding_size
[
0
]
=
8
;
/* DES = 64 bits key */
range
.
num_encoding_sizes
=
1
;
range
.
max_encoding_tokens
=
1
;
/* Only one key possible */
range
->
encoding_size
[
0
]
=
8
;
/* DES = 64 bits key */
range
->
num_encoding_sizes
=
1
;
range
->
max_encoding_tokens
=
1
;
/* Only one key possible */
}
else
{
range
.
num_encoding_sizes
=
0
;
range
.
max_encoding_tokens
=
0
;
range
->
num_encoding_sizes
=
0
;
range
->
max_encoding_tokens
=
0
;
}
/* Copy structure to the user buffer
. */
/* Enable interrupts and restore flags
. */
wv_splx
(
lp
,
&
flags
);
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
&
range
,
sizeof
(
struct
iw_range
)))
ret
=
-
EFAULT
;
wv_splhi
(
lp
,
&
flags
);
}
break
;
case
SIOCGIWPRIV
:
/* Basic checking */
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
struct
iw_priv_args
priv
[]
=
{
/* { cmd,
set_args,
get_args,
name } */
{
SIOCSIPQTHR
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"setqualthr"
},
{
SIOCGIPQTHR
,
0
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
"getqualthr"
},
{
SIOCSIPHISTO
,
IW_PRIV_TYPE_BYTE
|
16
,
0
,
"sethisto"
},
{
SIOCGIPHISTO
,
0
,
IW_PRIV_TYPE_INT
|
16
,
"gethisto"
},
};
/* Set the number of available ioctls. */
wrq
->
u
.
data
.
length
=
4
;
/* Copy structure to the user buffer. */
wv_splx
(
lp
,
&
flags
);
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
(
u8
*
)
priv
,
sizeof
(
priv
)))
ret
=
-
EFAULT
;
wv_splhi
(
lp
,
&
flags
);
}
break
;
return
ret
;
}
#ifdef WIRELESS_SPY
case
SIOCSIWSPY
:
/* Set the spy list */
/* Check the number of addresses. */
if
(
wrq
->
u
.
data
.
length
>
IW_MAX_SPY
)
{
ret
=
-
E2BIG
;
break
;
}
lp
->
spy_number
=
wrq
->
u
.
data
.
length
;
/* Are there are addresses to copy? */
if
(
lp
->
spy_number
>
0
)
{
struct
sockaddr
address
[
IW_MAX_SPY
];
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set spy list
*/
static
int
wavelan_set_spy
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
struct
sockaddr
*
address
=
(
struct
sockaddr
*
)
extra
;
int
i
;
int
ret
=
0
;
/* Copy addresses to the driver. */
wv_splx
(
lp
,
&
flags
);
err
=
copy_from_user
(
address
,
wrq
->
u
.
data
.
pointer
,
sizeof
(
struct
sockaddr
)
*
lp
->
spy_number
);
wv_splhi
(
lp
,
&
flags
);
if
(
err
)
{
ret
=
-
EFAULT
;
break
;
}
/* Disable spy while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp
->
spy_number
=
0
;
/* Are there are addresses to copy? */
if
(
wrqu
->
data
.
length
>
0
)
{
/* Copy addresses to the lp structure. */
for
(
i
=
0
;
i
<
lp
->
spy_number
;
i
++
)
{
memcpy
(
lp
->
spy_address
[
i
],
address
[
i
].
sa_data
,
for
(
i
=
0
;
i
<
wrqu
->
data
.
length
;
i
++
)
{
memcpy
(
lp
->
spy_address
[
i
],
address
[
i
].
sa_data
,
WAVELAN_ADDR_SIZE
);
}
/* Reset structure. */
memset
(
lp
->
spy_stat
,
0x00
,
sizeof
(
iw_qual
)
*
IW_MAX_SPY
);
memset
(
lp
->
spy_stat
,
0x00
,
sizeof
(
iw_qual
)
*
IW_MAX_SPY
);
#ifdef DEBUG_IOCTL_INFO
printk
(
KERN_DEBUG
"SetSpy: set of new addresses is:
\n
"
);
for
(
i
=
0
;
i
<
wrq
->
u
.
data
.
length
;
i
++
)
for
(
i
=
0
;
i
<
wrqu
->
data
.
length
;
i
++
)
printk
(
KERN_DEBUG
"%02X:%02X:%02X:%02X:%02X:%02X
\n
"
,
lp
->
spy_address
[
i
][
0
],
...
...
@@ -2180,20 +2263,28 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
#endif
/* DEBUG_IOCTL_INFO */
}
break
;
case
SIOCGIWSPY
:
/* Get the spy list and spy stats. */
/* Now we can set the number of addresses */
lp
->
spy_number
=
wrqu
->
data
.
length
;
/* Set the number of addresses */
wrq
->
u
.
data
.
length
=
lp
->
spy_number
;
return
ret
;
}
/* Does the user want to have the addresses back? */
if
((
lp
->
spy_number
>
0
)
&&
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
))
{
struct
sockaddr
address
[
IW_MAX_SPY
];
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get spy list
*/
static
int
wavelan_get_spy
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
struct
sockaddr
*
address
=
(
struct
sockaddr
*
)
extra
;
int
i
;
/* Set the number of addresses */
wrqu
->
data
.
length
=
lp
->
spy_number
;
/* Copy addresses from the lp structure. */
for
(
i
=
0
;
i
<
lp
->
spy_number
;
i
++
)
{
memcpy
(
address
[
i
].
sa_data
,
...
...
@@ -2201,42 +2292,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
WAVELAN_ADDR_SIZE
);
address
[
i
].
sa_family
=
AF_UNIX
;
}
/* Copy addresses to the user buffer. */
wv_splx
(
lp
,
&
flags
);
err
=
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
address
,
sizeof
(
struct
sockaddr
)
*
lp
->
spy_number
);
/* Copy stats to the user buffer (just after). */
err
|=
copy_to_user
(
wrq
->
u
.
data
.
pointer
+
(
sizeof
(
struct
sockaddr
)
*
lp
->
spy_number
),
lp
->
spy_stat
,
sizeof
(
iw_qual
)
*
lp
->
spy_number
);
wv_splhi
(
lp
,
&
flags
);
if
(
err
)
{
ret
=
-
EFAULT
;
break
;
}
if
(
lp
->
spy_number
>
0
)
memcpy
(
extra
+
(
sizeof
(
struct
sockaddr
)
*
lp
->
spy_number
),
lp
->
spy_stat
,
sizeof
(
iw_qual
)
*
lp
->
spy_number
);
/* Reset updated flags. */
for
(
i
=
0
;
i
<
lp
->
spy_number
;
i
++
)
lp
->
spy_stat
[
i
].
updated
=
0x0
;
}
/* if(pointer != NULL) */
break
;
return
(
0
);
}
#endif
/* WIRELESS_SPY */
/* ------------------ PRIVATE IOCTL ------------------ */
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set quality threshold
*/
static
int
wavelan_set_qthr
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
case
SIOCSIPQTHR
:
if
(
!
capable
(
CAP_NET_ADMIN
))
{
ret
=
-
EPERM
;
break
;
}
psa
.
psa_quality_thr
=
*
(
wrq
->
u
.
name
)
&
0x0F
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
psa
.
psa_quality_thr
=
*
(
extra
)
&
0x0F
;
psa_write
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
&
psa
.
psa_quality_thr
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_quality_thr
,
1
);
...
...
@@ -2244,81 +2330,193 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
update_psa_checksum
(
dev
,
ioaddr
,
lp
->
hacr
);
mmc_out
(
ioaddr
,
mmwoff
(
0
,
mmw_quality_thr
),
psa
.
psa_quality_thr
);
break
;
case
SIOCGIPQTHR
:
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
0
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static
int
wavelan_get_qthr
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
psa_read
(
ioaddr
,
lp
->
hacr
,
(
char
*
)
&
psa
.
psa_quality_thr
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_quality_thr
,
1
);
*
(
wrq
->
u
.
name
)
=
psa
.
psa_quality_thr
&
0x0F
;
break
;
*
(
extra
)
=
psa
.
psa_quality_thr
&
0x0F
;
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
0
;
}
#ifdef HISTOGRAM
case
SIOCSIPHISTO
:
/* Verify that the user is root. */
if
(
!
capable
(
CAP_NET_ADMIN
))
{
ret
=
-
EPERM
;
break
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set histogram
*/
static
int
wavelan_set_histo
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
/* Check the number of intervals. */
if
(
wrq
->
u
.
data
.
length
>
16
)
{
ret
=
-
E2BIG
;
break
;
if
(
wrqu
->
data
.
length
>
16
)
{
return
(
-
E2BIG
);
}
lp
->
his_number
=
wrq
->
u
.
data
.
length
;
/* Are there addresses to copy? */
if
(
lp
->
his_number
>
0
)
{
/* Disable histo while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp
->
his_number
=
0
;
/* Are there ranges to copy? */
if
(
wrqu
->
data
.
length
>
0
)
{
/* Copy interval ranges to the driver */
wv_splx
(
lp
,
&
flags
);
err
=
copy_from_user
(
lp
->
his_range
,
wrq
->
u
.
data
.
pointer
,
sizeof
(
char
)
*
lp
->
his_number
)
;
wv_splhi
(
lp
,
&
flags
);
if
(
err
)
{
ret
=
-
EFAULT
;
break
;
memcpy
(
lp
->
his_range
,
extra
,
wrqu
->
data
.
length
);
{
int
i
;
printk
(
KERN_DEBUG
"Histo :"
);
for
(
i
=
0
;
i
<
wrqu
->
data
.
length
;
i
++
)
printk
(
" %d"
,
lp
->
his_range
[
i
])
;
printk
(
"
\n
"
)
;
}
/* Rese
t structure. */
/* Reset resul
t structure. */
memset
(
lp
->
his_sum
,
0x00
,
sizeof
(
long
)
*
16
);
}
break
;
case
SIOCGIPHISTO
:
/* Now we can set the number of ranges */
lp
->
his_number
=
wrqu
->
data
.
length
;
return
(
0
);
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get histogram
*/
static
int
wavelan_get_histo
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
/* Set the number of intervals. */
wrq
->
u
.
data
.
length
=
lp
->
his_number
;
wrqu
->
data
.
length
=
lp
->
his_number
;
/* Give back the distribution statistics */
if
((
lp
->
his_number
>
0
)
&&
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
))
{
/* Copy data to the user buffer. */
wv_splx
(
lp
,
&
flags
);
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
lp
->
his_sum
,
sizeof
(
long
)
*
lp
->
his_number
);
ret
=
-
EFAULT
;
wv_splhi
(
lp
,
&
flags
);
if
(
lp
->
his_number
>
0
)
memcpy
(
extra
,
lp
->
his_sum
,
sizeof
(
long
)
*
lp
->
his_number
);
}
/* if(pointer != NULL) */
break
;
return
(
0
);
}
#endif
/* HISTOGRAM */
/* ------------------- OTHER IOCTL ------------------- */
/*------------------------------------------------------------------*/
/*
* Structures to export the Wireless Handlers
*/
default:
ret
=
-
EOPNOTSUPP
;
}
/* switch (cmd) */
static
const
iw_handler
wavelan_handler
[]
=
{
NULL
,
/* SIOCSIWNAME */
wavelan_get_name
,
/* SIOCGIWNAME */
wavelan_set_nwid
,
/* SIOCSIWNWID */
wavelan_get_nwid
,
/* SIOCGIWNWID */
wavelan_set_freq
,
/* SIOCSIWFREQ */
wavelan_get_freq
,
/* SIOCGIWFREQ */
NULL
,
/* SIOCSIWMODE */
NULL
,
/* SIOCGIWMODE */
wavelan_set_sens
,
/* SIOCSIWSENS */
wavelan_get_sens
,
/* SIOCGIWSENS */
NULL
,
/* SIOCSIWRANGE */
wavelan_get_range
,
/* SIOCGIWRANGE */
NULL
,
/* SIOCSIWPRIV */
NULL
,
/* SIOCGIWPRIV */
NULL
,
/* SIOCSIWSTATS */
NULL
,
/* SIOCGIWSTATS */
#ifdef WIRELESS_SPY
wavelan_set_spy
,
/* SIOCSIWSPY */
wavelan_get_spy
,
/* SIOCGIWSPY */
#else
/* WIRELESS_SPY */
NULL
,
/* SIOCSIWSPY */
NULL
,
/* SIOCGIWSPY */
#endif
/* WIRELESS_SPY */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCSIWAP */
NULL
,
/* SIOCGIWAP */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCGIWAPLIST */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCSIWESSID */
NULL
,
/* SIOCGIWESSID */
NULL
,
/* SIOCSIWNICKN */
NULL
,
/* SIOCGIWNICKN */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCSIWRATE */
NULL
,
/* SIOCGIWRATE */
NULL
,
/* SIOCSIWRTS */
NULL
,
/* SIOCGIWRTS */
NULL
,
/* SIOCSIWFRAG */
NULL
,
/* SIOCGIWFRAG */
NULL
,
/* SIOCSIWTXPOW */
NULL
,
/* SIOCGIWTXPOW */
NULL
,
/* SIOCSIWRETRY */
NULL
,
/* SIOCGIWRETRY */
/* Bummer ! Why those are only at the end ??? */
wavelan_set_encode
,
/* SIOCSIWENCODE */
wavelan_get_encode
,
/* SIOCGIWENCODE */
};
static
const
iw_handler
wavelan_private_handler
[]
=
{
wavelan_set_qthr
,
/* SIOCIWFIRSTPRIV */
wavelan_get_qthr
,
/* SIOCIWFIRSTPRIV + 1 */
#ifdef HISTOGRAM
wavelan_set_histo
,
/* SIOCIWFIRSTPRIV + 2 */
wavelan_get_histo
,
/* SIOCIWFIRSTPRIV + 3 */
#endif
/* HISTOGRAM */
};
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
static
const
struct
iw_priv_args
wavelan_private_args
[]
=
{
/*{ cmd, set_args, get_args, name } */
{
SIOCSIPQTHR
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"setqualthr"
},
{
SIOCGIPQTHR
,
0
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
"getqualthr"
},
{
SIOCSIPHISTO
,
IW_PRIV_TYPE_BYTE
|
16
,
0
,
"sethisto"
},
{
SIOCGIPHISTO
,
0
,
IW_PRIV_TYPE_INT
|
16
,
"gethisto"
},
};
#ifdef DEBUG_IOCTL_TRACE
printk
(
KERN_DEBUG
"%s: <-wavelan_ioctl()
\n
"
,
dev
->
name
);
#endif
return
ret
;
}
static
const
struct
iw_handler_def
wavelan_handler_def
=
{
num_standard:
sizeof
(
wavelan_handler
)
/
sizeof
(
iw_handler
),
num_private:
sizeof
(
wavelan_private_handler
)
/
sizeof
(
iw_handler
),
num_private_args:
sizeof
(
wavelan_private_args
)
/
sizeof
(
struct
iw_priv_args
),
standard:
(
iw_handler
*
)
wavelan_handler
,
private:
(
iw_handler
*
)
wavelan_private_handler
,
private_args:
(
struct
iw_priv_args
*
)
wavelan_private_args
,
};
/*------------------------------------------------------------------*/
/*
...
...
@@ -4069,8 +4267,8 @@ static int __init wavelan_config(device * dev)
#endif
/* SET_MAC_ADDRESS */
#ifdef WIRELESS_EXT
/* if wireless extension exists in the kernel */
dev
->
do_ioctl
=
wavelan_ioctl
;
dev
->
get_wireless_stats
=
wavelan_get_wireless_stats
;
dev
->
wireless_handlers
=
(
struct
iw_handler_def
*
)
&
wavelan_handler_def
;
#endif
dev
->
mtu
=
WAVELAN_MTU
;
...
...
drivers/net/wireless/wavelan.p.h
View file @
a5220ff4
...
...
@@ -345,6 +345,12 @@
* - Fix spinlock stupid bugs that I left in. The driver is now SMP
* compliant and doesn't lockup at startup.
*
* Changes made for release in 2.5.2 :
* ---------------------------------
* - Use new driver API for Wireless Extensions :
* o got rid of wavelan_ioctl()
* o use a bunch of iw_handler instead
*
* Wishes & dreams:
* ----------------
* - roaming (see Pcmcia driver)
...
...
@@ -379,6 +385,7 @@
#include <linux/init.h>
#include <linux/wireless.h>
/* Wireless extensions */
#include <net/iw_handler.h>
/* Wireless handlers */
/* WaveLAN declarations */
#include "i82586.h"
...
...
@@ -436,7 +443,7 @@
/************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW
static
const
char
*
version
=
"wavelan.c : v2
3 (SMP + wireless extensions) 05/10/00
\n
"
;
static
const
char
*
version
=
"wavelan.c : v2
4 (SMP + wireless extensions) 11/12/01
\n
"
;
#endif
/* Watchdog temporisation */
...
...
@@ -449,11 +456,9 @@ static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/
#define SIOCSIPQTHR SIOCIWFIRSTPRIV
/* Set quality threshold */
#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1
/* Get quality threshold */
#define SIOCSIPLTHR SIOCIWFIRSTPRIV + 2
/* Set level threshold */
#define SIOCGIPLTHR SIOCIWFIRSTPRIV + 3
/* Get level threshold */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV +
6
/* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV +
7
/* Get histogram values */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV +
2
/* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV +
3
/* Get histogram values */
/****************************** TYPES ******************************/
...
...
drivers/net/wireless/wavelan_cs.c
View file @
a5220ff4
...
...
@@ -1884,331 +1884,1149 @@ wl_his_gather(device * dev,
/*------------------------------------------------------------------*/
/*
* Perform ioctl : config & info stuff
* This is here that are treated the wireless extensions (iwconfig)
* Wireless Handler : get protocol name
*/
static
int
wavelan_ioctl
(
struct
net_device
*
dev
,
/* Device on wich the ioctl apply */
struct
ifreq
*
rq
,
/* Data passed */
int
cmd
)
/* Ioctl number */
static
int
wavelan_get_name
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
strcpy
(
wrqu
->
name
,
"WaveLAN"
);
return
0
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set NWID
*/
static
int
wavelan_set_nwid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
ioaddr_t
base
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
struct
iwreq
*
wrq
=
(
struct
iwreq
*
)
rq
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
mm_t
m
;
unsigned
long
flags
;
int
ret
=
0
;
#ifdef DEBUG_IOCTL_TRACE
printk
(
KERN_DEBUG
"%s: ->wavelan_ioctl(cmd=0x%X)
\n
"
,
dev
->
name
,
cmd
);
#endif
/* Disable interrupts & save flags */
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Look what is the request */
switch
(
cmd
)
{
/* --------------- WIRELESS EXTENSIONS --------------- */
case
SIOCGIWNAME
:
strcpy
(
wrq
->
u
.
name
,
"Wavelan"
);
break
;
case
SIOCSIWNWID
:
/* Set NWID in wavelan */
/* Set NWID in WaveLAN. */
#if WIRELESS_EXT > 8
if
(
!
wrq
->
u
.
nwid
.
disabled
)
{
if
(
!
wrqu
->
nwid
.
disabled
)
{
/* Set NWID in psa */
psa
.
psa_nwid
[
0
]
=
(
wrq
->
u
.
nwid
.
value
&
0xFF00
)
>>
8
;
psa
.
psa_nwid
[
1
]
=
wrq
->
u
.
nwid
.
value
&
0xFF
;
psa
.
psa_nwid
[
0
]
=
(
wrqu
->
nwid
.
value
&
0xFF00
)
>>
8
;
psa
.
psa_nwid
[
1
]
=
wrqu
->
nwid
.
value
&
0xFF
;
#else
/* WIRELESS_EXT > 8 */
if
(
wrq
->
u
.
nwid
.
on
)
{
if
(
wrq
->
u
.
nwid
.
on
)
{
/* Set NWID in psa */
psa
.
psa_nwid
[
0
]
=
(
wrq
->
u
.
nwid
.
nwid
&
0xFF00
)
>>
8
;
psa
.
psa_nwid
[
1
]
=
wrq
->
u
.
nwid
.
nwid
&
0xFF
;
#endif
/* WIRELESS_EXT > 8 */
psa
.
psa_nwid_select
=
0x01
;
psa_write
(
dev
,
(
char
*
)
psa
.
psa_nwid
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
psa
.
psa_nwid
,
3
);
psa_write
(
dev
,
(
char
*
)
psa
.
psa_nwid
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
psa
.
psa_nwid
,
3
);
/* Set NWID in mmc
*/
/* Set NWID in mmc.
*/
m
.
w
.
mmw_netw_id_l
=
psa
.
psa_nwid
[
1
];
m
.
w
.
mmw_netw_id_h
=
psa
.
psa_nwid
[
0
];
mmc_write
(
base
,
(
char
*
)
&
m
.
w
.
mmw_netw_id_l
-
(
char
*
)
&
m
,
(
unsigned
char
*
)
&
m
.
w
.
mmw_netw_id_l
,
2
);
mmc_write
(
base
,
(
char
*
)
&
m
.
w
.
mmw_netw_id_l
-
(
char
*
)
&
m
,
(
unsigned
char
*
)
&
m
.
w
.
mmw_netw_id_l
,
2
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_loopt_sel
),
0x00
);
}
else
{
/* Disable nwid in the psa */
}
else
{
/* Disable NWID in the psa. */
psa
.
psa_nwid_select
=
0x00
;
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_nwid_select
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_nwid_select
,
1
);
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_nwid_select
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_nwid_select
,
1
);
/* Disable nwid in the mmc (no filtering) */
mmc_out
(
base
,
mmwoff
(
0
,
mmw_loopt_sel
),
MMW_LOOPT_SEL_DIS_NWID
);
/* Disable NWID in the mmc (no filtering). */
mmc_out
(
base
,
mmwoff
(
0
,
mmw_loopt_sel
),
MMW_LOOPT_SEL_DIS_NWID
);
}
/* update the Wavelan checksum */
update_psa_checksum
(
dev
);
break
;
case
SIOCGIWNWID
:
/* Read the NWID */
psa_read
(
dev
,
(
char
*
)
psa
.
psa_nwid
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
psa
.
psa_nwid
,
3
);
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get NWID
*/
static
int
wavelan_get_nwid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Read the NWID. */
psa_read
(
dev
,
(
char
*
)
psa
.
psa_nwid
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
psa
.
psa_nwid
,
3
);
#if WIRELESS_EXT > 8
wrq
->
u
.
nwid
.
value
=
(
psa
.
psa_nwid
[
0
]
<<
8
)
+
psa
.
psa_nwid
[
1
];
wrq
->
u
.
nwid
.
disabled
=
!
(
psa
.
psa_nwid_select
);
wrq
->
u
.
nwid
.
fixed
=
1
;
/* Superfluous */
wrqu
->
nwid
.
value
=
(
psa
.
psa_nwid
[
0
]
<<
8
)
+
psa
.
psa_nwid
[
1
];
wrqu
->
nwid
.
disabled
=
!
(
psa
.
psa_nwid_select
);
wrqu
->
nwid
.
fixed
=
1
;
/* Superfluous */
#else
/* WIRELESS_EXT > 8 */
wrq
->
u
.
nwid
.
nwid
=
(
psa
.
psa_nwid
[
0
]
<<
8
)
+
psa
.
psa_nwid
[
1
];
wrq
->
u
.
nwid
.
on
=
psa
.
psa_nwid_select
;
#endif
/* WIRELESS_EXT > 8 */
break
;
case
SIOCSIWFREQ
:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
if
(
!
(
mmc_in
(
base
,
mmroff
(
0
,
mmr_fee_status
))
&
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set frequency
*/
static
int
wavelan_set_freq
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
ioaddr_t
base
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
unsigned
long
flags
;
int
ret
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if
(
!
(
mmc_in
(
base
,
mmroff
(
0
,
mmr_fee_status
))
&
(
MMR_FEE_STATUS_DWLD
|
MMR_FEE_STATUS_BUSY
)))
ret
=
wv_set_frequency
(
base
,
&
(
wrq
->
u
.
freq
));
ret
=
wv_set_frequency
(
base
,
&
(
wrqu
->
freq
));
else
ret
=
-
EOPNOTSUPP
;
break
;
case
SIOCGIWFREQ
:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
* (does it work for everybody ? - especially old cards...) */
if
(
!
(
mmc_in
(
base
,
mmroff
(
0
,
mmr_fee_status
))
&
(
MMR_FEE_STATUS_DWLD
|
MMR_FEE_STATUS_BUSY
)))
{
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get frequency
*/
static
int
wavelan_get_freq
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
ioaddr_t
base
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
* Does it work for everybody, especially old cards? */
if
(
!
(
mmc_in
(
base
,
mmroff
(
0
,
mmr_fee_status
))
&
(
MMR_FEE_STATUS_DWLD
|
MMR_FEE_STATUS_BUSY
)))
{
unsigned
short
freq
;
/* Ask the EEprom to read the frequency from the first area */
fee_read
(
base
,
0x00
/* 1st area - frequency... */
,
&
freq
,
1
);
wrq
->
u
.
freq
.
m
=
((
freq
>>
5
)
*
5
+
24000L
)
*
10000
;
wrq
->
u
.
freq
.
e
=
1
;
/* Ask the EEPROM to read the frequency from the first area. */
fee_read
(
base
,
0x00
,
&
freq
,
1
);
wrqu
->
freq
.
m
=
((
freq
>>
5
)
*
5
+
24000L
)
*
10000
;
wrqu
->
freq
.
e
=
1
;
}
else
{
psa_read
(
dev
,
(
char
*
)
&
psa
.
psa_subband
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_subband
,
1
);
if
(
psa
.
psa_subband
<=
4
)
{
wrqu
->
freq
.
m
=
fixed_bands
[
psa
.
psa_subband
];
wrqu
->
freq
.
e
=
(
psa
.
psa_subband
!=
0
);
}
else
ret
=
-
EOPNOTSUPP
;
}
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set level threshold
*/
static
int
wavelan_set_sens
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
ioaddr_t
base
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Set the level threshold. */
#if WIRELESS_EXT > 7
/* We should complain loudly if wrqu->sens.fixed = 0, because we
* can't set auto mode... */
psa
.
psa_thr_pre_set
=
wrqu
->
sens
.
value
&
0x3F
;
#else
/* WIRELESS_EXT > 7 */
psa
.
psa_thr_pre_set
=
wrq
->
u
.
sensitivity
&
0x3F
;
#endif
/* WIRELESS_EXT > 7 */
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_thr_pre_set
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_thr_pre_set
,
1
);
/* update the Wavelan checksum */
update_psa_checksum
(
dev
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_thr_pre_set
),
psa
.
psa_thr_pre_set
);
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get level threshold
*/
static
int
wavelan_get_sens
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Read the level threshold. */
psa_read
(
dev
,
(
char
*
)
&
psa
.
psa_thr_pre_set
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_thr_pre_set
,
1
);
#if WIRELESS_EXT > 7
wrqu
->
sens
.
value
=
psa
.
psa_thr_pre_set
&
0x3F
;
wrqu
->
sens
.
fixed
=
1
;
#else
/* WIRELESS_EXT > 7 */
wrq
->
u
.
sensitivity
=
psa
.
psa_thr_pre_set
&
0x3F
;
#endif
/* WIRELESS_EXT > 7 */
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
#if WIRELESS_EXT > 8
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set encryption key
*/
static
int
wavelan_set_encode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
ioaddr_t
base
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
unsigned
long
flags
;
psa_t
psa
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Check if capable of encryption */
if
(
!
mmc_encr
(
base
))
{
ret
=
-
EOPNOTSUPP
;
}
/* Check the size of the key */
if
((
wrqu
->
encoding
.
length
!=
8
)
&&
(
wrqu
->
encoding
.
length
!=
0
))
{
ret
=
-
EINVAL
;
}
if
(
!
ret
)
{
/* Basic checking... */
if
(
wrqu
->
encoding
.
length
==
8
)
{
/* Copy the key in the driver */
memcpy
(
psa
.
psa_encryption_key
,
extra
,
wrqu
->
encoding
.
length
);
psa
.
psa_encryption_select
=
1
;
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_encryption_select
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_encryption_select
,
8
+
1
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_encr_enable
),
MMW_ENCR_ENABLE_EN
|
MMW_ENCR_ENABLE_MODE
);
mmc_write
(
base
,
mmwoff
(
0
,
mmw_encr_key
),
(
unsigned
char
*
)
&
psa
.
psa_encryption_key
,
8
);
}
/* disable encryption */
if
(
wrqu
->
encoding
.
flags
&
IW_ENCODE_DISABLED
)
{
psa
.
psa_encryption_select
=
0
;
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_encryption_select
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_encryption_select
,
1
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_encr_enable
),
0
);
}
/* update the Wavelan checksum */
update_psa_checksum
(
dev
);
}
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get encryption key
*/
static
int
wavelan_get_encode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
ioaddr_t
base
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Check if encryption is available */
if
(
!
mmc_encr
(
base
))
{
ret
=
-
EOPNOTSUPP
;
}
else
{
/* Read the encryption key */
psa_read
(
dev
,
(
char
*
)
&
psa
.
psa_encryption_select
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_encryption_select
,
1
+
8
);
/* encryption is enabled ? */
if
(
psa
.
psa_encryption_select
)
wrqu
->
encoding
.
flags
=
IW_ENCODE_ENABLED
;
else
{
psa_read
(
dev
,
(
char
*
)
&
psa
.
psa_subband
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_subband
,
1
);
wrqu
->
encoding
.
flags
=
IW_ENCODE_DISABLED
;
wrqu
->
encoding
.
flags
|=
mmc_encr
(
base
);
/* Copy the key to the user buffer */
wrqu
->
encoding
.
length
=
8
;
memcpy
(
extra
,
psa
.
psa_encryption_key
,
wrqu
->
encoding
.
length
);
}
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
#endif
/* WIRELESS_EXT > 8 */
#ifdef WAVELAN_ROAMING_EXT
#if WIRELESS_EXT > 5
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set ESSID (domain)
*/
static
int
wavelan_set_essid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Check if disable */
if
(
wrqu
->
data
.
flags
==
0
)
lp
->
filter_domains
=
0
;
else
{
char
essid
[
IW_ESSID_MAX_SIZE
+
1
];
char
*
endp
;
/* Terminate the string */
memcpy
(
essid
,
extra
,
wrqu
->
data
.
length
);
essid
[
IW_ESSID_MAX_SIZE
]
=
'\0'
;
#ifdef DEBUG_IOCTL_INFO
printk
(
KERN_DEBUG
"SetEssid : ``%s''
\n
"
,
essid
);
#endif
/* DEBUG_IOCTL_INFO */
/* Convert to a number (note : Wavelan specific) */
lp
->
domain_id
=
simple_strtoul
(
essid
,
&
endp
,
16
);
/* Has it worked ? */
if
(
endp
>
essid
)
lp
->
filter_domains
=
1
;
else
{
lp
->
filter_domains
=
0
;
ret
=
-
EINVAL
;
}
}
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get ESSID (domain)
*/
static
int
wavelan_get_essid
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
/* Is the domain ID active ? */
wrqu
->
data
.
flags
=
lp
->
filter_domains
;
/* Copy Domain ID into a string (Wavelan specific) */
/* Sound crazy, be we can't have a snprintf in the kernel !!! */
sprintf
(
extra
,
"%lX"
,
lp
->
domain_id
);
extra
[
IW_ESSID_MAX_SIZE
]
=
'\0'
;
/* Set the length */
wrqu
->
data
.
length
=
strlen
(
extra
)
+
1
;
return
0
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set AP address
*/
static
int
wavelan_set_wap
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
#ifdef DEBUG_IOCTL_INFO
printk
(
KERN_DEBUG
"Set AP to : %02X:%02X:%02X:%02X:%02X:%02X
\n
"
,
wrqu
->
ap_addr
.
sa_data
[
0
],
wrqu
->
ap_addr
.
sa_data
[
1
],
wrqu
->
ap_addr
.
sa_data
[
2
],
wrqu
->
ap_addr
.
sa_data
[
3
],
wrqu
->
ap_addr
.
sa_data
[
4
],
wrqu
->
ap_addr
.
sa_data
[
5
]);
#endif
/* DEBUG_IOCTL_INFO */
return
-
EOPNOTSUPP
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get AP address
*/
static
int
wavelan_get_wap
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
/* Should get the real McCoy instead of own Ethernet address */
memcpy
(
wrqu
->
ap_addr
.
sa_data
,
dev
->
dev_addr
,
WAVELAN_ADDR_SIZE
);
wrqu
->
ap_addr
.
sa_family
=
ARPHRD_ETHER
;
return
-
EOPNOTSUPP
;
}
#endif
/* WIRELESS_EXT > 5 */
#endif
/* WAVELAN_ROAMING_EXT */
#if WIRELESS_EXT > 8
#ifdef WAVELAN_ROAMING
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set mode
*/
static
int
wavelan_set_mode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
unsigned
long
flags
;
int
ret
=
0
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Check mode */
switch
(
wrqu
->
mode
)
{
case
IW_MODE_ADHOC
:
if
(
do_roaming
)
{
wv_roam_cleanup
(
dev
);
do_roaming
=
0
;
}
break
;
case
IW_MODE_INFRA
:
if
(
!
do_roaming
)
{
wv_roam_init
(
dev
);
do_roaming
=
1
;
}
break
;
default:
ret
=
-
EINVAL
;
}
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get mode
*/
static
int
wavelan_get_mode
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
if
(
do_roaming
)
wrqu
->
mode
=
IW_MODE_INFRA
;
else
wrqu
->
mode
=
IW_MODE_ADHOC
;
return
0
;
}
#endif
/* WAVELAN_ROAMING */
#endif
/* WIRELESS_EXT > 8 */
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get range info
*/
static
int
wavelan_get_range
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
ioaddr_t
base
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
struct
iw_range
*
range
=
(
struct
iw_range
*
)
extra
;
unsigned
long
flags
;
int
ret
=
0
;
/* Set the length (very important for backward compatibility) */
wrqu
->
data
.
length
=
sizeof
(
struct
iw_range
);
/* Set all the info we don't care or don't know about to zero */
memset
(
range
,
0
,
sizeof
(
struct
iw_range
));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range
->
we_version_compiled
=
WIRELESS_EXT
;
range
->
we_version_source
=
9
;
#endif
/* WIRELESS_EXT > 10 */
/* Set information in the range struct. */
range
->
throughput
=
1
.
4
*
1000
*
1000
;
/* don't argue on this ! */
range
->
min_nwid
=
0x0000
;
range
->
max_nwid
=
0xFFFF
;
range
->
sensitivity
=
0x3F
;
range
->
max_qual
.
qual
=
MMR_SGNL_QUAL
;
range
->
max_qual
.
level
=
MMR_SIGNAL_LVL
;
range
->
max_qual
.
noise
=
MMR_SILENCE_LVL
;
#if WIRELESS_EXT > 11
range
->
avg_qual
.
qual
=
MMR_SGNL_QUAL
;
/* Always max */
/* Need to get better values for those two */
range
->
avg_qual
.
level
=
30
;
range
->
avg_qual
.
noise
=
8
;
#endif
/* WIRELESS_EXT > 11 */
#if WIRELESS_EXT > 7
range
->
num_bitrates
=
1
;
range
->
bitrate
[
0
]
=
2000000
;
/* 2 Mb/s */
#endif
/* WIRELESS_EXT > 7 */
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if
(
!
(
mmc_in
(
base
,
mmroff
(
0
,
mmr_fee_status
))
&
(
MMR_FEE_STATUS_DWLD
|
MMR_FEE_STATUS_BUSY
)))
{
range
->
num_channels
=
10
;
range
->
num_frequency
=
wv_frequency_list
(
base
,
range
->
freq
,
IW_MAX_FREQUENCIES
);
}
else
range
->
num_channels
=
range
->
num_frequency
=
0
;
#if WIRELESS_EXT > 8
/* Encryption supported ? */
if
(
mmc_encr
(
base
))
{
range
->
encoding_size
[
0
]
=
8
;
/* DES = 64 bits key */
range
->
num_encoding_sizes
=
1
;
range
->
max_encoding_tokens
=
1
;
/* Only one key possible */
}
else
{
range
->
num_encoding_sizes
=
0
;
range
->
max_encoding_tokens
=
0
;
}
#endif
/* WIRELESS_EXT > 8 */
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
ret
;
}
#ifdef WIRELESS_SPY
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set spy list
*/
static
int
wavelan_set_spy
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
struct
sockaddr
*
address
=
(
struct
sockaddr
*
)
extra
;
int
i
;
int
ret
=
0
;
/* Disable spy while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp
->
spy_number
=
0
;
/* Are there are addresses to copy? */
if
(
wrqu
->
data
.
length
>
0
)
{
/* Copy addresses to the lp structure. */
for
(
i
=
0
;
i
<
wrqu
->
data
.
length
;
i
++
)
{
memcpy
(
lp
->
spy_address
[
i
],
address
[
i
].
sa_data
,
WAVELAN_ADDR_SIZE
);
}
/* Reset structure. */
memset
(
lp
->
spy_stat
,
0x00
,
sizeof
(
iw_qual
)
*
IW_MAX_SPY
);
#ifdef DEBUG_IOCTL_INFO
printk
(
KERN_DEBUG
"SetSpy: set of new addresses is:
\n
"
);
for
(
i
=
0
;
i
<
wrqu
->
data
.
length
;
i
++
)
printk
(
KERN_DEBUG
"%02X:%02X:%02X:%02X:%02X:%02X
\n
"
,
lp
->
spy_address
[
i
][
0
],
lp
->
spy_address
[
i
][
1
],
lp
->
spy_address
[
i
][
2
],
lp
->
spy_address
[
i
][
3
],
lp
->
spy_address
[
i
][
4
],
lp
->
spy_address
[
i
][
5
]);
#endif
/* DEBUG_IOCTL_INFO */
}
/* Now we can set the number of addresses */
lp
->
spy_number
=
wrqu
->
data
.
length
;
return
ret
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get spy list
*/
static
int
wavelan_get_spy
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
struct
sockaddr
*
address
=
(
struct
sockaddr
*
)
extra
;
int
i
;
/* Set the number of addresses */
wrqu
->
data
.
length
=
lp
->
spy_number
;
/* Copy addresses from the lp structure. */
for
(
i
=
0
;
i
<
lp
->
spy_number
;
i
++
)
{
memcpy
(
address
[
i
].
sa_data
,
lp
->
spy_address
[
i
],
WAVELAN_ADDR_SIZE
);
address
[
i
].
sa_family
=
AF_UNIX
;
}
/* Copy stats to the user buffer (just after). */
if
(
lp
->
spy_number
>
0
)
memcpy
(
extra
+
(
sizeof
(
struct
sockaddr
)
*
lp
->
spy_number
),
lp
->
spy_stat
,
sizeof
(
iw_qual
)
*
lp
->
spy_number
);
/* Reset updated flags. */
for
(
i
=
0
;
i
<
lp
->
spy_number
;
i
++
)
lp
->
spy_stat
[
i
].
updated
=
0x0
;
return
(
0
);
}
#endif
/* WIRELESS_SPY */
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set quality threshold
*/
static
int
wavelan_set_qthr
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
ioaddr_t
base
=
dev
->
base_addr
;
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
psa
.
psa_quality_thr
=
*
(
extra
)
&
0x0F
;
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_quality_thr
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_quality_thr
,
1
);
/* update the Wavelan checksum */
update_psa_checksum
(
dev
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_quality_thr
),
psa
.
psa_quality_thr
);
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
0
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static
int
wavelan_get_qthr
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
psa_t
psa
;
unsigned
long
flags
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
psa_read
(
dev
,
(
char
*
)
&
psa
.
psa_quality_thr
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_quality_thr
,
1
);
*
(
extra
)
=
psa
.
psa_quality_thr
&
0x0F
;
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
0
;
}
#ifdef WAVELAN_ROAMING
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set roaming
*/
static
int
wavelan_set_roam
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
unsigned
long
flags
;
/* Disable interrupts and save flags. */
wv_splhi
(
lp
,
&
flags
);
/* Note : should check if user == root */
if
(
do_roaming
&&
(
*
extra
)
==
0
)
wv_roam_cleanup
(
dev
);
else
if
(
do_roaming
==
0
&&
(
*
extra
)
!=
0
)
wv_roam_init
(
dev
);
do_roaming
=
(
*
extra
);
/* Enable interrupts and restore flags. */
wv_splx
(
lp
,
&
flags
);
return
0
;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static
int
wavelan_get_roam
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
*
(
extra
)
=
do_roaming
;
return
0
;
}
#endif
/* WAVELAN_ROAMING */
#ifdef HISTOGRAM
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set histogram
*/
static
int
wavelan_set_histo
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
/* Check the number of intervals. */
if
(
wrqu
->
data
.
length
>
16
)
{
return
(
-
E2BIG
);
}
/* Disable histo while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp
->
his_number
=
0
;
/* Are there ranges to copy? */
if
(
wrqu
->
data
.
length
>
0
)
{
/* Copy interval ranges to the driver */
memcpy
(
lp
->
his_range
,
extra
,
wrqu
->
data
.
length
);
{
int
i
;
printk
(
KERN_DEBUG
"Histo :"
);
for
(
i
=
0
;
i
<
wrqu
->
data
.
length
;
i
++
)
printk
(
" %d"
,
lp
->
his_range
[
i
]);
printk
(
"
\n
"
);
}
/* Reset result structure. */
memset
(
lp
->
his_sum
,
0x00
,
sizeof
(
long
)
*
16
);
}
/* Now we can set the number of ranges */
lp
->
his_number
=
wrqu
->
data
.
length
;
return
(
0
);
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get histogram
*/
static
int
wavelan_get_histo
(
struct
net_device
*
dev
,
struct
iw_request_info
*
info
,
union
iwreq_data
*
wrqu
,
char
*
extra
)
{
net_local
*
lp
=
(
net_local
*
)
dev
->
priv
;
/* lp is not unused */
/* Set the number of intervals. */
wrqu
->
data
.
length
=
lp
->
his_number
;
/* Give back the distribution statistics */
if
(
lp
->
his_number
>
0
)
memcpy
(
extra
,
lp
->
his_sum
,
sizeof
(
long
)
*
lp
->
his_number
);
return
(
0
);
}
#endif
/* HISTOGRAM */
/*------------------------------------------------------------------*/
/*
* Structures to export the Wireless Handlers
*/
static
const
struct
iw_priv_args
wavelan_private_args
[]
=
{
/*{ cmd, set_args, get_args, name } */
{
SIOCSIPQTHR
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"setqualthr"
},
{
SIOCGIPQTHR
,
0
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
"getqualthr"
},
{
SIOCSIPROAM
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"setroam"
},
{
SIOCGIPROAM
,
0
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
"getroam"
},
{
SIOCSIPHISTO
,
IW_PRIV_TYPE_BYTE
|
16
,
0
,
"sethisto"
},
{
SIOCGIPHISTO
,
0
,
IW_PRIV_TYPE_INT
|
16
,
"gethisto"
},
};
#if WIRELESS_EXT > 12
static
const
iw_handler
wavelan_handler
[]
=
{
NULL
,
/* SIOCSIWNAME */
wavelan_get_name
,
/* SIOCGIWNAME */
wavelan_set_nwid
,
/* SIOCSIWNWID */
wavelan_get_nwid
,
/* SIOCGIWNWID */
wavelan_set_freq
,
/* SIOCSIWFREQ */
wavelan_get_freq
,
/* SIOCGIWFREQ */
#ifdef WAVELAN_ROAMING
wavelan_set_mode
,
/* SIOCSIWMODE */
wavelan_get_mode
,
/* SIOCGIWMODE */
#else
/* WAVELAN_ROAMING */
NULL
,
/* SIOCSIWMODE */
NULL
,
/* SIOCGIWMODE */
#endif
/* WAVELAN_ROAMING */
wavelan_set_sens
,
/* SIOCSIWSENS */
wavelan_get_sens
,
/* SIOCGIWSENS */
NULL
,
/* SIOCSIWRANGE */
wavelan_get_range
,
/* SIOCGIWRANGE */
NULL
,
/* SIOCSIWPRIV */
NULL
,
/* SIOCGIWPRIV */
NULL
,
/* SIOCSIWSTATS */
NULL
,
/* SIOCGIWSTATS */
#ifdef WIRELESS_SPY
wavelan_set_spy
,
/* SIOCSIWSPY */
wavelan_get_spy
,
/* SIOCGIWSPY */
#else
/* WIRELESS_SPY */
NULL
,
/* SIOCSIWSPY */
NULL
,
/* SIOCGIWSPY */
#endif
/* WIRELESS_SPY */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
#ifdef WAVELAN_ROAMING_EXT
wavelan_set_wap
,
/* SIOCSIWAP */
wavelan_get_wap
,
/* SIOCGIWAP */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCGIWAPLIST */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
wavelan_set_essid
,
/* SIOCSIWESSID */
wavelan_get_essid
,
/* SIOCGIWESSID */
#else
/* WAVELAN_ROAMING_EXT */
NULL
,
/* SIOCSIWAP */
NULL
,
/* SIOCGIWAP */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCGIWAPLIST */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCSIWESSID */
NULL
,
/* SIOCGIWESSID */
#endif
/* WAVELAN_ROAMING_EXT */
#if WIRELESS_EXT > 8
NULL
,
/* SIOCSIWNICKN */
NULL
,
/* SIOCGIWNICKN */
NULL
,
/* -- hole -- */
NULL
,
/* -- hole -- */
NULL
,
/* SIOCSIWRATE */
NULL
,
/* SIOCGIWRATE */
NULL
,
/* SIOCSIWRTS */
NULL
,
/* SIOCGIWRTS */
NULL
,
/* SIOCSIWFRAG */
NULL
,
/* SIOCGIWFRAG */
NULL
,
/* SIOCSIWTXPOW */
NULL
,
/* SIOCGIWTXPOW */
NULL
,
/* SIOCSIWRETRY */
NULL
,
/* SIOCGIWRETRY */
wavelan_set_encode
,
/* SIOCSIWENCODE */
wavelan_get_encode
,
/* SIOCGIWENCODE */
#endif
/* WIRELESS_EXT > 8 */
};
static
const
iw_handler
wavelan_private_handler
[]
=
{
wavelan_set_qthr
,
/* SIOCIWFIRSTPRIV */
wavelan_get_qthr
,
/* SIOCIWFIRSTPRIV + 1 */
#ifdef WAVELAN_ROAMING
wavelan_set_roam
,
/* SIOCIWFIRSTPRIV + 2 */
wavelan_get_roam
,
/* SIOCIWFIRSTPRIV + 3 */
#else
/* WAVELAN_ROAMING */
NULL
,
/* SIOCIWFIRSTPRIV + 2 */
NULL
,
/* SIOCIWFIRSTPRIV + 3 */
#endif
/* WAVELAN_ROAMING */
#ifdef HISTOGRAM
wavelan_set_histo
,
/* SIOCIWFIRSTPRIV + 4 */
wavelan_get_histo
,
/* SIOCIWFIRSTPRIV + 5 */
#endif
/* HISTOGRAM */
};
static
const
struct
iw_handler_def
wavelan_handler_def
=
{
num_standard:
sizeof
(
wavelan_handler
)
/
sizeof
(
iw_handler
),
num_private:
sizeof
(
wavelan_private_handler
)
/
sizeof
(
iw_handler
),
num_private_args:
sizeof
(
wavelan_private_args
)
/
sizeof
(
struct
iw_priv_args
),
standard:
(
iw_handler
*
)
wavelan_handler
,
private:
(
iw_handler
*
)
wavelan_private_handler
,
private_args:
(
struct
iw_priv_args
*
)
wavelan_private_args
,
};
#else
/* WIRELESS_EXT > 12 */
/*------------------------------------------------------------------*/
/*
* Perform ioctl : config & info stuff
* This is here that are treated the wireless extensions (iwconfig)
*/
static
int
wavelan_ioctl
(
struct
net_device
*
dev
,
/* Device on wich the ioctl apply */
struct
ifreq
*
rq
,
/* Data passed */
int
cmd
)
/* Ioctl number */
{
struct
iwreq
*
wrq
=
(
struct
iwreq
*
)
rq
;
int
ret
=
0
;
#ifdef DEBUG_IOCTL_TRACE
printk
(
KERN_DEBUG
"%s: ->wavelan_ioctl(cmd=0x%X)
\n
"
,
dev
->
name
,
cmd
);
#endif
/* Look what is the request */
switch
(
cmd
)
{
/* --------------- WIRELESS EXTENSIONS --------------- */
case
SIOCGIWNAME
:
wavelan_get_name
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCSIWNWID
:
ret
=
wavelan_set_nwid
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCGIWNWID
:
ret
=
wavelan_get_nwid
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
if
(
psa
.
psa_subband
<=
4
)
{
wrq
->
u
.
freq
.
m
=
fixed_bands
[
psa
.
psa_subband
];
wrq
->
u
.
freq
.
e
=
(
psa
.
psa_subband
!=
0
);
}
else
ret
=
-
EOPNOTSUPP
;
}
case
SIOCSIWFREQ
:
ret
=
wavelan_set_freq
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCGIWFREQ
:
ret
=
wavelan_get_freq
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCSIWSENS
:
/* Set the level threshold */
#if WIRELESS_EXT > 7
/* We should complain loudly if wrq->u.sens.fixed = 0, because we
* can't set auto mode... */
psa
.
psa_thr_pre_set
=
wrq
->
u
.
sens
.
value
&
0x3F
;
#else
/* WIRELESS_EXT > 7 */
psa
.
psa_thr_pre_set
=
wrq
->
u
.
sensitivity
&
0x3F
;
#endif
/* WIRELESS_EXT > 7 */
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_thr_pre_set
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_thr_pre_set
,
1
);
/* update the Wavelan checksum */
update_psa_checksum
(
dev
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_thr_pre_set
),
psa
.
psa_thr_pre_set
);
ret
=
wavelan_set_sens
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCGIWSENS
:
/* Read the level threshold */
psa_read
(
dev
,
(
char
*
)
&
psa
.
psa_thr_pre_set
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_thr_pre_set
,
1
);
#if WIRELESS_EXT > 7
wrq
->
u
.
sens
.
value
=
psa
.
psa_thr_pre_set
&
0x3F
;
wrq
->
u
.
sens
.
fixed
=
1
;
#else
/* WIRELESS_EXT > 7 */
wrq
->
u
.
sensitivity
=
psa
.
psa_thr_pre_set
&
0x3F
;
#endif
/* WIRELESS_EXT > 7 */
ret
=
wavelan_get_sens
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
#if WIRELESS_EXT > 8
case
SIOCSIWENCODE
:
/* Set encryption key */
if
(
!
mmc_encr
(
base
))
{
ret
=
-
EOPNOTSUPP
;
break
;
}
/* Basic checking... */
if
(
wrq
->
u
.
encoding
.
pointer
!=
(
caddr_t
)
0
)
{
/* Check the size of the key */
if
(
wrq
->
u
.
encoding
.
length
!=
8
)
{
char
keybuf
[
8
];
if
(
wrq
->
u
.
encoding
.
pointer
)
{
/* We actually have a key to set */
if
(
wrq
->
u
.
encoding
.
length
!=
8
)
{
ret
=
-
EINVAL
;
break
;
}
/* Copy the key in the driver */
if
(
copy_from_user
(
psa
.
psa_encryption_key
,
wrq
->
u
.
encoding
.
pointer
,
wrq
->
u
.
encoding
.
length
))
{
if
(
copy_from_user
(
keybuf
,
wrq
->
u
.
encoding
.
pointer
,
wrq
->
u
.
encoding
.
length
))
{
ret
=
-
EFAULT
;
break
;
}
psa
.
psa_encryption_select
=
1
;
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_encryption_select
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_encryption_select
,
8
+
1
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_encr_enable
),
MMW_ENCR_ENABLE_EN
|
MMW_ENCR_ENABLE_MODE
);
mmc_write
(
base
,
mmwoff
(
0
,
mmw_encr_key
),
(
unsigned
char
*
)
&
psa
.
psa_encryption_key
,
8
);
}
else
if
(
wrq
->
u
.
encoding
.
length
!=
0
)
{
ret
=
-
EINVAL
;
break
;
}
if
(
wrq
->
u
.
encoding
.
flags
&
IW_ENCODE_DISABLED
)
{
/* disable encryption */
psa
.
psa_encryption_select
=
0
;
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_encryption_select
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_encryption_select
,
1
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_encr_enable
),
0
);
ret
=
wavelan_set_encode
(
dev
,
NULL
,
&
(
wrq
->
u
),
keybuf
);
}
/* update the Wavelan checksum */
update_psa_checksum
(
dev
);
break
;
case
SIOCGIWENCODE
:
/* Read the encryption key */
if
(
!
mmc_encr
(
base
))
{
ret
=
-
EOPNOTSUPP
;
break
;
}
/* only super-user can see encryption key */
if
(
!
capable
(
CAP_NET_ADMIN
))
{
if
(
!
capable
(
CAP_NET_ADMIN
))
{
ret
=
-
EPERM
;
break
;
}
/* Basic checking... */
if
(
wrq
->
u
.
encoding
.
pointer
!=
(
caddr_t
)
0
)
{
psa_read
(
dev
,
(
char
*
)
&
psa
.
psa_encryption_select
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_encryption_select
,
1
+
8
);
/* encryption is enabled ? */
if
(
psa
.
psa_encryption_select
)
wrq
->
u
.
encoding
.
flags
=
IW_ENCODE_ENABLED
;
else
wrq
->
u
.
encoding
.
flags
=
IW_ENCODE_DISABLED
;
wrq
->
u
.
encoding
.
flags
|=
mmc_encr
(
base
);
/* Copy the key to the user buffer */
wrq
->
u
.
encoding
.
length
=
8
;
if
(
copy_to_user
(
wrq
->
u
.
encoding
.
pointer
,
psa
.
psa_encryption_key
,
8
))
char
keybuf
[
8
];
ret
=
wavelan_get_encode
(
dev
,
NULL
,
&
(
wrq
->
u
),
keybuf
);
if
(
wrq
->
u
.
encoding
.
pointer
)
{
if
(
copy_to_user
(
wrq
->
u
.
encoding
.
pointer
,
keybuf
,
wrq
->
u
.
encoding
.
length
))
ret
=
-
EFAULT
;
}
}
break
;
#endif
/* WIRELESS_EXT > 8 */
#ifdef WAVELAN_ROAMING_EXT
#if WIRELESS_EXT > 5
case
SIOCSIWESSID
:
/* Check if disable */
if
(
wrq
->
u
.
data
.
flags
==
0
)
lp
->
filter_domains
=
0
;
else
/* Basic checking... */
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
char
essid
[
IW_ESSID_MAX_SIZE
+
1
];
char
*
endp
;
/* Check the size of the string */
if
(
wrq
->
u
.
data
.
length
>
IW_ESSID_MAX_SIZE
+
1
)
{
char
essidbuf
[
IW_ESSID_MAX_SIZE
+
1
];
if
(
wrq
->
u
.
essid
.
length
>
IW_ESSID_MAX_SIZE
)
{
ret
=
-
E2BIG
;
break
;
}
/* Copy the string in the driver */
if
(
copy_from_user
(
essid
,
wrq
->
u
.
data
.
pointer
,
wrq
->
u
.
data
.
length
))
{
if
(
copy_from_user
(
essidbuf
,
wrq
->
u
.
essid
.
pointer
,
wrq
->
u
.
essid
.
length
))
{
ret
=
-
EFAULT
;
break
;
}
essid
[
IW_ESSID_MAX_SIZE
]
=
'\0'
;
#ifdef DEBUG_IOCTL_INFO
printk
(
KERN_DEBUG
"SetEssid : ``%s''
\n
"
,
essid
);
#endif
/* DEBUG_IOCTL_INFO */
/* Convert to a number (note : Wavelan specific) */
lp
->
domain_id
=
simple_strtoul
(
essid
,
&
endp
,
16
);
/* Has it worked ? */
if
(
endp
>
essid
)
lp
->
filter_domains
=
1
;
else
{
lp
->
filter_domains
=
0
;
ret
=
-
EINVAL
;
}
ret
=
wavelan_set_essid
(
dev
,
NULL
,
&
(
wrq
->
u
),
essidbuf
);
}
break
;
case
SIOCGIWESSID
:
/* Basic checking... */
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
char
essid
[
IW_ESSID_MAX_SIZE
+
1
];
/* Is the domain ID active ? */
wrq
->
u
.
data
.
flags
=
lp
->
filter_domains
;
/* Copy Domain ID into a string (Wavelan specific) */
/* Sound crazy, be we can't have a snprintf in the kernel !!! */
sprintf
(
essid
,
"%lX"
,
lp
->
domain_id
);
essid
[
IW_ESSID_MAX_SIZE
]
=
'\0'
;
/* Set the length */
wrq
->
u
.
data
.
length
=
strlen
(
essid
)
+
1
;
/* Copy structure to the user buffer */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
essid
,
wrq
->
u
.
data
.
length
))
char
essidbuf
[
IW_ESSID_MAX_SIZE
+
1
];
ret
=
wavelan_get_essid
(
dev
,
NULL
,
&
(
wrq
->
u
),
essidbuf
);
if
(
wrq
->
u
.
essid
.
pointer
)
if
(
copy_to_user
(
wrq
->
u
.
essid
.
pointer
,
essidbuf
,
wrq
->
u
.
essid
.
length
)
)
ret
=
-
EFAULT
;
}
break
;
case
SIOCSIWAP
:
#ifdef DEBUG_IOCTL_INFO
printk
(
KERN_DEBUG
"Set AP to : %02X:%02X:%02X:%02X:%02X:%02X
\n
"
,
wrq
->
u
.
ap_addr
.
sa_data
[
0
],
wrq
->
u
.
ap_addr
.
sa_data
[
1
],
wrq
->
u
.
ap_addr
.
sa_data
[
2
],
wrq
->
u
.
ap_addr
.
sa_data
[
3
],
wrq
->
u
.
ap_addr
.
sa_data
[
4
],
wrq
->
u
.
ap_addr
.
sa_data
[
5
]);
#endif
/* DEBUG_IOCTL_INFO */
ret
=
-
EOPNOTSUPP
;
/* Not supported yet */
ret
=
wavelan_set_wap
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCGIWAP
:
/* Should get the real McCoy instead of own Ethernet address */
memcpy
(
wrq
->
u
.
ap_addr
.
sa_data
,
dev
->
dev_addr
,
WAVELAN_ADDR_SIZE
);
wrq
->
u
.
ap_addr
.
sa_family
=
ARPHRD_ETHER
;
ret
=
-
EOPNOTSUPP
;
/* Not supported yet */
ret
=
wavelan_get_wap
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
#endif
/* WIRELESS_EXT > 5 */
#endif
/* WAVELAN_ROAMING_EXT */
...
...
@@ -2216,103 +3034,22 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
#if WIRELESS_EXT > 8
#ifdef WAVELAN_ROAMING
case
SIOCSIWMODE
:
switch
(
wrq
->
u
.
mode
)
{
case
IW_MODE_ADHOC
:
if
(
do_roaming
)
{
wv_roam_cleanup
(
dev
);
do_roaming
=
0
;
}
break
;
case
IW_MODE_INFRA
:
if
(
!
do_roaming
)
{
wv_roam_init
(
dev
);
do_roaming
=
1
;
}
break
;
default:
ret
=
-
EINVAL
;
}
ret
=
wavelan_set_mode
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCGIWMODE
:
if
(
do_roaming
)
wrq
->
u
.
mode
=
IW_MODE_INFRA
;
else
wrq
->
u
.
mode
=
IW_MODE_ADHOC
;
ret
=
wavelan_get_mode
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
#endif
/* WAVELAN_ROAMING */
#endif
/* WIRELESS_EXT > 8 */
case
SIOCGIWRANGE
:
/* Basic checking... */
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
struct
iw_range
range
;
/* Set the length (very important for backward compatibility) */
wrq
->
u
.
data
.
length
=
sizeof
(
struct
iw_range
);
/* Set all the info we don't care or don't know about to zero */
memset
(
&
range
,
0
,
sizeof
(
range
));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range
.
we_version_compiled
=
WIRELESS_EXT
;
range
.
we_version_source
=
9
;
/* Nothing for us in v10 and v11 */
#endif
/* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range
.
throughput
=
1
.
4
*
1000
*
1000
;
/* don't argue on this ! */
range
.
min_nwid
=
0x0000
;
range
.
max_nwid
=
0xFFFF
;
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
if
(
!
(
mmc_in
(
base
,
mmroff
(
0
,
mmr_fee_status
))
&
(
MMR_FEE_STATUS_DWLD
|
MMR_FEE_STATUS_BUSY
)))
{
range
.
num_channels
=
10
;
range
.
num_frequency
=
wv_frequency_list
(
base
,
range
.
freq
,
IW_MAX_FREQUENCIES
);
}
else
range
.
num_channels
=
range
.
num_frequency
=
0
;
range
.
sensitivity
=
0x3F
;
range
.
max_qual
.
qual
=
MMR_SGNL_QUAL
;
range
.
max_qual
.
level
=
MMR_SIGNAL_LVL
;
range
.
max_qual
.
noise
=
MMR_SILENCE_LVL
;
#if WIRELESS_EXT > 11
range
.
avg_qual
.
qual
=
MMR_SGNL_QUAL
;
/* Always max */
/* Need to get better values for those two */
range
.
avg_qual
.
level
=
30
;
range
.
avg_qual
.
noise
=
8
;
#endif
/* WIRELESS_EXT > 11 */
#if WIRELESS_EXT > 7
range
.
num_bitrates
=
1
;
range
.
bitrate
[
0
]
=
2000000
;
/* 2 Mb/s */
#endif
/* WIRELESS_EXT > 7 */
#if WIRELESS_EXT > 8
/* Encryption supported ? */
if
(
mmc_encr
(
base
))
{
range
.
encoding_size
[
0
]
=
8
;
/* DES = 64 bits key */
range
.
num_encoding_sizes
=
1
;
range
.
max_encoding_tokens
=
1
;
/* Only one key possible */
}
else
{
range
.
num_encoding_sizes
=
0
;
range
.
max_encoding_tokens
=
0
;
}
#endif
/* WIRELESS_EXT > 8 */
/* Copy structure to the user buffer */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
&
range
,
ret
=
wavelan_get_range
(
dev
,
NULL
,
&
(
wrq
->
u
),
(
char
*
)
&
range
);
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
&
range
,
sizeof
(
struct
iw_range
)))
ret
=
-
EFAULT
;
}
...
...
@@ -2322,119 +3059,59 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
/* Basic checking... */
if
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
)
{
struct
iw_priv_args
priv
[]
=
{
/* cmd, set_args, get_args, name */
{
SIOCSIPQTHR
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"setqualthr"
},
{
SIOCGIPQTHR
,
0
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
"getqualthr"
},
{
SIOCSIPHISTO
,
IW_PRIV_TYPE_BYTE
|
16
,
0
,
"sethisto"
},
{
SIOCGIPHISTO
,
0
,
IW_PRIV_TYPE_INT
|
16
,
"gethisto"
},
{
SIOCSIPROAM
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
0
,
"setroam"
},
{
SIOCGIPROAM
,
0
,
IW_PRIV_TYPE_BYTE
|
IW_PRIV_SIZE_FIXED
|
1
,
"getroam"
},
};
/* Set the number of ioctl available */
wrq
->
u
.
data
.
length
=
6
;
wrq
->
u
.
data
.
length
=
sizeof
(
wavelan_private_args
)
/
sizeof
(
wavelan_private_args
[
0
])
;
/* Copy structure to the user buffer */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
(
u_char
*
)
priv
,
sizeof
(
priv
)))
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
(
u_char
*
)
wavelan_private_args
,
sizeof
(
wavelan_private_args
)))
ret
=
-
EFAULT
;
}
break
;
#ifdef WIRELESS_SPY
case
SIOCSIWSPY
:
/* Set the spy list */
/* Check the number of addresses */
if
(
wrq
->
u
.
data
.
length
>
IW_MAX_SPY
)
{
struct
sockaddr
address
[
IW_MAX_SPY
];
/* Check the number of addresses */
if
(
wrq
->
u
.
data
.
length
>
IW_MAX_SPY
)
{
ret
=
-
E2BIG
;
break
;
}
lp
->
spy_number
=
wrq
->
u
.
data
.
length
;
/* If there is some addresses to copy */
if
(
lp
->
spy_number
>
0
)
{
struct
sockaddr
address
[
IW_MAX_SPY
];
int
i
;
/* Copy addresses to the driver */
if
(
copy_from_user
(
address
,
wrq
->
u
.
data
.
pointer
,
sizeof
(
struct
sockaddr
)
*
lp
->
spy_number
))
{
/* Get the data in the driver */
if
(
wrq
->
u
.
data
.
pointer
)
{
if
(
copy_from_user
((
char
*
)
address
,
wrq
->
u
.
data
.
pointer
,
sizeof
(
struct
sockaddr
)
*
wrq
->
u
.
data
.
length
))
{
ret
=
-
EFAULT
;
break
;
}
/* Copy addresses to the lp structure */
for
(
i
=
0
;
i
<
lp
->
spy_number
;
i
++
)
{
memcpy
(
lp
->
spy_address
[
i
],
address
[
i
].
sa_data
,
WAVELAN_ADDR_SIZE
);
}
else
if
(
wrq
->
u
.
data
.
length
!=
0
)
{
ret
=
-
EINVAL
;
break
;
}
/* Reset structure... */
memset
(
lp
->
spy_stat
,
0x00
,
sizeof
(
iw_qual
)
*
IW_MAX_SPY
);
#ifdef DEBUG_IOCTL_INFO
printk
(
KERN_DEBUG
"SetSpy - Set of new addresses is :
\n
"
);
for
(
i
=
0
;
i
<
wrq
->
u
.
data
.
length
;
i
++
)
printk
(
KERN_DEBUG
"%02X:%02X:%02X:%02X:%02X:%02X
\n
"
,
lp
->
spy_address
[
i
][
0
],
lp
->
spy_address
[
i
][
1
],
lp
->
spy_address
[
i
][
2
],
lp
->
spy_address
[
i
][
3
],
lp
->
spy_address
[
i
][
4
],
lp
->
spy_address
[
i
][
5
]);
#endif
/* DEBUG_IOCTL_INFO */
ret
=
wavelan_set_spy
(
dev
,
NULL
,
&
(
wrq
->
u
),
(
char
*
)
address
);
}
break
;
case
SIOCGIWSPY
:
/* Get the spy list and spy stats */
/* Set the number of addresses */
wrq
->
u
.
data
.
length
=
lp
->
spy_number
;
/* If the user want to have the addresses back... */
if
((
lp
->
spy_number
>
0
)
&&
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
))
{
struct
sockaddr
address
[
IW_MAX_SPY
];
int
i
;
/* Copy addresses from the lp structure */
for
(
i
=
0
;
i
<
lp
->
spy_number
;
i
++
)
{
memcpy
(
address
[
i
].
sa_data
,
lp
->
spy_address
[
i
],
WAVELAN_ADDR_SIZE
);
address
[
i
].
sa_family
=
ARPHRD_ETHER
;
}
/* Copy addresses to the user buffer */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
address
,
sizeof
(
struct
sockaddr
)
*
lp
->
spy_number
))
{
char
buffer
[
IW_MAX_SPY
*
(
sizeof
(
struct
sockaddr
)
+
sizeof
(
struct
iw_quality
))];
ret
=
wavelan_get_spy
(
dev
,
NULL
,
&
(
wrq
->
u
),
buffer
);
if
(
wrq
->
u
.
data
.
pointer
)
{
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
buffer
,
(
wrq
->
u
.
data
.
length
*
(
sizeof
(
struct
sockaddr
)
+
sizeof
(
struct
iw_quality
)))
))
ret
=
-
EFAULT
;
break
;
}
/* Copy stats to the user buffer (just after) */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
+
(
sizeof
(
struct
sockaddr
)
*
lp
->
spy_number
),
lp
->
spy_stat
,
sizeof
(
iw_qual
)
*
lp
->
spy_number
))
{
ret
=
-
EFAULT
;
break
;
}
/* Reset updated flags */
for
(
i
=
0
;
i
<
lp
->
spy_number
;
i
++
)
lp
->
spy_stat
[
i
].
updated
=
0x0
;
}
/* if(pointer != NULL) */
break
;
#endif
/* WIRELESS_SPY */
...
...
@@ -2446,34 +3123,21 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret
=
-
EPERM
;
break
;
}
psa
.
psa_quality_thr
=
*
(
wrq
->
u
.
name
)
&
0x0F
;
psa_write
(
dev
,
(
char
*
)
&
psa
.
psa_quality_thr
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_quality_thr
,
1
);
/* update the Wavelan checksum */
update_psa_checksum
(
dev
);
mmc_out
(
base
,
mmwoff
(
0
,
mmw_quality_thr
),
psa
.
psa_quality_thr
);
ret
=
wavelan_set_qthr
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCGIPQTHR
:
psa_read
(
dev
,
(
char
*
)
&
psa
.
psa_quality_thr
-
(
char
*
)
&
psa
,
(
unsigned
char
*
)
&
psa
.
psa_quality_thr
,
1
);
*
(
wrq
->
u
.
name
)
=
psa
.
psa_quality_thr
&
0x0F
;
ret
=
wavelan_get_qthr
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
#ifdef WAVELAN_ROAMING
case
SIOCSIPROAM
:
/* Note : should check if user == root */
if
(
do_roaming
&&
(
*
wrq
->
u
.
name
)
==
0
)
wv_roam_cleanup
(
dev
);
else
if
(
do_roaming
==
0
&&
(
*
wrq
->
u
.
name
)
!=
0
)
wv_roam_init
(
dev
);
do_roaming
=
(
*
wrq
->
u
.
name
);
ret
=
wavelan_set_roam
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
);
break
;
case
SIOCGIPROAM
:
*
(
wrq
->
u
.
name
)
=
do_roaming
;
ret
=
wavelan_get_roam
(
dev
,
NULL
,
&
(
wrq
->
u
),
NULL
)
;
break
;
#endif
/* WAVELAN_ROAMING */
...
...
@@ -2484,44 +3148,44 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
{
ret
=
-
EPERM
;
}
{
char
buffer
[
16
];
/* Check the number of intervals */
if
(
wrq
->
u
.
data
.
length
>
16
)
{
ret
=
-
E2BIG
;
break
;
}
lp
->
his_number
=
wrq
->
u
.
data
.
length
;
/* If there is some addresses to copy */
if
(
lp
->
his_number
>
0
)
{
/* Copy interval ranges to the driver */
if
(
copy_from_user
(
lp
->
his_range
,
wrq
->
u
.
data
.
pointer
,
sizeof
(
char
)
*
lp
->
his_number
))
{
/* Get the data in the driver */
if
(
wrq
->
u
.
data
.
pointer
)
{
if
(
copy_from_user
(
buffer
,
wrq
->
u
.
data
.
pointer
,
sizeof
(
struct
sockaddr
)
*
wrq
->
u
.
data
.
length
))
{
ret
=
-
EFAULT
;
break
;
}
/* Reset structure... */
memset
(
lp
->
his_sum
,
0x00
,
sizeof
(
long
)
*
16
);
}
else
if
(
wrq
->
u
.
data
.
length
!=
0
)
{
ret
=
-
EINVAL
;
break
;
}
ret
=
wavelan_set_histo
(
dev
,
NULL
,
&
(
wrq
->
u
),
buffer
);
}
break
;
case
SIOCGIPHISTO
:
/* Set the number of intervals */
wrq
->
u
.
data
.
length
=
lp
->
his_number
;
/* Give back the distribution statistics */
if
((
lp
->
his_number
>
0
)
&&
(
wrq
->
u
.
data
.
pointer
!=
(
caddr_t
)
0
))
{
/* Copy data to the user buffer */
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
lp
->
his_sum
,
sizeof
(
long
)
*
lp
->
his_number
))
long
buffer
[
16
];
ret
=
wavelan_get_histo
(
dev
,
NULL
,
&
(
wrq
->
u
),
(
char
*
)
buffer
);
if
(
wrq
->
u
.
data
.
pointer
)
{
if
(
copy_to_user
(
wrq
->
u
.
data
.
pointer
,
buffer
,
(
wrq
->
u
.
data
.
length
*
sizeof
(
long
))))
ret
=
-
EFAULT
;
}
/* if(pointer != NULL) */
}
}
break
;
#endif
/* HISTOGRAM */
...
...
@@ -2531,14 +3195,12 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret
=
-
EOPNOTSUPP
;
}
/* ReEnable interrupts & restore flags */
wv_splx
(
lp
,
&
flags
);
#ifdef DEBUG_IOCTL_TRACE
printk
(
KERN_DEBUG
"%s: <-wavelan_ioctl()
\n
"
,
dev
->
name
);
#endif
return
ret
;
}
#endif
/* WIRELESS_EXT > 12 */
/*------------------------------------------------------------------*/
/*
...
...
@@ -4530,7 +5192,11 @@ wavelan_attach(void)
dev
->
watchdog_timeo
=
WATCHDOG_JIFFIES
;
#ifdef WIRELESS_EXT
/* If wireless extension exist in the kernel */
#if WIRELESS_EXT > 12
dev
->
wireless_handlers
=
(
struct
iw_handler_def
*
)
&
wavelan_handler_def
;
#else
/* WIRELESS_EXT > 12 */
dev
->
do_ioctl
=
wavelan_ioctl
;
/* wireless extensions */
#endif
/* WIRELESS_EXT > 12 */
dev
->
get_wireless_stats
=
wavelan_get_wireless_stats
;
#endif
...
...
drivers/net/wireless/wavelan_cs.p.h
View file @
a5220ff4
...
...
@@ -394,6 +394,12 @@
* o control first busy loop in wv_82593_cmd()
* o Extend spinlock protection in wv_hw_config()
*
* Changes made for release in 3.1.33 :
* ----------------------------------
* - Optional use new driver API for Wireless Extensions :
* o got rid of wavelan_ioctl()
* o use a bunch of iw_handler instead
*
* Wishes & dreams:
* ----------------
* - Cleanup and integrate the roaming code
...
...
@@ -430,6 +436,9 @@
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h>
/* Wireless extensions */
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif
/* WIRELESS_EXT > 12 */
#endif
/* Pcmcia headers that we need */
...
...
@@ -498,7 +507,7 @@
/************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW
static
const
char
*
version
=
"wavelan_cs.c : v2
3 (SMP + wireless extensions) 20/12/00
\n
"
;
static
const
char
*
version
=
"wavelan_cs.c : v2
4 (SMP + wireless extensions) 11/1/02
\n
"
;
#endif
/* Watchdog temporisation */
...
...
@@ -523,8 +532,8 @@ static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/
#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2
/* Set roaming state */
#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3
/* Get roaming state */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV +
6
/* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV +
7
/* Get histogram values */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV +
4
/* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV +
5
/* Get histogram values */
/*************************** WaveLAN Roaming **************************/
#ifdef WAVELAN_ROAMING
/* Conditional compile, see above in options */
...
...
@@ -589,6 +598,16 @@ typedef struct iw_freq iw_freq;
typedef
struct
net_local
net_local
;
typedef
struct
timer_list
timer_list
;
#if WIRELESS_EXT <= 12
/* Wireless extensions backward compatibility */
/* Part of iw_handler prototype we need */
struct
iw_request_info
{
__u16
cmd
;
/* Wireless Extension command */
__u16
flags
;
/* More to come ;-) */
};
#endif
/* WIRELESS_EXT <= 12 */
/* Basic types */
typedef
u_char
mac_addr
[
WAVELAN_ADDR_SIZE
];
/* Hardware address */
...
...
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