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
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