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
nexedi
linux
Commits
f7126cc7
Commit
f7126cc7
authored
Aug 07, 2003
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[netdrvr] add ethtool_ops to struct net_device, and associated infrastructure
Contributed by Matthew Wilcox.
parent
29fa971b
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
789 additions
and
7 deletions
+789
-7
include/linux/ethtool.h
include/linux/ethtool.h
+97
-2
include/linux/netdevice.h
include/linux/netdevice.h
+4
-1
net/core/Makefile
net/core/Makefile
+2
-2
net/core/dev.c
net/core/dev.c
+14
-2
net/core/ethtool.c
net/core/ethtool.c
+672
-0
No files found.
include/linux/ethtool.h
View file @
f7126cc7
...
...
@@ -97,7 +97,7 @@ struct ethtool_coalesce {
u32
rx_max_coalesced_frames
;
/* Same as above two parameters, except that these values
* apply while an IRQ is being service
s
by the host. Not
* apply while an IRQ is being service
d
by the host. Not
* all cards support this feature and the values are ignored
* in that case.
*/
...
...
@@ -119,7 +119,7 @@ struct ethtool_coalesce {
u32
tx_max_coalesced_frames
;
/* Same as above two parameters, except that these values
* apply while an IRQ is being service
s
by the host. Not
* apply while an IRQ is being service
d
by the host. Not
* all cards support this feature and the values are ignored
* in that case.
*/
...
...
@@ -250,6 +250,101 @@ struct ethtool_stats {
u64
data
[
0
];
};
struct
net_device
;
/* Some generic methods drivers may use in their ethtool_ops */
u32
ethtool_op_get_link
(
struct
net_device
*
dev
);
u32
ethtool_op_get_tx_csum
(
struct
net_device
*
dev
);
u32
ethtool_op_get_sg
(
struct
net_device
*
dev
);
int
ethtool_op_set_sg
(
struct
net_device
*
dev
,
u32
data
);
/**
* ðtool_ops - Alter and report network device settings
* get_settings: Get device-specific settings
* set_settings: Set device-specific settings
* get_drvinfo: Report driver information
* get_regs: Get device registers
* get_wol: Report whether Wake-on-Lan is enabled
* set_wol: Turn Wake-on-Lan on or off
* get_msglevel: Report driver message level
* set_msglevel: Set driver message level
* nway_reset: Restart autonegotiation
* get_link: Get link status
* get_eeprom: Read data from the device EEPROM
* set_eeprom: Write data to the device EEPROM
* get_coalesce: Get interrupt coalescing parameters
* set_coalesce: Set interrupt coalescing parameters
* get_ringparam: Report ring sizes
* set_ringparam: Set ring sizes
* get_pauseparam: Report pause parameters
* set_pauseparam: Set pause paramters
* get_rx_csum: Report whether receive checksums are turned on or off
* set_rx_csum: Turn receive checksum on or off
* get_tx_csum: Report whether transmit checksums are turned on or off
* set_tx_csum: Turn transmit checksums on or off
* get_sg: Report whether scatter-gather is enabled
* set_sg: Turn scatter-gather on or off
* self_test: Run specified self-tests
* get_strings: Return a set of strings that describe the requested objects
* phys_id: Identify the device
* get_stats: Return statistics about the device
*
* Description:
*
* get_settings:
* @get_settings is passed an ðtool_cmd to fill in. It returns
* an negative errno or zero.
*
* set_settings:
* @set_settings is passed an ðtool_cmd and should attempt to set
* all the settings this device supports. It may return an error value
* if something goes wrong (otherwise 0).
*
* get_eeprom:
* Should fill in the magic field. Don't need to check len for zero
* or wraparound but must check offset + len < size. Fill in the data
* argument with the eeprom values from offset to offset + len. Update
* len to the amount read. Returns an error or zero.
*
* set_eeprom:
* Should validate the magic field. Don't need to check len for zero
* or wraparound but must check offset + len < size. Update len to
* the amount written. Returns an error or zero.
*/
struct
ethtool_ops
{
int
(
*
get_settings
)(
struct
net_device
*
,
struct
ethtool_cmd
*
);
int
(
*
set_settings
)(
struct
net_device
*
,
struct
ethtool_cmd
*
);
void
(
*
get_drvinfo
)(
struct
net_device
*
,
struct
ethtool_drvinfo
*
);
int
(
*
get_regs_len
)(
struct
net_device
*
);
void
(
*
get_regs
)(
struct
net_device
*
,
struct
ethtool_regs
*
,
void
*
);
void
(
*
get_wol
)(
struct
net_device
*
,
struct
ethtool_wolinfo
*
);
int
(
*
set_wol
)(
struct
net_device
*
,
struct
ethtool_wolinfo
*
);
u32
(
*
get_msglevel
)(
struct
net_device
*
);
void
(
*
set_msglevel
)(
struct
net_device
*
,
u32
);
int
(
*
nway_reset
)(
struct
net_device
*
);
u32
(
*
get_link
)(
struct
net_device
*
);
int
(
*
get_eeprom
)(
struct
net_device
*
,
struct
ethtool_eeprom
*
,
u8
*
);
int
(
*
set_eeprom
)(
struct
net_device
*
,
struct
ethtool_eeprom
*
,
u8
*
);
int
(
*
get_coalesce
)(
struct
net_device
*
,
struct
ethtool_coalesce
*
);
int
(
*
set_coalesce
)(
struct
net_device
*
,
struct
ethtool_coalesce
*
);
void
(
*
get_ringparam
)(
struct
net_device
*
,
struct
ethtool_ringparam
*
);
int
(
*
set_ringparam
)(
struct
net_device
*
,
struct
ethtool_ringparam
*
);
void
(
*
get_pauseparam
)(
struct
net_device
*
,
struct
ethtool_pauseparam
*
);
int
(
*
set_pauseparam
)(
struct
net_device
*
,
struct
ethtool_pauseparam
*
);
u32
(
*
get_rx_csum
)(
struct
net_device
*
);
int
(
*
set_rx_csum
)(
struct
net_device
*
,
u32
);
u32
(
*
get_tx_csum
)(
struct
net_device
*
);
int
(
*
set_tx_csum
)(
struct
net_device
*
,
u32
);
u32
(
*
get_sg
)(
struct
net_device
*
);
int
(
*
set_sg
)(
struct
net_device
*
,
u32
);
int
(
*
self_test_count
)(
struct
net_device
*
);
void
(
*
self_test
)(
struct
net_device
*
,
struct
ethtool_test
*
,
u64
*
);
void
(
*
get_strings
)(
struct
net_device
*
,
u32
stringset
,
u8
*
);
int
(
*
phys_id
)(
struct
net_device
*
,
u32
);
int
(
*
get_stats_count
)(
struct
net_device
*
);
void
(
*
get_ethtool_stats
)(
struct
net_device
*
,
struct
ethtool_stats
*
,
u64
*
);
};
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001
/* Get settings. */
#define ETHTOOL_SSET 0x00000002
/* Set settings. */
...
...
include/linux/netdevice.h
View file @
f7126cc7
...
...
@@ -43,6 +43,7 @@
struct
divert_blk
;
struct
vlan_group
;
struct
ethtool_ops
;
#define HAVE_ALLOC_NETDEV
/* feature macro: alloc_xxxdev
functions are available. */
...
...
@@ -300,6 +301,8 @@ struct net_device
* See <net/iw_handler.h> for details. Jean II */
struct
iw_handler_def
*
wireless_handlers
;
struct
ethtool_ops
*
ethtool_ops
;
/*
* This marks the end of the "visible" part of the structure. All
* fields hereafter are internal to the system, and may change at
...
...
@@ -485,7 +488,6 @@ struct packet_type
struct
list_head
list
;
};
#include <linux/interrupt.h>
#include <linux/notifier.h>
...
...
@@ -633,6 +635,7 @@ extern int netif_rx(struct sk_buff *skb);
#define HAVE_NETIF_RECEIVE_SKB 1
extern
int
netif_receive_skb
(
struct
sk_buff
*
skb
);
extern
int
dev_ioctl
(
unsigned
int
cmd
,
void
*
);
extern
int
dev_ethtool
(
struct
ifreq
*
);
extern
unsigned
dev_get_flags
(
const
struct
net_device
*
);
extern
int
dev_change_flags
(
struct
net_device
*
,
unsigned
);
extern
int
dev_set_mtu
(
struct
net_device
*
,
int
);
...
...
net/core/Makefile
View file @
f7126cc7
...
...
@@ -6,8 +6,8 @@ obj-y := sock.o skbuff.o iovec.o datagram.o scm.o
obj-$(CONFIG_SYSCTL)
+=
sysctl_net_core.o
obj-y
+=
flow.o dev.o
net-sysfs.o dev_mcast.o dst.o neighbour
.o
\
rtnetlink.o utils.o link_watch.o filter.o
obj-y
+=
flow.o dev.o
ethtool.o net-sysfs.o dev_mcast.o dst
.o
\
neighbour.o
rtnetlink.o utils.o link_watch.o filter.o
obj-$(CONFIG_NETFILTER)
+=
netfilter.o
obj-$(CONFIG_NET_DIVERT)
+=
dv.o
...
...
net/core/dev.c
View file @
f7126cc7
...
...
@@ -2365,7 +2365,6 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
cmd
==
SIOCBONDSLAVEINFOQUERY
||
cmd
==
SIOCBONDINFOQUERY
||
cmd
==
SIOCBONDCHANGEACTIVE
||
cmd
==
SIOCETHTOOL
||
cmd
==
SIOCGMIIPHY
||
cmd
==
SIOCGMIIREG
||
cmd
==
SIOCSMIIREG
||
...
...
@@ -2462,13 +2461,26 @@ int dev_ioctl(unsigned int cmd, void *arg)
}
return
ret
;
case
SIOCETHTOOL
:
dev_load
(
ifr
.
ifr_name
);
rtnl_lock
();
ret
=
dev_ethtool
(
&
ifr
);
rtnl_unlock
();
if
(
!
ret
)
{
if
(
colon
)
*
colon
=
':'
;
if
(
copy_to_user
(
arg
,
&
ifr
,
sizeof
(
struct
ifreq
)))
ret
=
-
EFAULT
;
}
return
ret
;
/*
* These ioctl calls:
* - require superuser power.
* - require strict serialization.
* - return a value
*/
case
SIOCETHTOOL
:
case
SIOCGMIIPHY
:
case
SIOCGMIIREG
:
if
(
!
capable
(
CAP_NET_ADMIN
))
...
...
net/core/ethtool.c
0 → 100644
View file @
f7126cc7
/*
* net/core/ethtool.c - Ethtool ioctl handler
* Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
*
* This file is where we call all the ethtool_ops commands to get
* the information ethtool needs. We fall back to calling do_ioctl()
* for drivers which haven't been converted to ethtool_ops yet.
*
* It's GPL, stupid.
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
/*
* Some useful ethtool_ops methods that're device independent.
* If we find that all drivers want to do the same thing here,
* we can turn these into dev_() function calls.
*/
u32
ethtool_op_get_link
(
struct
net_device
*
dev
)
{
return
netif_carrier_ok
(
dev
)
?
1
:
0
;
}
u32
ethtool_op_get_tx_csum
(
struct
net_device
*
dev
)
{
return
(
dev
->
features
&
NETIF_F_IP_CSUM
)
!=
0
;
}
u32
ethtool_op_get_sg
(
struct
net_device
*
dev
)
{
return
(
dev
->
features
&
NETIF_F_SG
)
!=
0
;
}
int
ethtool_op_set_sg
(
struct
net_device
*
dev
,
u32
data
)
{
if
(
data
)
dev
->
features
|=
NETIF_F_SG
;
else
dev
->
features
&=
~
NETIF_F_SG
;
return
0
;
}
/* Handlers for each ethtool command */
static
int
ethtool_get_settings
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_cmd
cmd
=
{
ETHTOOL_GSET
};
int
err
;
if
(
!
dev
->
ethtool_ops
->
get_settings
)
return
-
EOPNOTSUPP
;
err
=
dev
->
ethtool_ops
->
get_settings
(
dev
,
&
cmd
);
if
(
err
<
0
)
return
err
;
if
(
copy_to_user
(
useraddr
,
&
cmd
,
sizeof
(
cmd
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_settings
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_cmd
cmd
;
if
(
!
dev
->
ethtool_ops
->
set_settings
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
cmd
,
useraddr
,
sizeof
(
cmd
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_settings
(
dev
,
&
cmd
);
}
static
int
ethtool_get_drvinfo
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_drvinfo
info
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
if
(
!
ops
->
get_drvinfo
)
return
-
EOPNOTSUPP
;
memset
(
&
info
,
0
,
sizeof
(
info
));
info
.
cmd
=
ETHTOOL_GDRVINFO
;
ops
->
get_drvinfo
(
dev
,
&
info
);
if
(
ops
->
self_test_count
)
info
.
testinfo_len
=
ops
->
self_test_count
(
dev
);
if
(
ops
->
get_stats_count
)
info
.
n_stats
=
ops
->
get_stats_count
(
dev
);
if
(
ops
->
get_regs_len
)
info
.
regdump_len
=
ops
->
get_regs_len
(
dev
);
/* XXX: eeprom? */
if
(
copy_to_user
(
useraddr
,
&
info
,
sizeof
(
info
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_get_regs
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_regs
regs
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
void
*
regbuf
;
int
reglen
,
ret
;
if
(
!
ops
->
get_regs
||
!
ops
->
get_regs_len
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
regs
,
useraddr
,
sizeof
(
regs
)))
return
-
EFAULT
;
reglen
=
ops
->
get_regs_len
(
dev
);
if
(
regs
.
len
>
reglen
)
regs
.
len
=
reglen
;
regbuf
=
kmalloc
(
reglen
,
GFP_USER
);
if
(
!
regbuf
)
return
-
ENOMEM
;
ops
->
get_regs
(
dev
,
&
regs
,
regbuf
);
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
regs
,
sizeof
(
regs
)))
goto
out
;
useraddr
+=
offsetof
(
struct
ethtool_regs
,
data
);
if
(
copy_to_user
(
useraddr
,
regbuf
,
reglen
))
goto
out
;
ret
=
0
;
out:
kfree
(
regbuf
);
return
ret
;
}
static
int
ethtool_get_wol
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_wolinfo
wol
=
{
ETHTOOL_GWOL
};
if
(
!
dev
->
ethtool_ops
->
get_wol
)
return
-
EOPNOTSUPP
;
dev
->
ethtool_ops
->
get_wol
(
dev
,
&
wol
);
if
(
copy_to_user
(
useraddr
,
&
wol
,
sizeof
(
wol
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_wol
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_wolinfo
wol
;
if
(
!
dev
->
ethtool_ops
->
set_wol
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
wol
,
useraddr
,
sizeof
(
wol
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_wol
(
dev
,
&
wol
);
}
static
int
ethtool_get_msglevel
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GMSGLVL
};
if
(
!
dev
->
ethtool_ops
->
get_msglevel
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_msglevel
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_msglevel
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
;
if
(
!
dev
->
ethtool_ops
->
set_msglevel
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
dev
->
ethtool_ops
->
set_msglevel
(
dev
,
edata
.
data
);
return
0
;
}
static
int
ethtool_nway_reset
(
struct
net_device
*
dev
)
{
if
(
!
dev
->
ethtool_ops
->
nway_reset
)
return
-
EOPNOTSUPP
;
return
dev
->
ethtool_ops
->
nway_reset
(
dev
);
}
static
int
ethtool_get_link
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GLINK
};
if
(
!
dev
->
ethtool_ops
->
get_link
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_link
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_get_eeprom
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_eeprom
eeprom
;
u8
*
data
;
int
len
,
ret
;
if
(
!
dev
->
ethtool_ops
->
get_eeprom
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
eeprom
,
useraddr
,
sizeof
(
eeprom
)))
return
-
EFAULT
;
len
=
eeprom
.
len
;
/* Check for wrap and zero */
if
(
eeprom
.
offset
+
len
<=
eeprom
.
offset
)
return
-
EINVAL
;
data
=
kmalloc
(
len
,
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
if
(
copy_from_user
(
data
,
useraddr
+
sizeof
(
eeprom
),
len
))
return
-
EFAULT
;
ret
=
dev
->
ethtool_ops
->
get_eeprom
(
dev
,
&
eeprom
,
data
);
if
(
!
ret
)
goto
out
;
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
eeprom
,
sizeof
(
eeprom
)))
goto
out
;
if
(
copy_to_user
(
useraddr
+
sizeof
(
eeprom
),
data
,
eeprom
.
len
))
goto
out
;
ret
=
0
;
out:
kfree
(
data
);
return
ret
;
}
static
int
ethtool_set_eeprom
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_eeprom
eeprom
;
u8
*
data
;
int
len
,
ret
;
if
(
!
dev
->
ethtool_ops
->
set_eeprom
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
eeprom
,
useraddr
,
sizeof
(
eeprom
)))
return
-
EFAULT
;
len
=
eeprom
.
len
;
/* Check for wrap and zero */
if
(
eeprom
.
offset
+
len
<=
eeprom
.
offset
)
return
-
EINVAL
;
data
=
kmalloc
(
len
,
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
if
(
copy_from_user
(
data
,
useraddr
+
sizeof
(
eeprom
),
len
))
return
-
EFAULT
;
ret
=
dev
->
ethtool_ops
->
set_eeprom
(
dev
,
&
eeprom
,
data
);
if
(
ret
)
goto
out
;
if
(
copy_to_user
(
useraddr
+
sizeof
(
eeprom
),
data
,
len
))
ret
=
-
EFAULT
;
out:
kfree
(
data
);
return
ret
;
}
static
int
ethtool_get_coalesce
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_coalesce
coalesce
=
{
ETHTOOL_GCOALESCE
};
if
(
!
dev
->
ethtool_ops
->
get_coalesce
)
return
-
EOPNOTSUPP
;
dev
->
ethtool_ops
->
get_coalesce
(
dev
,
&
coalesce
);
if
(
copy_to_user
(
useraddr
,
&
coalesce
,
sizeof
(
coalesce
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_coalesce
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_coalesce
coalesce
;
if
(
!
dev
->
ethtool_ops
->
get_coalesce
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
coalesce
,
useraddr
,
sizeof
(
coalesce
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_coalesce
(
dev
,
&
coalesce
);
}
static
int
ethtool_get_ringparam
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_ringparam
ringparam
=
{
ETHTOOL_GRINGPARAM
};
if
(
!
dev
->
ethtool_ops
->
get_ringparam
)
return
-
EOPNOTSUPP
;
dev
->
ethtool_ops
->
get_ringparam
(
dev
,
&
ringparam
);
if
(
copy_to_user
(
useraddr
,
&
ringparam
,
sizeof
(
ringparam
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_ringparam
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_ringparam
ringparam
;
if
(
!
dev
->
ethtool_ops
->
get_ringparam
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
ringparam
,
useraddr
,
sizeof
(
ringparam
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_ringparam
(
dev
,
&
ringparam
);
}
static
int
ethtool_get_pauseparam
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_pauseparam
pauseparam
=
{
ETHTOOL_GPAUSEPARAM
};
if
(
!
dev
->
ethtool_ops
->
get_pauseparam
)
return
-
EOPNOTSUPP
;
dev
->
ethtool_ops
->
get_pauseparam
(
dev
,
&
pauseparam
);
if
(
copy_to_user
(
useraddr
,
&
pauseparam
,
sizeof
(
pauseparam
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_pauseparam
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_pauseparam
pauseparam
;
if
(
!
dev
->
ethtool_ops
->
get_pauseparam
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
pauseparam
,
useraddr
,
sizeof
(
pauseparam
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_pauseparam
(
dev
,
&
pauseparam
);
}
static
int
ethtool_get_rx_csum
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GRXCSUM
};
if
(
!
dev
->
ethtool_ops
->
get_rx_csum
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_rx_csum
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_rx_csum
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
;
if
(
!
dev
->
ethtool_ops
->
set_rx_csum
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
dev
->
ethtool_ops
->
set_rx_csum
(
dev
,
edata
.
data
);
return
0
;
}
static
int
ethtool_get_tx_csum
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GTXCSUM
};
if
(
!
dev
->
ethtool_ops
->
get_tx_csum
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_tx_csum
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_tx_csum
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
;
if
(
!
dev
->
ethtool_ops
->
set_tx_csum
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_tx_csum
(
dev
,
edata
.
data
);
}
static
int
ethtool_get_sg
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GSG
};
if
(
!
dev
->
ethtool_ops
->
get_sg
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_sg
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_sg
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
;
if
(
!
dev
->
ethtool_ops
->
set_sg
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_sg
(
dev
,
edata
.
data
);
}
static
int
ethtool_self_test
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_test
test
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
u64
*
data
;
int
ret
;
if
(
!
ops
->
self_test
||
!
ops
->
self_test_count
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
test
,
useraddr
,
sizeof
(
test
)))
return
-
EFAULT
;
test
.
len
=
ops
->
self_test_count
(
dev
);
data
=
kmalloc
(
test
.
len
*
sizeof
(
u64
),
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
ops
->
self_test
(
dev
,
&
test
,
data
);
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
test
,
sizeof
(
test
)))
goto
out
;
useraddr
+=
sizeof
(
test
);
if
(
copy_to_user
(
useraddr
,
data
,
test
.
len
*
sizeof
(
u64
)))
goto
out
;
ret
=
0
;
out:
kfree
(
data
);
return
ret
;
}
static
int
ethtool_get_strings
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_gstrings
gstrings
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
u8
*
data
;
int
ret
;
if
(
!
ops
->
get_strings
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
gstrings
,
useraddr
,
sizeof
(
gstrings
)))
return
-
EFAULT
;
switch
(
gstrings
.
string_set
)
{
case
ETH_SS_TEST
:
if
(
ops
->
self_test_count
)
gstrings
.
len
=
ops
->
self_test_count
(
dev
);
else
return
-
EOPNOTSUPP
;
case
ETH_SS_STATS
:
if
(
ops
->
get_stats_count
)
gstrings
.
len
=
ops
->
get_stats_count
(
dev
);
else
return
-
EOPNOTSUPP
;
default:
return
-
EINVAL
;
}
data
=
kmalloc
(
gstrings
.
len
*
ETH_GSTRING_LEN
,
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
ops
->
get_strings
(
dev
,
gstrings
.
string_set
,
data
);
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
gstrings
,
sizeof
(
gstrings
)))
goto
out
;
useraddr
+=
sizeof
(
gstrings
);
if
(
copy_to_user
(
useraddr
,
data
,
gstrings
.
len
*
ETH_GSTRING_LEN
))
goto
out
;
ret
=
0
;
out:
kfree
(
data
);
return
ret
;
}
static
int
ethtool_phys_id
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_value
id
;
if
(
!
dev
->
ethtool_ops
->
phys_id
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
id
,
useraddr
,
sizeof
(
id
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
phys_id
(
dev
,
id
.
data
);
}
static
int
ethtool_get_stats
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_stats
stats
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
u64
*
data
;
int
ret
;
if
(
!
ops
->
get_ethtool_stats
||
!
ops
->
get_stats_count
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
stats
,
useraddr
,
sizeof
(
stats
)))
return
-
EFAULT
;
stats
.
n_stats
=
ops
->
get_stats_count
(
dev
);
data
=
kmalloc
(
stats
.
n_stats
*
sizeof
(
u64
),
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
ops
->
get_ethtool_stats
(
dev
,
&
stats
,
data
);
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
stats
,
sizeof
(
stats
)))
goto
out
;
useraddr
+=
sizeof
(
stats
);
if
(
copy_to_user
(
useraddr
,
data
,
stats
.
n_stats
*
sizeof
(
u64
)))
goto
out
;
ret
=
0
;
out:
kfree
(
data
);
return
ret
;
}
/* The main entry point in this file. Called from net/core/dev.c */
int
dev_ethtool
(
struct
ifreq
*
ifr
)
{
struct
net_device
*
dev
=
__dev_get_by_name
(
ifr
->
ifr_name
);
void
*
useraddr
=
(
void
*
)
ifr
->
ifr_data
;
u32
ethcmd
;
/*
* XXX: This can be pushed down into the ethtool_* handlers that
* need it. Keep existing behaviour for the moment.
*/
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
!
dev
||
!
netif_device_present
(
dev
))
return
-
ENODEV
;
if
(
!
dev
->
ethtool_ops
)
goto
ioctl
;
if
(
copy_from_user
(
&
ethcmd
,
useraddr
,
sizeof
(
ethcmd
)))
return
-
EFAULT
;
switch
(
ethcmd
)
{
case
ETHTOOL_GSET
:
return
ethtool_get_settings
(
dev
,
useraddr
);
case
ETHTOOL_SSET
:
return
ethtool_set_settings
(
dev
,
useraddr
);
case
ETHTOOL_GDRVINFO
:
return
ethtool_get_drvinfo
(
dev
,
useraddr
);
case
ETHTOOL_GREGS
:
return
ethtool_get_regs
(
dev
,
useraddr
);
case
ETHTOOL_GWOL
:
return
ethtool_get_wol
(
dev
,
useraddr
);
case
ETHTOOL_SWOL
:
return
ethtool_set_wol
(
dev
,
useraddr
);
case
ETHTOOL_GMSGLVL
:
return
ethtool_get_msglevel
(
dev
,
useraddr
);
case
ETHTOOL_SMSGLVL
:
return
ethtool_set_msglevel
(
dev
,
useraddr
);
case
ETHTOOL_NWAY_RST
:
return
ethtool_nway_reset
(
dev
);
case
ETHTOOL_GLINK
:
return
ethtool_get_link
(
dev
,
useraddr
);
case
ETHTOOL_GEEPROM
:
return
ethtool_get_eeprom
(
dev
,
useraddr
);
case
ETHTOOL_SEEPROM
:
return
ethtool_set_eeprom
(
dev
,
useraddr
);
case
ETHTOOL_GCOALESCE
:
return
ethtool_get_coalesce
(
dev
,
useraddr
);
case
ETHTOOL_SCOALESCE
:
return
ethtool_set_coalesce
(
dev
,
useraddr
);
case
ETHTOOL_GRINGPARAM
:
return
ethtool_get_ringparam
(
dev
,
useraddr
);
case
ETHTOOL_SRINGPARAM
:
return
ethtool_set_ringparam
(
dev
,
useraddr
);
case
ETHTOOL_GPAUSEPARAM
:
return
ethtool_get_pauseparam
(
dev
,
useraddr
);
case
ETHTOOL_SPAUSEPARAM
:
return
ethtool_set_pauseparam
(
dev
,
useraddr
);
case
ETHTOOL_GRXCSUM
:
return
ethtool_get_rx_csum
(
dev
,
useraddr
);
case
ETHTOOL_SRXCSUM
:
return
ethtool_set_rx_csum
(
dev
,
useraddr
);
case
ETHTOOL_GTXCSUM
:
return
ethtool_get_tx_csum
(
dev
,
useraddr
);
case
ETHTOOL_STXCSUM
:
return
ethtool_set_tx_csum
(
dev
,
useraddr
);
case
ETHTOOL_GSG
:
return
ethtool_get_sg
(
dev
,
useraddr
);
case
ETHTOOL_SSG
:
return
ethtool_set_sg
(
dev
,
useraddr
);
case
ETHTOOL_TEST
:
return
ethtool_self_test
(
dev
,
useraddr
);
case
ETHTOOL_GSTRINGS
:
return
ethtool_get_strings
(
dev
,
useraddr
);
case
ETHTOOL_PHYS_ID
:
return
ethtool_phys_id
(
dev
,
useraddr
);
case
ETHTOOL_GSTATS
:
return
ethtool_get_stats
(
dev
,
useraddr
);
default:
return
-
EOPNOTSUPP
;
}
ioctl:
if
(
dev
->
do_ioctl
)
return
dev
->
do_ioctl
(
dev
,
ifr
,
SIOCETHTOOL
);
return
-
EOPNOTSUPP
;
}
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