* Re: [PATCH 1/2 v5] usbnet: allow status interrupt URB to always be active
From: Bjørn Mork @ 2013-04-11 11:08 UTC (permalink / raw)
To: Ming Lei
Cc: Oliver Neukum, Dan Williams, Elina Pasheva, Network Development,
linux-usb, Rory Filer, Phil Sutter
In-Reply-To: <CACVXFVO+QZ+mtdOFuNuh+8HQOMcuQrKJRAaW9ohyrMCMeZXsjQ@mail.gmail.com>
Ming Lei <tom.leiming@gmail.com> writes:
> OK, I say it again, GFP_KERNEL is enough to cover all cases, and the
> mem_flags parameter is redundant.
The docs for usb_submit_urb() in drivers/usb/core/urb.c lists some
possible mem_flags use cases. Among these are (where (b) and (c) are
cases needing GFP_ATOMIC and not applicable here):
<quote>
* (3) If you use a kernel thread with a network driver you must use
* GFP_NOIO, unless (b) or (c) apply;
</quote>
Is this example
a) wrong, or
b) not applicable, or
c) to be excluded from the new API?
Bjørn
^ permalink raw reply
* Re: [PATCH 1/2 v5] usbnet: allow status interrupt URB to always be active
From: Oliver Neukum @ 2013-04-11 11:14 UTC (permalink / raw)
To: Ming Lei
Cc: Dan Williams, Elina Pasheva, Network Development, linux-usb,
Rory Filer, Phil Sutter
In-Reply-To: <CACVXFVNHoBNpyRztp1Bu_41=YnszqQ3jQDw4j87Zd2hZM3r-VA@mail.gmail.com>
On Thursday 11 April 2013 18:03:09 Ming Lei wrote:
> On Thu, Apr 11, 2013 at 5:53 PM, Oliver Neukum <oliver@neukum.org> wrote:
> > On Thursday 11 April 2013 16:09:16 Ming Lei wrote:
> >>
> >> Could you explain why work queue need GFP_NOIO?
> >
> > Your fix for the memory allocation depends on it happening in the same
> > context. If you execute code on a work queue this happens in the context
> > of a kernel thread.
>
> I understand the interface might be called from workqueue, and my question
> is why GFP_NOIO is needed in the work queue context. Generally speaking,
> GFP_KERNEL is enough for work queue context.
>
> As we discussed before, GFP_NOIO is required in runtime resume context
> and reset context, and the two contexts have been addressed automatically.
> So looks you didn't answer my question, :-)
Sorry, I misunderstood.
Task A Task B queue
queue work
request a reset
allocate memory and block
cancel the work
shit happened
Regards
Oliver
^ permalink raw reply
* [PATCH] tcp: Reallocate headroom if it would overflow csum_start
From: Thomas Graf @ 2013-04-11 11:19 UTC (permalink / raw)
To: davem; +Cc: netdev, eric.dumazet
If a TCP retransmission gets partially ACKed and collapsed multiple
times it is possible for the headroom to grow beyond 64K which will
overflow the 16bit skb->csum_start which is based on the start of
the headroom. It has been observed rarely in the wild with IPoIB due
to the 64K MTU.
Verify if the acking and collapsing resulted in a headroom exceeding
what csum_start can cover and reallocate the headroom if so.
LLNL has been running the patch for a while and has not seen the
problem occur since.
A big thank you to Jim Foraker <foraker1@llnl.gov> and the team at
LLNL for helping out with the investigation and testing.
Reported-by: Jim Foraker <foraker1@llnl.gov>
Signed-off-by: Thomas Graf <tgraf@suug.ch>
---
v2: reallocate headroom instead of preventing further collapsing
net/ipv4/tcp_output.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index b44cf81..bf6ceb7 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2388,8 +2388,11 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
*/
TCP_SKB_CB(skb)->when = tcp_time_stamp;
- /* make sure skb->data is aligned on arches that require it */
- if (unlikely(NET_IP_ALIGN && ((unsigned long)skb->data & 3))) {
+ /* make sure skb->data is aligned on arches that require it
+ * and check if ack-trimming & collapsing extended the headroom
+ * beyond what csum_start can cover. */
+ if (unlikely(NET_IP_ALIGN && ((unsigned long)skb->data & 3) ||
+ skb_headroom(skb) >= 0xFFFF)) {
struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
GFP_ATOMIC);
return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH 1/2 v5] usbnet: allow status interrupt URB to always be active
From: Ming Lei @ 2013-04-11 11:42 UTC (permalink / raw)
To: Bjørn Mork
Cc: Oliver Neukum, Dan Williams, Elina Pasheva, Network Development,
linux-usb, Rory Filer, Phil Sutter
In-Reply-To: <87d2u1wci6.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
On Thu, Apr 11, 2013 at 7:08 PM, Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org> wrote:
>
> The docs for usb_submit_urb() in drivers/usb/core/urb.c lists some
> possible mem_flags use cases. Among these are (where (b) and (c) are
> cases needing GFP_ATOMIC and not applicable here):
>
> <quote>
> * (3) If you use a kernel thread with a network driver you must use
> * GFP_NOIO, unless (b) or (c) apply;
> </quote>
>
> Is this example
> a) wrong, or
> b) not applicable, or
> c) to be excluded from the new API?
IMO, it may be a) or b), and we can find many GFP_KERNEL usage
inside usbnet(kevent(), ...).
Also (3) doesn't explain the cause. Oliver, could you give a hit?
Wrt. usbnet, except for in xmit & receive handler, the rule should be
same with other usb driver.
Thanks,
--
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2 v5] usbnet: allow status interrupt URB to always be active
From: Oliver Neukum @ 2013-04-11 11:54 UTC (permalink / raw)
To: Ming Lei
Cc: Bjørn Mork, Dan Williams, Elina Pasheva, Network Development,
linux-usb, Rory Filer, Phil Sutter
In-Reply-To: <CACVXFVO13tG606nDHth5rEA9jexj1iFHnry5ktrMpm_aGGTSvw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Thursday 11 April 2013 19:42:53 Ming Lei wrote:
> On Thu, Apr 11, 2013 at 7:08 PM, Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org> wrote:
> >
> > The docs for usb_submit_urb() in drivers/usb/core/urb.c lists some
> > possible mem_flags use cases. Among these are (where (b) and (c) are
> > cases needing GFP_ATOMIC and not applicable here):
> >
> > <quote>
> > * (3) If you use a kernel thread with a network driver you must use
> > * GFP_NOIO, unless (b) or (c) apply;
> > </quote>
> >
> > Is this example
> > a) wrong, or
> > b) not applicable, or
> > c) to be excluded from the new API?
>
> IMO, it may be a) or b), and we can find many GFP_KERNEL usage
> inside usbnet(kevent(), ...).
Only in the rx path.
> Also (3) doesn't explain the cause. Oliver, could you give a hit?
IIRC this was to cover networked file systems.
Regards
Oliver
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] net: Fix tentative IPv6 address due to DAD looping back
From: Hannes Frederic Sowa @ 2013-04-11 11:55 UTC (permalink / raw)
To: Meng, Jilin
Cc: davem@davemloft.net, kuznet@ms2.inr.ac.ru, jmorris@namei.org,
yoshfuji@linux-ipv6.org, kaber@trash.net, Sun, Yinglin,
Prithviraj, Lakshmanan, netdev@vger.kernel.org
In-Reply-To: <027526AF93736D4380632CD4F3B42B8002FE9D@MX101CL02.corp.emc.com>
On Thu, Apr 11, 2013 at 03:06:23AM +0000, Meng, Jilin wrote:
> we should ignore the looped-back IPv6 DAD packet to avoid configuration failure.
> This occurs when a bonding interface with roundrobin mode is being configured an IPv6 address while the switch side isn't configured bonding/channel yet.
I am very uncomfortable with this change in ndisc layer. I would
prefer DAD kicking in and disabling ipv6 on that interface in such a
situation. The likelihood that an interface with the same mac address
has the same ll ipv6 address is very high and DAD must guard that.
> Signed-off-by: Jilin Meng <jilin.meng@emc.com>
> Signed-off-by: Yinglin Sun <yinglin.sun@emc.com>
> Signed-off-by: Lakshmanan Prithviraj <lakshmanan.prithviraj@emc.com>
> ---
> --- linux/net/ipv6/ndisc.c.orig 2013-03-12 17:16:18.000000000 +0800
> +++ linux/net/ipv6/ndisc.c 2013-04-11 09:00:45.000000000 +0800
> @@ -71,6 +71,7 @@
>
> #include <linux/netfilter.h>
> #include <linux/netfilter_ipv6.h>
> +#include <linux/etherdevice.h>
>
> /* Set to 3 to get tracing... */
> #define ND_DEBUG 1
> @@ -757,6 +758,19 @@ static void ndisc_recv_ns(struct sk_buff
>
> if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
> if (dad) {
> + if (dev->type == ARPHRD_ETHER) {
> + const unsigned char *sadr;
> + sadr = skb_mac_header(skb);
> + if (ether_addr_equal_64bits(sadr + 6, dev->dev_addr))
Minor improvment:
struct ethhdr *eth = eth_hdr(skb);
if (ether_addr_equal_64bits(eth->h_source, dev->dev_addr))
^ permalink raw reply
* [PATCH net-next 0/3] Mellanox Ethernet driver updates 2013-04-11
From: Amir Vadai @ 2013-04-11 11:56 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Or Gerlitz, Amir Vadai
Hi Dave,
This series contains updates to mlx4 driver.
First two patches enable SRIOV guests running old mlx4 drivers with B0 steering
only to run over hypervisor with new drivers that is using device managed flow
steering (DMFS).
Third patch is a fix to set corret MTU in SRIOV.
Thanks,
Amir
Eugenia Emantayev (1):
net/mlx4_en: set correct MTU in SRIOV
Hadar Hen Zion (2):
net/mlx4_core: Add helper function to translate B0 steering rules to
DMFS
net/mlx4_core: Translate guest B0 steering rules to DMFS
drivers/net/ethernet/mellanox/mlx4/mcg.c | 51 +++++++-----
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 4 +
drivers/net/ethernet/mellanox/mlx4/port.c | 4 +-
.../net/ethernet/mellanox/mlx4/resource_tracker.c | 85 +++++++++++++++-----
4 files changed, 99 insertions(+), 45 deletions(-)
--
1.7.8.2
^ permalink raw reply
* [PATCH net-next 2/3] net/mlx4_core: Translate guest B0 steering rules to DMFS
From: Amir Vadai @ 2013-04-11 11:56 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Or Gerlitz, Amir Vadai, Hadar Hen Zion
In-Reply-To: <1365681402-19445-1-git-send-email-amirv@mellanox.com>
From: Hadar Hen Zion <hadarh@mellanox.com>
The different steering modes are global to the device, with DMFS
being introduced after SRIOV was merged. Hence, SRIOV guests running
legacy / older Linux kernels or non-Linux drivers may provide
B0 steering directives when the hypervisor is using DMFS and fail.
Under B0 only L2 steering rules are allowed, hence B0 is a subset of DMFS.
Use this fact to enable such legacy guests to run by modifying the SRIOV
B0 steering wrapper to translate guest B0 directives to DMFS ones when
the device uses DMFS. The translated B0 rule has to be kept in the
resource tracker as a B0 object to allow for lookup in case of detach.
Signed-off-by: Hadar Hen Zion <hadarh@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
---
.../net/ethernet/mellanox/mlx4/resource_tracker.c | 85 +++++++++++++++-----
1 files changed, 63 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 1391b52..f2d6443 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -75,6 +75,7 @@ struct res_gid {
u8 gid[16];
enum mlx4_protocol prot;
enum mlx4_steer_type steer;
+ u64 reg_id;
};
enum res_qp_states {
@@ -2934,7 +2935,7 @@ static struct res_gid *find_gid(struct mlx4_dev *dev, int slave,
static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
u8 *gid, enum mlx4_protocol prot,
- enum mlx4_steer_type steer)
+ enum mlx4_steer_type steer, u64 reg_id)
{
struct res_gid *res;
int err;
@@ -2951,6 +2952,7 @@ static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
memcpy(res->gid, gid, 16);
res->prot = prot;
res->steer = steer;
+ res->reg_id = reg_id;
list_add_tail(&res->list, &rqp->mcg_list);
err = 0;
}
@@ -2961,7 +2963,7 @@ static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
u8 *gid, enum mlx4_protocol prot,
- enum mlx4_steer_type steer)
+ enum mlx4_steer_type steer, u64 *reg_id)
{
struct res_gid *res;
int err;
@@ -2971,6 +2973,7 @@ static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
if (!res || res->prot != prot || res->steer != steer)
err = -EINVAL;
else {
+ *reg_id = res->reg_id;
list_del(&res->list);
kfree(res);
err = 0;
@@ -2980,6 +2983,37 @@ static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
return err;
}
+static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ int block_loopback, enum mlx4_protocol prot,
+ enum mlx4_steer_type type, u64 *reg_id)
+{
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5],
+ block_loopback, prot,
+ reg_id);
+ case MLX4_STEERING_MODE_B0:
+ return mlx4_qp_attach_common(dev, qp, gid,
+ block_loopback, prot, type);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ enum mlx4_protocol prot, enum mlx4_steer_type type,
+ u64 reg_id)
+{
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ return mlx4_flow_detach(dev, reg_id);
+ case MLX4_STEERING_MODE_B0:
+ return mlx4_qp_detach_common(dev, qp, gid, prot, type);
+ default:
+ return -EINVAL;
+ }
+}
+
int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
@@ -2992,14 +3026,12 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
int err;
int qpn;
struct res_qp *rqp;
+ u64 reg_id = 0;
int attach = vhcr->op_modifier;
int block_loopback = vhcr->in_modifier >> 31;
u8 steer_type_mask = 2;
enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1;
- if (dev->caps.steering_mode != MLX4_STEERING_MODE_B0)
- return -EINVAL;
-
qpn = vhcr->in_modifier & 0xffffff;
err = get_res(dev, slave, qpn, RES_QP, &rqp);
if (err)
@@ -3007,30 +3039,32 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
qp.qpn = qpn;
if (attach) {
- err = add_mcg_res(dev, slave, rqp, gid, prot, type);
- if (err)
+ err = qp_attach(dev, &qp, gid, block_loopback, prot,
+ type, ®_id);
+ if (err) {
+ pr_err("Fail to attach rule to qp 0x%x\n", qpn);
goto ex_put;
-
- err = mlx4_qp_attach_common(dev, &qp, gid,
- block_loopback, prot, type);
+ }
+ err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id);
if (err)
- goto ex_rem;
+ goto ex_detach;
} else {
- err = rem_mcg_res(dev, slave, rqp, gid, prot, type);
+ err = rem_mcg_res(dev, slave, rqp, gid, prot, type, ®_id);
if (err)
goto ex_put;
- err = mlx4_qp_detach_common(dev, &qp, gid, prot, type);
- }
+ err = qp_detach(dev, &qp, gid, prot, type, reg_id);
+ if (err)
+ pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n",
+ qpn, reg_id);
+ }
put_res(dev, slave, qpn, RES_QP);
- return 0;
+ return err;
-ex_rem:
- /* ignore error return below, already in error */
- (void) rem_mcg_res(dev, slave, rqp, gid, prot, type);
+ex_detach:
+ qp_detach(dev, &qp, gid, prot, type, reg_id);
ex_put:
put_res(dev, slave, qpn, RES_QP);
-
return err;
}
@@ -3266,9 +3300,16 @@ static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp)
struct mlx4_qp qp; /* dummy for calling attach/detach */
list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) {
- qp.qpn = rqp->local_qpn;
- (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, rgid->prot,
- rgid->steer);
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ mlx4_flow_detach(dev, rgid->reg_id);
+ break;
+ case MLX4_STEERING_MODE_B0:
+ qp.qpn = rqp->local_qpn;
+ (void) mlx4_qp_detach_common(dev, &qp, rgid->gid,
+ rgid->prot, rgid->steer);
+ break;
+ }
list_del(&rgid->list);
kfree(rgid);
}
--
1.7.8.2
^ permalink raw reply related
* [PATCH net-next 3/3] net/mlx4_en: set correct MTU in SRIOV
From: Amir Vadai @ 2013-04-11 11:56 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Or Gerlitz, Amir Vadai, Eugenia Emantayev,
Eugenia Emantayev, Jack Morgenstein
In-Reply-To: <1365681402-19445-1-git-send-email-amirv@mellanox.com>
From: Eugenia Emantayev <eugenia@mellanox.co.il>
When setting MTU in SRIOV mode add ETH, VLAN and FCS header length
to the maximum MTU obtained from QUERY_DEV_CAP.
Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/port.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 10c57c8..4b6aad3 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -32,6 +32,7 @@
#include <linux/errno.h>
#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
#include <linux/export.h>
#include <linux/mlx4/cmd.h>
@@ -517,7 +518,8 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
/* Mtu is configured as the max MTU among all the
* the functions on the port. */
mtu = be16_to_cpu(gen_context->mtu);
- mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port]);
+ mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
+ ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
prev_mtu = slave_st->mtu[port];
slave_st->mtu[port] = mtu;
if (mtu > master->max_mtu[port])
--
1.7.8.2
^ permalink raw reply related
* Re: [PATCH 1/2 v5] usbnet: allow status interrupt URB to always be active
From: Ming Lei @ 2013-04-11 12:11 UTC (permalink / raw)
To: Oliver Neukum
Cc: Dan Williams, Elina Pasheva, Network Development, linux-usb,
Rory Filer, Phil Sutter
In-Reply-To: <28454387.MvMlbQoOly@linux-5eaq.site>
On Thu, Apr 11, 2013 at 7:14 PM, Oliver Neukum <oliver@neukum.org> wrote:
>
> Sorry, I misunderstood.
No problem, :-)
>
> Task A Task B queue
>
> queue work
> request a reset
> allocate memory and block
> cancel the work
> shit happened
If I understand the case correctly, the above deadlock can be avoided
by canceling rx/tx URBs at the end of pre_reset() or usbnet_disconnect(),
then memory can still be reclaimed in queue context since rx/tx is still
workable. Right?
Thanks,
--
Ming Lei
^ permalink raw reply
* [PATCH net-next 1/3] net/mlx4_core: Add helper function to translate B0 steering rules to DMFS
From: Amir Vadai @ 2013-04-11 11:56 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Or Gerlitz, Amir Vadai, Hadar Hen Zion
In-Reply-To: <1365681402-19445-1-git-send-email-amirv@mellanox.com>
From: Hadar Hen Zion <hadarh@mellanox.com>
A pre-step for supporting guests that use B0 steering over a hypervisor
that runs in DMFS (device managed flow steering mode). Add helper function
which allows to translate L2 attachments / detachments provided in B0 mode
to DMFS rules.
Signed-off-by: Hadar Hen Zion <hadarh@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/mcg.c | 51 ++++++++++++++++------------
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 4 ++
2 files changed, 33 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index 5268552..ffc78d2 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -1125,28 +1125,11 @@ static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
return err;
}
-int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- u8 port, int block_mcast_loopback,
- enum mlx4_protocol prot, u64 *reg_id)
+int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
+ u8 gid[16], u8 port,
+ int block_mcast_loopback,
+ enum mlx4_protocol prot, u64 *reg_id)
{
-
- switch (dev->caps.steering_mode) {
- case MLX4_STEERING_MODE_A0:
- if (prot == MLX4_PROT_ETH)
- return 0;
-
- case MLX4_STEERING_MODE_B0:
- if (prot == MLX4_PROT_ETH)
- gid[7] |= (MLX4_MC_STEER << 1);
-
- if (mlx4_is_mfunc(dev))
- return mlx4_QP_ATTACH(dev, qp, gid, 1,
- block_mcast_loopback, prot);
- return mlx4_qp_attach_common(dev, qp, gid,
- block_mcast_loopback, prot,
- MLX4_MC_STEER);
-
- case MLX4_STEERING_MODE_DEVICE_MANAGED: {
struct mlx4_spec_list spec = { {NULL} };
__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
@@ -1180,8 +1163,32 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
list_add_tail(&spec.list, &rule.list);
return mlx4_flow_attach(dev, &rule, reg_id);
- }
+}
+int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ u8 port, int block_mcast_loopback,
+ enum mlx4_protocol prot, u64 *reg_id)
+{
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_A0:
+ if (prot == MLX4_PROT_ETH)
+ return 0;
+
+ case MLX4_STEERING_MODE_B0:
+ if (prot == MLX4_PROT_ETH)
+ gid[7] |= (MLX4_MC_STEER << 1);
+
+ if (mlx4_is_mfunc(dev))
+ return mlx4_QP_ATTACH(dev, qp, gid, 1,
+ block_mcast_loopback, prot);
+ return mlx4_qp_attach_common(dev, qp, gid,
+ block_mcast_loopback, prot,
+ MLX4_MC_STEER);
+
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
+ block_mcast_loopback,
+ prot, reg_id);
default:
return -EINVAL;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index d738454..252f4ba 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -1190,6 +1190,10 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int block_mcast_loopback, enum mlx4_protocol prot,
enum mlx4_steer_type steer);
+int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
+ u8 gid[16], u8 port,
+ int block_mcast_loopback,
+ enum mlx4_protocol prot, u64 *reg_id);
int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
--
1.7.8.2
^ permalink raw reply related
* Re: [PATCH 1/2 v5] usbnet: allow status interrupt URB to always be active
From: Ming Lei @ 2013-04-11 12:16 UTC (permalink / raw)
To: Oliver Neukum
Cc: Bjørn Mork, Dan Williams, Elina Pasheva, Network Development,
linux-usb, Rory Filer, Phil Sutter
In-Reply-To: <1762413.DH0n5NjUdu@linux-5eaq.site>
On Thu, Apr 11, 2013 at 7:54 PM, Oliver Neukum <oliver@neukum.org> wrote:
>> > Is this example
>> > a) wrong, or
>> > b) not applicable, or
>> > c) to be excluded from the new API?
>>
>> IMO, it may be a) or b), and we can find many GFP_KERNEL usage
>> inside usbnet(kevent(), ...).
>
> Only in the rx path.
So it is b) since usbnet_status_start() can't be in rx path, :-)
>
>> Also (3) doesn't explain the cause. Oliver, could you give a hit?
>
> IIRC this was to cover networked file systems.
Given atomic allocation is used in rx/tx path already, and suppose
no other contexts might block rx/tx path, so is the rule still valid now?
Thanks,
--
Ming Lei
^ permalink raw reply
* Re: [PATCH 1/2 v5] usbnet: allow status interrupt URB to always be active
From: Oliver Neukum @ 2013-04-11 12:28 UTC (permalink / raw)
To: Ming Lei
Cc: Dan Williams, Elina Pasheva, Network Development, linux-usb,
Rory Filer, Phil Sutter
In-Reply-To: <CACVXFVORLr+cRV6uG0-CbYnQ4DKucforyVFcLq+B8Xwz5bVguw@mail.gmail.com>
On Thursday 11 April 2013 20:11:13 Ming Lei wrote:
> On Thu, Apr 11, 2013 at 7:14 PM, Oliver Neukum <oliver@neukum.org> wrote:
> >
> > Sorry, I misunderstood.
>
> No problem, :-)
>
> >
> > Task A Task B queue
> >
> > queue work
> > request a reset
> > allocate memory and block
> > cancel the work
> > shit happened
>
> If I understand the case correctly, the above deadlock can be avoided
> by canceling rx/tx URBs at the end of pre_reset() or usbnet_disconnect(),
No. cancel_work_sync() must wait for the work. The work will not finish.
Regards
Oliver
^ permalink raw reply
* Re: [PATCH 3.8-stable] r8169: fix auto speed down issue
From: Luis Henriques @ 2013-04-11 12:34 UTC (permalink / raw)
To: hayeswang
Cc: 'Jonghwan Choi', 'nic_swsd', stable, netdev,
'David S. Miller', 'Jonghwan Choi'
In-Reply-To: <D9E739B840C44289BF6CAC95EA18ACC2@realtek.com.tw>
On Mon, Apr 08, 2013 at 05:21:23PM +0800, hayeswang wrote:
> From: Jonghwan Choi [mailto:jhbird.choi@gmail.com]
> [...]
> > This patch looks like it should be in the 3.8-stable tree,
> > should we apply it?
>
> Yes.
I'm queuing this patch for the 3.5 kernel as well. Thanks.
Cheers,
--
Luis
^ permalink raw reply
* [PATCH] net: mv643xx_eth: Add GRO support
From: Sebastian Hesselbarth @ 2013-04-11 12:40 UTC (permalink / raw)
To: Sebastian Hesselbarth
Cc: Soeren Moch, David S. Miller, Lennert Buytenhek, Andrew Lunn,
Jason Cooper, Florian Fainelli, Benjamin Herrenschmidt,
Paul Mackerras, Dale Farnsworth, netdev, linux-arm-kernel,
linuxppc-dev, linux-kernel
This patch adds GRO support to mv643xx_eth by making it invoke
napi_gro_receive instead of netif_receive_skb.
Signed-off-by: Soeren Moch <smoch@web.de>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Lennert Buytenhek <buytenh@wantstofly.org>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Florian Fainelli <florian@openwrt.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Dale Farnsworth <dale@farnsworth.org>
Cc: netdev@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-kernel@vger.kernel.org
---
drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 305038f..c850d04 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -604,7 +604,7 @@ static int rxq_process(struct rx_queue *rxq, int budget)
lro_receive_skb(&rxq->lro_mgr, skb, (void *)cmd_sts);
lro_flush_needed = 1;
} else
- netif_receive_skb(skb);
+ napi_gro_receive(&mp->napi, skb);
continue;
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH] tcp: Reallocate headroom if it would overflow csum_start
From: Sergei Shtylyov @ 2013-04-11 12:41 UTC (permalink / raw)
To: Thomas Graf; +Cc: davem, netdev, eric.dumazet
In-Reply-To: <c35c262084e8907098dc2db5ea9690d2119b4916.1365678820.git.tgraf@suug.ch>
Hello.
On 11-04-2013 15:19, Thomas Graf wrote:
> If a TCP retransmission gets partially ACKed and collapsed multiple
> times it is possible for the headroom to grow beyond 64K which will
> overflow the 16bit skb->csum_start which is based on the start of
> the headroom. It has been observed rarely in the wild with IPoIB due
> to the 64K MTU.
> Verify if the acking and collapsing resulted in a headroom exceeding
> what csum_start can cover and reallocate the headroom if so.
> LLNL has been running the patch for a while and has not seen the
> problem occur since.
> A big thank you to Jim Foraker <foraker1@llnl.gov> and the team at
> LLNL for helping out with the investigation and testing.
> Reported-by: Jim Foraker <foraker1@llnl.gov>
> Signed-off-by: Thomas Graf <tgraf@suug.ch>
[...]
Minor formatting nit.
> diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
> index b44cf81..bf6ceb7 100644
> --- a/net/ipv4/tcp_output.c
> +++ b/net/ipv4/tcp_output.c
> @@ -2388,8 +2388,11 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
> */
> TCP_SKB_CB(skb)->when = tcp_time_stamp;
>
> - /* make sure skb->data is aligned on arches that require it */
> - if (unlikely(NET_IP_ALIGN && ((unsigned long)skb->data & 3))) {
> + /* make sure skb->data is aligned on arches that require it
> + * and check if ack-trimming & collapsing extended the headroom
> + * beyond what csum_start can cover. */
The preferred multi-line comment style in the networking code:
/* bla
* bla
*/
WBR, Sergei
^ permalink raw reply
* [PATCH v2 net-next] ptp: dynamic allocation of PHC char devices
From: Jiri Benc @ 2013-04-11 12:48 UTC (permalink / raw)
To: netdev; +Cc: Richard Cochran, Ben Hutchings
As network adapters supporting PTP are becoming more common, machines with
many NICs suddenly have many PHCs, too. The current limit of eight /dev/ptp*
char devices (and thus, 8 network interfaces with PHC) is insufficient. Let
the ptp driver allocate the char devices dynamically.
idr is used for tracking minor numbers allocation; the mapping from index to
pointer is not used, as it is not needed for posix clocks.
Tested with 28 PHCs, removing and re-adding some of them.
Signed-off-by: Jiri Benc <jbenc@redhat.com>
---
v2: Removed dynamic allocation of chunks of minor numbers, the full minor
range is allocated instead.
---
drivers/ptp/ptp_clock.c | 60 +++++++++++++++++++++++++++++-----------------
1 files changed, 38 insertions(+), 22 deletions(-)
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 79f4bce..c8c57bc 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/bitops.h>
+#include <linux/idr.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -32,7 +32,6 @@
#include "ptp_private.h"
#define PTP_MAX_ALARMS 4
-#define PTP_MAX_CLOCKS 8
#define PTP_PPS_DEFAULTS (PPS_CAPTUREASSERT | PPS_OFFSETASSERT)
#define PTP_PPS_EVENT PPS_CAPTUREASSERT
#define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC)
@@ -42,7 +41,7 @@
static dev_t ptp_devt;
static struct class *ptp_class;
-static DECLARE_BITMAP(ptp_clocks_map, PTP_MAX_CLOCKS);
+static struct idr ptp_clocks_map;
static DEFINE_MUTEX(ptp_clocks_mutex); /* protects 'ptp_clocks_map' */
/* time stamp event queue operations */
@@ -166,17 +165,36 @@ static struct posix_clock_operations ptp_clock_ops = {
.read = ptp_read,
};
-static void delete_ptp_clock(struct posix_clock *pc)
+static int ptp_clock_alloc_index(struct ptp_clock *ptp)
{
- struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ int index;
- mutex_destroy(&ptp->tsevq_mux);
+ mutex_lock(&ptp_clocks_mutex);
+ index = idr_alloc(&ptp_clocks_map, ptp, 0, 0, GFP_KERNEL);
+ if (index < 0)
+ goto no_idr;
+ if (index > MINORMASK) {
+ idr_remove(&ptp_clocks_map, index);
+ index = -EBUSY;
+ }
+no_idr:
+ mutex_unlock(&ptp_clocks_mutex);
+ return index;
+}
- /* Remove the clock from the bit map. */
+static void ptp_clock_free_index(int index)
+{
mutex_lock(&ptp_clocks_mutex);
- clear_bit(ptp->index, ptp_clocks_map);
+ idr_remove(&ptp_clocks_map, index);
mutex_unlock(&ptp_clocks_mutex);
+}
+static void delete_ptp_clock(struct posix_clock *pc)
+{
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+
+ mutex_destroy(&ptp->tsevq_mux);
+ ptp_clock_free_index(ptp->index);
kfree(ptp);
}
@@ -191,21 +209,18 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
if (info->n_alarm > PTP_MAX_ALARMS)
return ERR_PTR(-EINVAL);
- /* Find a free clock slot and reserve it. */
- err = -EBUSY;
- mutex_lock(&ptp_clocks_mutex);
- index = find_first_zero_bit(ptp_clocks_map, PTP_MAX_CLOCKS);
- if (index < PTP_MAX_CLOCKS)
- set_bit(index, ptp_clocks_map);
- else
- goto no_slot;
-
/* Initialize a clock structure. */
err = -ENOMEM;
ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
if (ptp == NULL)
goto no_memory;
+ index = ptp_clock_alloc_index(ptp);
+ if (index < 0) {
+ err = index;
+ goto no_slot;
+ }
+
ptp->clock.ops = ptp_clock_ops;
ptp->clock.release = delete_ptp_clock;
ptp->info = info;
@@ -260,11 +275,10 @@ no_sysfs:
device_destroy(ptp_class, ptp->devid);
no_device:
mutex_destroy(&ptp->tsevq_mux);
+ ptp_clock_free_index(index);
+no_slot:
kfree(ptp);
no_memory:
- clear_bit(index, ptp_clocks_map);
-no_slot:
- mutex_unlock(&ptp_clocks_mutex);
return ERR_PTR(err);
}
EXPORT_SYMBOL(ptp_clock_register);
@@ -323,7 +337,8 @@ EXPORT_SYMBOL(ptp_clock_index);
static void __exit ptp_exit(void)
{
class_destroy(ptp_class);
- unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS);
+ unregister_chrdev_region(ptp_devt, MINORMASK + 1);
+ idr_destroy(&ptp_clocks_map);
}
static int __init ptp_init(void)
@@ -336,7 +351,8 @@ static int __init ptp_init(void)
return PTR_ERR(ptp_class);
}
- err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp");
+ idr_init(&ptp_clocks_map);
+ err = alloc_chrdev_region(&ptp_devt, 0, MINORMASK + 1, "ptp");
if (err < 0) {
pr_err("ptp: failed to allocate device region\n");
goto no_region;
--
1.7.6.5
^ permalink raw reply related
* Re: [PATCH 1/2 v5] usbnet: allow status interrupt URB to always be active
From: Ming Lei @ 2013-04-11 12:59 UTC (permalink / raw)
To: Oliver Neukum
Cc: Dan Williams, Elina Pasheva, Network Development, linux-usb,
Rory Filer, Phil Sutter
In-Reply-To: <1735684.e8eeVoUkuq@linux-5eaq.site>
On Thu, Apr 11, 2013 at 8:28 PM, Oliver Neukum <oliver@neukum.org> wrote:
> On Thursday 11 April 2013 20:11:13 Ming Lei wrote:
>> On Thu, Apr 11, 2013 at 7:14 PM, Oliver Neukum <oliver@neukum.org> wrote:
>> >
>> > Sorry, I misunderstood.
>>
>> No problem, :-)
>>
>> >
>> > Task A Task B queue
>> >
>> > queue work
>> > request a reset
>> > allocate memory and block
>> > cancel the work
>> > shit happened
>>
>> If I understand the case correctly, the above deadlock can be avoided
>> by canceling rx/tx URBs at the end of pre_reset() or usbnet_disconnect(),
>
> No. cancel_work_sync() must wait for the work. The work will not finish.
The work will complete when memory is reclaimed, and the rx/tx path is
still working, so memory reclaim can continue and the deadlock may not
be caused, may it?
Thanks,
--
Ming Lei
^ permalink raw reply
* Re: [PATCH] net: mv643xx_eth: Add GRO support
From: Willy Tarreau @ 2013-04-11 13:13 UTC (permalink / raw)
To: Sebastian Hesselbarth
Cc: Andrew Lunn, Jason Cooper, Benjamin Herrenschmidt, linux-kernel,
Florian Fainelli, Soeren Moch, Paul Mackerras, Lennert Buytenhek,
Dale Farnsworth, netdev, linuxppc-dev, David S. Miller,
linux-arm-kernel
In-Reply-To: <1365684023-9967-1-git-send-email-sebastian.hesselbarth@gmail.com>
Hi,
On Thu, Apr 11, 2013 at 02:40:23PM +0200, Sebastian Hesselbarth wrote:
> This patch adds GRO support to mv643xx_eth by making it invoke
> napi_gro_receive instead of netif_receive_skb.
>
> Signed-off-by: Soeren Moch <smoch@web.de>
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Lennert Buytenhek <buytenh@wantstofly.org>
> Cc: Andrew Lunn <andrew@lunn.ch>
> Cc: Jason Cooper <jason@lakedaemon.net>
> Cc: Florian Fainelli <florian@openwrt.org>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Dale Farnsworth <dale@farnsworth.org>
> Cc: netdev@vger.kernel.org
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linuxppc-dev@lists.ozlabs.org
> Cc: linux-kernel@vger.kernel.org
> ---
> drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
> index 305038f..c850d04 100644
> --- a/drivers/net/ethernet/marvell/mv643xx_eth.c
> +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
> @@ -604,7 +604,7 @@ static int rxq_process(struct rx_queue *rxq, int budget)
> lro_receive_skb(&rxq->lro_mgr, skb, (void *)cmd_sts);
> lro_flush_needed = 1;
> } else
> - netif_receive_skb(skb);
> + napi_gro_receive(&mp->napi, skb);
>
> continue;
I remember having experimented with this on 3.6 a few months ago with this
driver and finally switching back to something like this instead which
showed better performance on my tests :
if (skb->ip_summed == CHECKSUM_UNNECESSARY)
napi_gro_receive(napi, skb);
else
netif_receive_skb(skb);
Unfortunately I don't have more details as my commit message was rather
short due to this resulting from experimentation. Did you verify that
you did not lose any performance in various workloads ? I was playing
with bridges at this time, it's possible that I got better performance
on bridging with netif_receive_skb() than with napi_gro_receive().
Regards,
Willy
^ permalink raw reply
* Re: [PATCH net-next] netprio_cgroup: make local table static
From: Neil Horman @ 2013-04-11 13:22 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: David S. Miller, netdev
In-Reply-To: <20130410135605.0431e7aa@nehalam.linuxnetplumber.net>
On Wed, Apr 10, 2013 at 01:56:05PM -0700, Stephen Hemminger wrote:
> Minor sparse warning
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
>
> --- a/net/core/netprio_cgroup.c 2013-04-10 13:36:56.928429191 -0700
> +++ b/net/core/netprio_cgroup.c 2013-04-10 13:37:04.516330753 -0700
> @@ -247,7 +247,7 @@ static struct cftype ss_files[] = {
> { } /* terminate */
> };
>
> -struct cgroup_subsys net_prio_subsys = {
> +static struct cgroup_subsys net_prio_subsys = {
> .name = "net_prio",
> .css_alloc = cgrp_css_alloc,
> .css_online = cgrp_css_online,
>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
^ permalink raw reply
* [PATCH 17/26] hostap: Don't use create_proc_read_entry() [RFC]
From: David Howells @ 2013-04-11 13:29 UTC (permalink / raw)
To: linux-kernel
Cc: devel, Jouni Malinen, Greg Kroah-Hartman, linux-wireless,
John W. Linville, viro, netdev, Johannes Berg
In-Reply-To: <20130411132739.32763.82609.stgit@warthog.procyon.org.uk>
Don't use create_proc_read_entry() as that is deprecated, but rather use
proc_create_data() and seq_file instead.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Jouni Malinen <j@w1.fi>
cc: John W. Linville <linville@tuxdriver.com>
cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
cc: Johannes Berg <johannes@sipsolutions.net>
cc: linux-wireless@vger.kernel.org
cc: netdev@vger.kernel.org
cc: devel@driverdev.osuosl.org
---
drivers/net/wireless/hostap/hostap_ap.c | 375 +++++++++-------
drivers/net/wireless/hostap/hostap_download.c | 68 +++
drivers/net/wireless/hostap/hostap_hw.c | 38 +-
drivers/net/wireless/hostap/hostap_proc.c | 589 ++++++++++++++-----------
drivers/net/wireless/hostap/hostap_wlan.h | 3
drivers/staging/rtl8192e/rtllib_crypt_ccmp.c | 21 -
drivers/staging/rtl8192e/rtllib_crypt_tkip.c | 44 +-
drivers/staging/rtl8192e/rtllib_crypt_wep.c | 6
include/net/lib80211.h | 4
net/wireless/lib80211_crypt_ccmp.c | 29 +
net/wireless/lib80211_crypt_tkip.c | 44 +-
net/wireless/lib80211_crypt_wep.c | 5
12 files changed, 703 insertions(+), 523 deletions(-)
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index dd9a18f..19c45e3 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -17,6 +17,7 @@
*/
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/delay.h>
#include <linux/random.h>
#include <linux/if_arp.h>
@@ -64,28 +65,32 @@ static void prism2_send_mgmt(struct net_device *dev,
#ifndef PRISM2_NO_PROCFS_DEBUG
-static int ap_debug_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct ap_data *ap = (struct ap_data *) data;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast);
- p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast);
- p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ);
- p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets);
- p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack);
- p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds);
- p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs);
- p += sprintf(p, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc);
+static int ap_debug_proc_show(struct seq_file *m, void *v)
+{
+ struct ap_data *ap = m->private;
+
+ seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast);
+ seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast);
+ seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ);
+ seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets);
+ seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack);
+ seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds);
+ seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs);
+ seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc);
+ return 0;
+}
- return (p - page);
+static int ap_debug_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ap_debug_proc_show, PDE_DATA(inode));
}
+
+static const struct file_operations ap_debug_proc_fops = {
+ .open = ap_debug_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
#endif /* PRISM2_NO_PROCFS_DEBUG */
@@ -325,50 +330,81 @@ void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
}
-static int ap_control_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int ap_control_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- struct ap_data *ap = (struct ap_data *) data;
+ struct ap_data *ap = m->private;
char *policy_txt;
struct mac_entry *entry;
- if (off != 0) {
- *eof = 1;
+ if (v == SEQ_START_TOKEN) {
+ switch (ap->mac_restrictions.policy) {
+ case MAC_POLICY_OPEN:
+ policy_txt = "open";
+ break;
+ case MAC_POLICY_ALLOW:
+ policy_txt = "allow";
+ break;
+ case MAC_POLICY_DENY:
+ policy_txt = "deny";
+ break;
+ default:
+ policy_txt = "unknown";
+ break;
+ }
+ seq_printf(m, "MAC policy: %s\n", policy_txt);
+ seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries);
+ seq_puts(m, "MAC list:\n");
return 0;
}
- switch (ap->mac_restrictions.policy) {
- case MAC_POLICY_OPEN:
- policy_txt = "open";
- break;
- case MAC_POLICY_ALLOW:
- policy_txt = "allow";
- break;
- case MAC_POLICY_DENY:
- policy_txt = "deny";
- break;
- default:
- policy_txt = "unknown";
- break;
- }
- p += sprintf(p, "MAC policy: %s\n", policy_txt);
- p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);
- p += sprintf(p, "MAC list:\n");
+ entry = v;
+ seq_printf(m, "%pM\n", entry->addr);
+ return 0;
+}
+
+static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos)
+{
+ struct ap_data *ap = m->private;
spin_lock_bh(&ap->mac_restrictions.lock);
- list_for_each_entry(entry, &ap->mac_restrictions.mac_list, list) {
- if (p - page > PAGE_SIZE - 80) {
- p += sprintf(p, "All entries did not fit one page.\n");
- break;
- }
+ return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos);
+}
- p += sprintf(p, "%pM\n", entry->addr);
- }
+static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos)
+{
+ struct ap_data *ap = m->private;
+ return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos);
+}
+
+static void ap_control_proc_stop(struct seq_file *m, void *v)
+{
+ struct ap_data *ap = m->private;
spin_unlock_bh(&ap->mac_restrictions.lock);
+}
- return (p - page);
+static const struct seq_operations ap_control_proc_seqops = {
+ .start = ap_control_proc_start,
+ .next = ap_control_proc_next,
+ .stop = ap_control_proc_stop,
+ .show = ap_control_proc_show,
+};
+
+static int ap_control_proc_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open(file, &ap_control_proc_seqops);
+ if (ret == 0) {
+ struct seq_file *m = file->private_data;
+ m->private = PDE_DATA(inode);
+ }
+ return ret;
}
+static const struct file_operations ap_control_proc_fops = {
+ .open = ap_control_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
{
@@ -510,61 +546,84 @@ void ap_control_kickall(struct ap_data *ap)
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-#define PROC_LIMIT (PAGE_SIZE - 80)
-
-static int prism2_ap_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int prism2_ap_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- struct ap_data *ap = (struct ap_data *) data;
- struct sta_info *sta;
+ struct sta_info *sta = v;
int i;
- if (off > PROC_LIMIT) {
- *eof = 1;
+ if (v == SEQ_START_TOKEN) {
+ seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
return 0;
}
- p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
- spin_lock_bh(&ap->sta_table_lock);
- list_for_each_entry(sta, &ap->sta_list, list) {
- if (!sta->ap)
- continue;
+ if (!sta->ap)
+ return 0;
- p += sprintf(p, "%pM %d %d %d %d '",
- sta->addr,
- sta->u.ap.channel, sta->last_rx_signal,
- sta->last_rx_silence, sta->last_rx_rate);
- for (i = 0; i < sta->u.ap.ssid_len; i++)
- p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 &&
- sta->u.ap.ssid[i] < 127) ?
- "%c" : "<%02x>"),
- sta->u.ap.ssid[i]);
- p += sprintf(p, "'");
- if (sta->capability & WLAN_CAPABILITY_ESS)
- p += sprintf(p, " [ESS]");
- if (sta->capability & WLAN_CAPABILITY_IBSS)
- p += sprintf(p, " [IBSS]");
- if (sta->capability & WLAN_CAPABILITY_PRIVACY)
- p += sprintf(p, " [WEP]");
- p += sprintf(p, "\n");
-
- if ((p - page) > PROC_LIMIT) {
- printk(KERN_DEBUG "hostap: ap proc did not fit\n");
- break;
- }
- }
- spin_unlock_bh(&ap->sta_table_lock);
+ seq_printf(m, "%pM %d %d %d %d '",
+ sta->addr,
+ sta->u.ap.channel, sta->last_rx_signal,
+ sta->last_rx_silence, sta->last_rx_rate);
- if ((p - page) <= off) {
- *eof = 1;
- return 0;
+ for (i = 0; i < sta->u.ap.ssid_len; i++) {
+ if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127)
+ seq_putc(m, sta->u.ap.ssid[i]);
+ else
+ seq_printf(m, "<%02x>", sta->u.ap.ssid[i]);
}
- *start = page + off;
+ seq_putc(m, '\'');
+ if (sta->capability & WLAN_CAPABILITY_ESS)
+ seq_puts(m, " [ESS]");
+ if (sta->capability & WLAN_CAPABILITY_IBSS)
+ seq_puts(m, " [IBSS]");
+ if (sta->capability & WLAN_CAPABILITY_PRIVACY)
+ seq_puts(m, " [WEP]");
+ seq_putc(m, '\n');
+ return 0;
+}
+
+static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos)
+{
+ struct ap_data *ap = m->private;
+ spin_lock_bh(&ap->sta_table_lock);
+ return seq_list_start_head(&ap->sta_list, *_pos);
+}
- return (p - page - off);
+static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos)
+{
+ struct ap_data *ap = m->private;
+ return seq_list_next(v, &ap->sta_list, _pos);
}
+
+static void prism2_ap_proc_stop(struct seq_file *m, void *v)
+{
+ struct ap_data *ap = m->private;
+ spin_unlock_bh(&ap->sta_table_lock);
+}
+
+static const struct seq_operations prism2_ap_proc_seqops = {
+ .start = prism2_ap_proc_start,
+ .next = prism2_ap_proc_next,
+ .stop = prism2_ap_proc_stop,
+ .show = prism2_ap_proc_show,
+};
+
+static int prism2_ap_proc_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open(file, &prism2_ap_proc_seqops);
+ if (ret == 0) {
+ struct seq_file *m = file->private_data;
+ m->private = PDE_DATA(inode);
+ }
+ return ret;
+}
+
+static const struct file_operations prism2_ap_proc_fops = {
+ .open = prism2_ap_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
@@ -836,15 +895,12 @@ void hostap_init_ap_proc(local_info_t *local)
return;
#ifndef PRISM2_NO_PROCFS_DEBUG
- create_proc_read_entry("ap_debug", 0, ap->proc,
- ap_debug_proc_read, ap);
+ proc_create_data("ap_debug", 0, ap->proc, &ap_debug_proc_fops, ap);
#endif /* PRISM2_NO_PROCFS_DEBUG */
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- create_proc_read_entry("ap_control", 0, ap->proc,
- ap_control_proc_read, ap);
- create_proc_read_entry("ap", 0, ap->proc,
- prism2_ap_proc_read, ap);
+ proc_create_data("ap_control", 0, ap->proc, &ap_control_proc_fops, ap);
+ proc_create_data("ap", 0, ap->proc, &prism2_ap_proc_fops, ap);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
}
@@ -982,79 +1038,86 @@ static void prism2_send_mgmt(struct net_device *dev,
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-static int prism2_sta_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int prism2_sta_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- struct sta_info *sta = (struct sta_info *) data;
+ struct sta_info *sta = m->private;
int i;
/* FIX: possible race condition.. the STA data could have just expired,
* but proc entry was still here so that the read could have started;
* some locking should be done here.. */
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p, "%s=%pM\nusers=%d\naid=%d\n"
- "flags=0x%04x%s%s%s%s%s%s%s\n"
- "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
- sta->ap ? "AP" : "STA",
- sta->addr, atomic_read(&sta->users), sta->aid,
- sta->flags,
- sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
- sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
- sta->flags & WLAN_STA_PS ? " PS" : "",
- sta->flags & WLAN_STA_TIM ? " TIM" : "",
- sta->flags & WLAN_STA_PERM ? " PERM" : "",
- sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "",
- sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "",
- sta->capability, sta->listen_interval);
+ seq_printf(m,
+ "%s=%pM\nusers=%d\naid=%d\n"
+ "flags=0x%04x%s%s%s%s%s%s%s\n"
+ "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
+ sta->ap ? "AP" : "STA",
+ sta->addr, atomic_read(&sta->users), sta->aid,
+ sta->flags,
+ sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
+ sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
+ sta->flags & WLAN_STA_PS ? " PS" : "",
+ sta->flags & WLAN_STA_TIM ? " TIM" : "",
+ sta->flags & WLAN_STA_PERM ? " PERM" : "",
+ sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "",
+ sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "",
+ sta->capability, sta->listen_interval);
/* supported_rates: 500 kbit/s units with msb ignored */
for (i = 0; i < sizeof(sta->supported_rates); i++)
if (sta->supported_rates[i] != 0)
- p += sprintf(p, "%d%sMbps ",
- (sta->supported_rates[i] & 0x7f) / 2,
- sta->supported_rates[i] & 1 ? ".5" : "");
- p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n"
- "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n"
- "tx_packets=%lu\n"
- "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n"
- "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n"
- "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n"
- "tx[11M]=%d\n"
- "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n",
- jiffies, sta->last_auth, sta->last_assoc, sta->last_rx,
- sta->last_tx,
- sta->rx_packets, sta->tx_packets, sta->rx_bytes,
- sta->tx_bytes, skb_queue_len(&sta->tx_buf),
- sta->last_rx_silence,
- sta->last_rx_signal, sta->last_rx_rate / 10,
- sta->last_rx_rate % 10 ? ".5" : "",
- sta->tx_rate, sta->tx_count[0], sta->tx_count[1],
- sta->tx_count[2], sta->tx_count[3], sta->rx_count[0],
- sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);
+ seq_printf(m, "%d%sMbps ",
+ (sta->supported_rates[i] & 0x7f) / 2,
+ sta->supported_rates[i] & 1 ? ".5" : "");
+ seq_printf(m,
+ "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n"
+ "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n"
+ "tx_packets=%lu\n"
+ "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n"
+ "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n"
+ "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n"
+ "tx[11M]=%d\n"
+ "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n",
+ jiffies, sta->last_auth, sta->last_assoc, sta->last_rx,
+ sta->last_tx,
+ sta->rx_packets, sta->tx_packets, sta->rx_bytes,
+ sta->tx_bytes, skb_queue_len(&sta->tx_buf),
+ sta->last_rx_silence,
+ sta->last_rx_signal, sta->last_rx_rate / 10,
+ sta->last_rx_rate % 10 ? ".5" : "",
+ sta->tx_rate, sta->tx_count[0], sta->tx_count[1],
+ sta->tx_count[2], sta->tx_count[3], sta->rx_count[0],
+ sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);
if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats)
- p = sta->crypt->ops->print_stats(p, sta->crypt->priv);
+ sta->crypt->ops->print_stats(m, sta->crypt->priv);
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
if (sta->ap) {
if (sta->u.ap.channel >= 0)
- p += sprintf(p, "channel=%d\n", sta->u.ap.channel);
- p += sprintf(p, "ssid=");
- for (i = 0; i < sta->u.ap.ssid_len; i++)
- p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 &&
- sta->u.ap.ssid[i] < 127) ?
- "%c" : "<%02x>"),
- sta->u.ap.ssid[i]);
- p += sprintf(p, "\n");
+ seq_printf(m, "channel=%d\n", sta->u.ap.channel);
+ seq_puts(m, "ssid=");
+ for (i = 0; i < sta->u.ap.ssid_len; i++) {
+ if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127)
+ seq_putc(m, sta->u.ap.ssid[i]);
+ else
+ seq_printf(m, "<%02x>", sta->u.ap.ssid[i]);
+ }
+ seq_putc(m, '\n');
}
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- return (p - page);
+ return 0;
+}
+
+static int prism2_sta_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, prism2_sta_proc_show, PDE_DATA(inode));
}
+static const struct file_operations prism2_sta_proc_fops = {
+ .open = prism2_sta_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
static void handle_add_proc_queue(struct work_struct *work)
{
@@ -1076,9 +1139,9 @@ static void handle_add_proc_queue(struct work_struct *work)
if (sta) {
sprintf(name, "%pM", sta->addr);
- sta->proc = create_proc_read_entry(
+ sta->proc = proc_create_data(
name, 0, ap->proc,
- prism2_sta_proc_read, sta);
+ &prism2_sta_proc_fops, sta);
atomic_dec(&sta->users);
}
diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c
index e73bf73..705fe66 100644
--- a/drivers/net/wireless/hostap/hostap_download.c
+++ b/drivers/net/wireless/hostap/hostap_download.c
@@ -174,20 +174,70 @@ static int prism2_pda_ok(u8 *buf)
}
-static int prism2_download_aux_dump(struct net_device *dev,
- unsigned int addr, int len, u8 *buf)
-{
- int res;
+#define prism2_download_aux_dump_npages 65536
- prism2_enable_aux_port(dev, 1);
- res = hfa384x_from_aux(dev, addr, len, buf);
- prism2_enable_aux_port(dev, 0);
- if (res)
- return -1;
+struct prism2_download_aux_dump {
+ local_info_t *local;
+ u16 page[0x80];
+};
+
+static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v)
+{
+ struct prism2_download_aux_dump *ctx = m->private;
+ hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page);
+ seq_write(m, ctx->page, 0x80);
return 0;
}
+static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos)
+{
+ struct prism2_download_aux_dump *ctx = m->private;
+ prism2_enable_aux_port(ctx->local->dev, 1);
+ if (*_pos >= prism2_download_aux_dump_npages)
+ return NULL;
+ return (void *)((unsigned long)*_pos + 1);
+}
+
+static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos)
+{
+ ++*_pos;
+ if (*_pos >= prism2_download_aux_dump_npages)
+ return NULL;
+ return (void *)((unsigned long)*_pos + 1);
+}
+
+static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v)
+{
+ struct prism2_download_aux_dump *ctx = m->private;
+ prism2_enable_aux_port(ctx->local->dev, 0);
+}
+
+static const struct seq_operations prism2_download_aux_dump_proc_seqops = {
+ .start = prism2_download_aux_dump_proc_start,
+ .next = prism2_download_aux_dump_proc_next,
+ .stop = prism2_download_aux_dump_proc_stop,
+ .show = prism2_download_aux_dump_proc_show,
+};
+
+static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops,
+ sizeof(struct prism2_download_aux_dump));
+ if (ret == 0) {
+ struct seq_file *m = file->private_data;
+ m->private = PDE_DATA(inode);
+ }
+ return ret;
+}
+
+static const struct file_operations prism2_download_aux_dump_proc_fops = {
+ .open = prism2_download_aux_dump_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
static u8 * prism2_read_pda(struct net_device *dev)
{
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 8e7000f..507ab99 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -38,6 +38,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/if_arp.h>
#include <linux/delay.h>
#include <linux/random.h>
@@ -129,8 +130,7 @@ static void prism2_check_sta_fw_version(local_info_t *local);
#ifdef PRISM2_DOWNLOAD_SUPPORT
/* hostap_download.c */
-static int prism2_download_aux_dump(struct net_device *dev,
- unsigned int addr, int len, u8 *buf);
+static const struct file_operations prism2_download_aux_dump_proc_fops;
static u8 * prism2_read_pda(struct net_device *dev);
static int prism2_download(local_info_t *local,
struct prism2_download_param *param);
@@ -2894,19 +2894,12 @@ static void hostap_tick_timer(unsigned long data)
#ifndef PRISM2_NO_PROCFS_DEBUG
-static int prism2_registers_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int prism2_registers_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- local_info_t *local = (local_info_t *) data;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
+ local_info_t *local = m->private;
#define SHOW_REG(n) \
-p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))
+ seq_printf(m, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))
SHOW_REG(CMD);
SHOW_REG(PARAM0);
@@ -2952,8 +2945,21 @@ p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))
SHOW_REG(PCI_M1_CTL);
#endif /* PRISM2_PCI */
- return (p - page);
+ return 0;
}
+
+static int prism2_registers_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, prism2_registers_proc_show, PDE_DATA(inode));
+}
+
+static const struct file_operations prism2_registers_proc_fops = {
+ .open = prism2_registers_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
#endif /* PRISM2_NO_PROCFS_DEBUG */
@@ -3128,7 +3134,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
local->func->reset_port = prism2_reset_port;
local->func->schedule_reset = prism2_schedule_reset;
#ifdef PRISM2_DOWNLOAD_SUPPORT
- local->func->read_aux = prism2_download_aux_dump;
+ local->func->read_aux_fops = &prism2_download_aux_dump_proc_fops;
local->func->download = prism2_download;
#endif /* PRISM2_DOWNLOAD_SUPPORT */
local->func->tx = prism2_tx_80211;
@@ -3274,8 +3280,8 @@ static int hostap_hw_ready(struct net_device *dev)
}
hostap_init_proc(local);
#ifndef PRISM2_NO_PROCFS_DEBUG
- create_proc_read_entry("registers", 0, local->proc,
- prism2_registers_proc_read, local);
+ proc_create_data("registers", 0, local->proc,
+ &prism2_registers_proc_fops, local);
#endif /* PRISM2_NO_PROCFS_DEBUG */
hostap_init_ap_proc(local);
return 0;
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index dc447c1..89292cf 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -12,259 +12,297 @@
#ifndef PRISM2_NO_PROCFS_DEBUG
-static int prism2_debug_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int prism2_debug_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- local_info_t *local = (local_info_t *) data;
+ local_info_t *local = m->private;
int i;
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p, "next_txfid=%d next_alloc=%d\n",
- local->next_txfid, local->next_alloc);
+ seq_printf(m, "next_txfid=%d next_alloc=%d\n",
+ local->next_txfid, local->next_alloc);
for (i = 0; i < PRISM2_TXFID_COUNT; i++)
- p += sprintf(p, "FID: tx=%04X intransmit=%04X\n",
- local->txfid[i], local->intransmitfid[i]);
- p += sprintf(p, "FW TX rate control: %d\n", local->fw_tx_rate_control);
- p += sprintf(p, "beacon_int=%d\n", local->beacon_int);
- p += sprintf(p, "dtim_period=%d\n", local->dtim_period);
- p += sprintf(p, "wds_max_connections=%d\n",
- local->wds_max_connections);
- p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled);
- p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
+ seq_printf(m, "FID: tx=%04X intransmit=%04X\n",
+ local->txfid[i], local->intransmitfid[i]);
+ seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control);
+ seq_printf(m, "beacon_int=%d\n", local->beacon_int);
+ seq_printf(m, "dtim_period=%d\n", local->dtim_period);
+ seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections);
+ seq_printf(m, "dev_enabled=%d\n", local->dev_enabled);
+ seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
for (i = 0; i < WEP_KEYS; i++) {
if (local->crypt_info.crypt[i] &&
local->crypt_info.crypt[i]->ops) {
- p += sprintf(p, "crypt[%d]=%s\n", i,
- local->crypt_info.crypt[i]->ops->name);
+ seq_printf(m, "crypt[%d]=%s\n", i,
+ local->crypt_info.crypt[i]->ops->name);
}
}
- p += sprintf(p, "pri_only=%d\n", local->pri_only);
- p += sprintf(p, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
- p += sprintf(p, "sram_type=%d\n", local->sram_type);
- p += sprintf(p, "no_pri=%d\n", local->no_pri);
+ seq_printf(m, "pri_only=%d\n", local->pri_only);
+ seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
+ seq_printf(m, "sram_type=%d\n", local->sram_type);
+ seq_printf(m, "no_pri=%d\n", local->no_pri);
+
+ return 0;
+}
- return (p - page);
+static int prism2_debug_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, prism2_debug_proc_show, PDE_DATA(inode));
}
+
+static const struct file_operations prism2_debug_proc_fops = {
+ .open = prism2_debug_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
#endif /* PRISM2_NO_PROCFS_DEBUG */
-static int prism2_stats_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int prism2_stats_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- local_info_t *local = (local_info_t *) data;
+ local_info_t *local = m->private;
struct comm_tallies_sums *sums = &local->comm_tallies;
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
- p += sprintf(p, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
- p += sprintf(p, "TxFragments=%u\n", sums->tx_fragments);
- p += sprintf(p, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
- p += sprintf(p, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
- p += sprintf(p, "TxDeferredTransmissions=%u\n",
- sums->tx_deferred_transmissions);
- p += sprintf(p, "TxSingleRetryFrames=%u\n",
- sums->tx_single_retry_frames);
- p += sprintf(p, "TxMultipleRetryFrames=%u\n",
- sums->tx_multiple_retry_frames);
- p += sprintf(p, "TxRetryLimitExceeded=%u\n",
- sums->tx_retry_limit_exceeded);
- p += sprintf(p, "TxDiscards=%u\n", sums->tx_discards);
- p += sprintf(p, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
- p += sprintf(p, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
- p += sprintf(p, "RxFragments=%u\n", sums->rx_fragments);
- p += sprintf(p, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
- p += sprintf(p, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
- p += sprintf(p, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
- p += sprintf(p, "RxDiscardsNoBuffer=%u\n",
- sums->rx_discards_no_buffer);
- p += sprintf(p, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
- p += sprintf(p, "RxDiscardsWEPUndecryptable=%u\n",
- sums->rx_discards_wep_undecryptable);
- p += sprintf(p, "RxMessageInMsgFragments=%u\n",
- sums->rx_message_in_msg_fragments);
- p += sprintf(p, "RxMessageInBadMsgFragments=%u\n",
- sums->rx_message_in_bad_msg_fragments);
+ seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
+ seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
+ seq_printf(m, "TxFragments=%u\n", sums->tx_fragments);
+ seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
+ seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
+ seq_printf(m, "TxDeferredTransmissions=%u\n",
+ sums->tx_deferred_transmissions);
+ seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames);
+ seq_printf(m, "TxMultipleRetryFrames=%u\n",
+ sums->tx_multiple_retry_frames);
+ seq_printf(m, "TxRetryLimitExceeded=%u\n",
+ sums->tx_retry_limit_exceeded);
+ seq_printf(m, "TxDiscards=%u\n", sums->tx_discards);
+ seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
+ seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
+ seq_printf(m, "RxFragments=%u\n", sums->rx_fragments);
+ seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
+ seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
+ seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
+ seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer);
+ seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
+ seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n",
+ sums->rx_discards_wep_undecryptable);
+ seq_printf(m, "RxMessageInMsgFragments=%u\n",
+ sums->rx_message_in_msg_fragments);
+ seq_printf(m, "RxMessageInBadMsgFragments=%u\n",
+ sums->rx_message_in_bad_msg_fragments);
/* FIX: this may grow too long for one page(?) */
- return (p - page);
+ return 0;
+}
+
+static int prism2_stats_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, prism2_stats_proc_show, PDE_DATA(inode));
}
+static const struct file_operations prism2_stats_proc_fops = {
+ .open = prism2_stats_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
-static int prism2_wds_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int prism2_wds_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- local_info_t *local = (local_info_t *) data;
- struct list_head *ptr;
+ struct list_head *ptr = v;
struct hostap_interface *iface;
- if (off > PROC_LIMIT) {
- *eof = 1;
- return 0;
- }
+ iface = list_entry(ptr, struct hostap_interface, list);
+ if (iface->type == HOSTAP_INTERFACE_WDS)
+ seq_printf(m, "%s\t%pM\n",
+ iface->dev->name, iface->u.wds.remote_addr);
+ return 0;
+}
+static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos)
+{
+ local_info_t *local = m->private;
read_lock_bh(&local->iface_lock);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type != HOSTAP_INTERFACE_WDS)
- continue;
- p += sprintf(p, "%s\t%pM\n",
- iface->dev->name,
- iface->u.wds.remote_addr);
- if ((p - page) > PROC_LIMIT) {
- printk(KERN_DEBUG "%s: wds proc did not fit\n",
- local->dev->name);
- break;
- }
- }
- read_unlock_bh(&local->iface_lock);
+ return seq_list_start(&local->hostap_interfaces, *_pos);
+}
- if ((p - page) <= off) {
- *eof = 1;
- return 0;
- }
+static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos)
+{
+ local_info_t *local = m->private;
+ return seq_list_next(v, &local->hostap_interfaces, _pos);
+}
+
+static void prism2_wds_proc_stop(struct seq_file *m, void *v)
+{
+ local_info_t *local = m->private;
+ read_unlock_bh(&local->iface_lock);
+}
- *start = page + off;
+static const struct seq_operations prism2_wds_proc_seqops = {
+ .start = prism2_wds_proc_start,
+ .next = prism2_wds_proc_next,
+ .stop = prism2_wds_proc_stop,
+ .show = prism2_wds_proc_show,
+};
- return (p - page - off);
+static int prism2_wds_proc_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open(file, &prism2_wds_proc_seqops);
+ if (ret == 0) {
+ struct seq_file *m = file->private_data;
+ m->private = PDE_DATA(inode);
+ }
+ return ret;
}
+static const struct file_operations prism2_wds_proc_fops = {
+ .open = prism2_wds_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
-static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+
+static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- local_info_t *local = (local_info_t *) data;
- struct list_head *ptr;
+ local_info_t *local = m->private;
+ struct list_head *ptr = v;
struct hostap_bss_info *bss;
int i;
- if (off > PROC_LIMIT) {
- *eof = 1;
+ if (ptr == &local->bss_list) {
+ seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
+ "SSID(hex)\tWPA IE\n");
return 0;
}
- p += sprintf(p, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
- "SSID(hex)\tWPA IE\n");
+ bss = list_entry(ptr, struct hostap_bss_info, list);
+ seq_printf(m, "%pM\t%lu\t%u\t0x%x\t",
+ bss->bssid, bss->last_update,
+ bss->count, bss->capab_info);
+
+ for (i = 0; i < bss->ssid_len; i++)
+ seq_putc(m,bss->ssid[i] >= 32 && bss->ssid[i] < 127 ?
+ bss->ssid[i] : '_');
+
+ seq_putc(m, '\t');
+ for (i = 0; i < bss->ssid_len; i++)
+ seq_printf(m, "%02x", bss->ssid[i]);
+ seq_putc(m, '\t');
+ for (i = 0; i < bss->wpa_ie_len; i++)
+ seq_printf(m, "%02x", bss->wpa_ie[i]);
+ seq_putc(m, '\n');
+ return 0;
+}
+
+static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos)
+{
+ local_info_t *local = m->private;
spin_lock_bh(&local->lock);
- list_for_each(ptr, &local->bss_list) {
- bss = list_entry(ptr, struct hostap_bss_info, list);
- p += sprintf(p, "%pM\t%lu\t%u\t0x%x\t",
- bss->bssid, bss->last_update,
- bss->count, bss->capab_info);
- for (i = 0; i < bss->ssid_len; i++) {
- p += sprintf(p, "%c",
- bss->ssid[i] >= 32 && bss->ssid[i] < 127 ?
- bss->ssid[i] : '_');
- }
- p += sprintf(p, "\t");
- for (i = 0; i < bss->ssid_len; i++) {
- p += sprintf(p, "%02x", bss->ssid[i]);
- }
- p += sprintf(p, "\t");
- for (i = 0; i < bss->wpa_ie_len; i++) {
- p += sprintf(p, "%02x", bss->wpa_ie[i]);
- }
- p += sprintf(p, "\n");
- if ((p - page) > PROC_LIMIT) {
- printk(KERN_DEBUG "%s: BSS proc did not fit\n",
- local->dev->name);
- break;
- }
- }
- spin_unlock_bh(&local->lock);
+ return seq_list_start_head(&local->bss_list, *_pos);
+}
- if ((p - page) <= off) {
- *eof = 1;
- return 0;
- }
+static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos)
+{
+ local_info_t *local = m->private;
+ return seq_list_next(v, &local->bss_list, _pos);
+}
+
+static void prism2_bss_list_proc_stop(struct seq_file *m, void *v)
+{
+ local_info_t *local = m->private;
+ spin_unlock_bh(&local->lock);
+}
- *start = page + off;
+static const struct seq_operations prism2_bss_list_proc_seqops = {
+ .start = prism2_bss_list_proc_start,
+ .next = prism2_bss_list_proc_next,
+ .stop = prism2_bss_list_proc_stop,
+ .show = prism2_bss_list_proc_show,
+};
- return (p - page - off);
+static int prism2_bss_list_proc_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open(file, &prism2_bss_list_proc_seqops);
+ if (ret == 0) {
+ struct seq_file *m = file->private_data;
+ m->private = PDE_DATA(inode);
+ }
+ return ret;
}
+static const struct file_operations prism2_bss_list_proc_fops = {
+ .open = prism2_bss_list_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
-static int prism2_crypt_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+
+static int prism2_crypt_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- local_info_t *local = (local_info_t *) data;
+ local_info_t *local = m->private;
int i;
- if (off > PROC_LIMIT) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
+ seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
for (i = 0; i < WEP_KEYS; i++) {
if (local->crypt_info.crypt[i] &&
local->crypt_info.crypt[i]->ops &&
local->crypt_info.crypt[i]->ops->print_stats) {
- p = local->crypt_info.crypt[i]->ops->print_stats(
- p, local->crypt_info.crypt[i]->priv);
+ local->crypt_info.crypt[i]->ops->print_stats(
+ m, local->crypt_info.crypt[i]->priv);
}
}
+ return 0;
+}
- if ((p - page) <= off) {
- *eof = 1;
- return 0;
- }
-
- *start = page + off;
-
- return (p - page - off);
+static int prism2_crypt_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, prism2_crypt_proc_show, PDE_DATA(inode));
}
+static const struct file_operations prism2_crypt_proc_fops = {
+ .open = prism2_crypt_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
-static int prism2_pda_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf,
+ size_t count, loff_t *_pos)
{
- local_info_t *local = (local_info_t *) data;
+ local_info_t *local = PDE_DATA(file_inode(file));
+ size_t off;
- if (local->pda == NULL || off >= PRISM2_PDA_SIZE) {
- *eof = 1;
+ if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE)
return 0;
- }
- if (off + count > PRISM2_PDA_SIZE)
+ off = *_pos;
+ if (count > PRISM2_PDA_SIZE - off)
count = PRISM2_PDA_SIZE - off;
-
- memcpy(page, local->pda + off, count);
+ if (copy_to_user(buf, local->pda + off, count) != 0)
+ return -EFAULT;
+ *_pos += count;
return count;
}
+static const struct file_operations prism2_pda_proc_fops = {
+ .read = prism2_pda_proc_read,
+ .llseek = generic_file_llseek,
+};
-static int prism2_aux_dump_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- local_info_t *local = (local_info_t *) data;
-
- if (local->func->read_aux == NULL) {
- *eof = 1;
- return 0;
- }
-
- if (local->func->read_aux(local->dev, off, count, page)) {
- *eof = 1;
- return 0;
- }
- *start = page;
- return count;
+static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf,
+ size_t bufsize, loff_t *_pos)
+{
+ return 0;
}
+static const struct file_operations prism2_aux_dump_proc_fops = {
+ .read = prism2_aux_dump_proc_no_read,
+};
+
#ifdef PRISM2_IO_DEBUG
static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
@@ -306,82 +344,108 @@ static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
#ifndef PRISM2_NO_STATION_MODES
-static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int prism2_scan_results_proc_show(struct seq_file *m, void *v)
{
- char *p = page;
- local_info_t *local = (local_info_t *) data;
- int entry, i, len, total = 0;
+ local_info_t *local = m->private;
+ unsigned long entry;
+ int i, len;
struct hfa384x_hostscan_result *scanres;
- u8 *pos;
+ u8 *p;
- p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
- "SSID\n");
+ if (v == SEQ_START_TOKEN) {
+ seq_printf(m,
+ "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n");
+ return 0;
+ }
+
+ entry = (unsigned long)v - 2;
+ scanres = &local->last_scan_results[entry];
+
+ seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ",
+ le16_to_cpu(scanres->chid),
+ (s16) le16_to_cpu(scanres->anl),
+ (s16) le16_to_cpu(scanres->sl),
+ le16_to_cpu(scanres->beacon_interval),
+ le16_to_cpu(scanres->capability),
+ le16_to_cpu(scanres->rate),
+ scanres->bssid,
+ le16_to_cpu(scanres->atim));
+
+ p = scanres->sup_rates;
+ for (i = 0; i < sizeof(scanres->sup_rates); i++) {
+ if (p[i] == 0)
+ break;
+ seq_printf(m, "<%02x>", p[i]);
+ }
+ seq_putc(m, ' ');
+
+ p = scanres->ssid;
+ len = le16_to_cpu(scanres->ssid_len);
+ if (len > 32)
+ len = 32;
+ for (i = 0; i < len; i++) {
+ unsigned char c = p[i];
+ if (c >= 32 && c < 127)
+ seq_putc(m, c);
+ else
+ seq_printf(m, "<%02x>", c);
+ }
+ seq_putc(m, '\n');
+ return 0;
+}
+static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos)
+{
+ local_info_t *local = m->private;
spin_lock_bh(&local->lock);
- for (entry = 0; entry < local->last_scan_results_count; entry++) {
- scanres = &local->last_scan_results[entry];
- if (total + (p - page) <= off) {
- total += p - page;
- p = page;
- }
- if (total + (p - page) > off + count)
- break;
- if ((p - page) > (PAGE_SIZE - 200))
- break;
+ /* We have a header (pos 0) + N results to show (pos 1...N) */
+ if (*_pos > local->last_scan_results_count)
+ return NULL;
+ return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
+}
- p += sprintf(p, "%d %d %d %d 0x%02x %d %pM %d ",
- le16_to_cpu(scanres->chid),
- (s16) le16_to_cpu(scanres->anl),
- (s16) le16_to_cpu(scanres->sl),
- le16_to_cpu(scanres->beacon_interval),
- le16_to_cpu(scanres->capability),
- le16_to_cpu(scanres->rate),
- scanres->bssid,
- le16_to_cpu(scanres->atim));
-
- pos = scanres->sup_rates;
- for (i = 0; i < sizeof(scanres->sup_rates); i++) {
- if (pos[i] == 0)
- break;
- p += sprintf(p, "<%02x>", pos[i]);
- }
- p += sprintf(p, " ");
-
- pos = scanres->ssid;
- len = le16_to_cpu(scanres->ssid_len);
- if (len > 32)
- len = 32;
- for (i = 0; i < len; i++) {
- unsigned char c = pos[i];
- if (c >= 32 && c < 127)
- p += sprintf(p, "%c", c);
- else
- p += sprintf(p, "<%02x>", c);
- }
- p += sprintf(p, "\n");
- }
+static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos)
+{
+ local_info_t *local = m->private;
+
+ ++*_pos;
+ if (*_pos > local->last_scan_results_count)
+ return NULL;
+ return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
+}
+
+static void prism2_scan_results_proc_stop(struct seq_file *m, void *v)
+{
+ local_info_t *local = m->private;
spin_unlock_bh(&local->lock);
+}
- total += (p - page);
- if (total >= off + count)
- *eof = 1;
+static const struct seq_operations prism2_scan_results_proc_seqops = {
+ .start = prism2_scan_results_proc_start,
+ .next = prism2_scan_results_proc_next,
+ .stop = prism2_scan_results_proc_stop,
+ .show = prism2_scan_results_proc_show,
+};
- if (total < off) {
- *eof = 1;
- return 0;
+static int prism2_scan_results_proc_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open(file, &prism2_scan_results_proc_seqops);
+ if (ret == 0) {
+ struct seq_file *m = file->private_data;
+ m->private = PDE_DATA(inode);
}
+ return ret;
+}
+
+static const struct file_operations prism2_scan_results_proc_fops = {
+ .open = prism2_scan_results_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
- len = total - off;
- if (len > (p - page))
- len = p - page;
- *start = p - len;
- if (len > count)
- len = count;
- return len;
-}
#endif /* PRISM2_NO_STATION_MODES */
@@ -403,28 +467,29 @@ void hostap_init_proc(local_info_t *local)
}
#ifndef PRISM2_NO_PROCFS_DEBUG
- create_proc_read_entry("debug", 0, local->proc,
- prism2_debug_proc_read, local);
+ proc_create_data("debug", 0, local->proc,
+ &prism2_debug_proc_fops, local);
#endif /* PRISM2_NO_PROCFS_DEBUG */
- create_proc_read_entry("stats", 0, local->proc,
- prism2_stats_proc_read, local);
- create_proc_read_entry("wds", 0, local->proc,
- prism2_wds_proc_read, local);
- create_proc_read_entry("pda", 0, local->proc,
- prism2_pda_proc_read, local);
- create_proc_read_entry("aux_dump", 0, local->proc,
- prism2_aux_dump_proc_read, local);
- create_proc_read_entry("bss_list", 0, local->proc,
- prism2_bss_list_proc_read, local);
- create_proc_read_entry("crypt", 0, local->proc,
- prism2_crypt_proc_read, local);
+ proc_create_data("stats", 0, local->proc,
+ &prism2_stats_proc_fops, local);
+ proc_create_data("wds", 0, local->proc,
+ &prism2_wds_proc_fops, local);
+ proc_create_data("pda", 0, local->proc,
+ &prism2_pda_proc_fops, local);
+ proc_create_data("aux_dump", 0, local->proc,
+ local->func->read_aux_fops ?: &prism2_aux_dump_proc_fops,
+ local);
+ proc_create_data("bss_list", 0, local->proc,
+ &prism2_bss_list_proc_fops, local);
+ proc_create_data("crypt", 0, local->proc,
+ &prism2_crypt_proc_fops, local);
#ifdef PRISM2_IO_DEBUG
- create_proc_read_entry("io_debug", 0, local->proc,
- prism2_io_debug_proc_read, local);
+ proc_create_data("io_debug", 0, local->proc,
+ &prism2_io_debug_proc_fops, local);
#endif /* PRISM2_IO_DEBUG */
#ifndef PRISM2_NO_STATION_MODES
- create_proc_read_entry("scan_results", 0, local->proc,
- prism2_scan_results_proc_read, local);
+ proc_create_data("scan_results", 0, local->proc,
+ &prism2_scan_results_proc_fops, local);
#endif /* PRISM2_NO_STATION_MODES */
}
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index 7bb0b4b..5790401 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -596,8 +596,7 @@ struct prism2_helper_functions {
struct prism2_download_param *param);
int (*tx)(struct sk_buff *skb, struct net_device *dev);
int (*set_tim)(struct net_device *dev, int aid, int set);
- int (*read_aux)(struct net_device *dev, unsigned addr, int len,
- u8 *buf);
+ const struct file_operations *read_aux_fops;
int need_tx_headroom; /* number of bytes of headroom needed before
* IEEE 802.11 header */
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
index 4217b88..e51cb49 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
@@ -412,19 +412,18 @@ static int rtllib_ccmp_get_key(void *key, int len, u8 *seq, void *priv)
}
-static char *rtllib_ccmp_print_stats(char *p, void *priv)
+static void rtllib_ccmp_print_stats(struct seq_file *m, void *priv)
{
struct rtllib_ccmp_data *ccmp = priv;
- p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
- "tx_pn=%pM rx_pn=%pM "
- "format_errors=%d replays=%d decrypt_errors=%d\n",
- ccmp->key_idx, ccmp->key_set,
- ccmp->tx_pn, ccmp->rx_pn,
- ccmp->dot11RSNAStatsCCMPFormatErrors,
- ccmp->dot11RSNAStatsCCMPReplays,
- ccmp->dot11RSNAStatsCCMPDecryptErrors);
-
- return p;
+ seq_printf(m,
+ "key[%d] alg=CCMP key_set=%d "
+ "tx_pn=%pM rx_pn=%pM "
+ "format_errors=%d replays=%d decrypt_errors=%d\n",
+ ccmp->key_idx, ccmp->key_set,
+ ccmp->tx_pn, ccmp->rx_pn,
+ ccmp->dot11RSNAStatsCCMPFormatErrors,
+ ccmp->dot11RSNAStatsCCMPReplays,
+ ccmp->dot11RSNAStatsCCMPDecryptErrors);
}
static struct lib80211_crypto_ops rtllib_crypt_ccmp = {
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
index 8009250..5cfd73b 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
@@ -708,30 +708,30 @@ static int rtllib_tkip_get_key(void *key, int len, u8 *seq, void *priv)
}
-static char *rtllib_tkip_print_stats(char *p, void *priv)
+static void rtllib_tkip_print_stats(struct seq_file *m, void *priv)
{
struct rtllib_tkip_data *tkip = priv;
- p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
- "tx_pn=%02x%02x%02x%02x%02x%02x "
- "rx_pn=%02x%02x%02x%02x%02x%02x "
- "replays=%d icv_errors=%d local_mic_failures=%d\n",
- tkip->key_idx, tkip->key_set,
- (tkip->tx_iv32 >> 24) & 0xff,
- (tkip->tx_iv32 >> 16) & 0xff,
- (tkip->tx_iv32 >> 8) & 0xff,
- tkip->tx_iv32 & 0xff,
- (tkip->tx_iv16 >> 8) & 0xff,
- tkip->tx_iv16 & 0xff,
- (tkip->rx_iv32 >> 24) & 0xff,
- (tkip->rx_iv32 >> 16) & 0xff,
- (tkip->rx_iv32 >> 8) & 0xff,
- tkip->rx_iv32 & 0xff,
- (tkip->rx_iv16 >> 8) & 0xff,
- tkip->rx_iv16 & 0xff,
- tkip->dot11RSNAStatsTKIPReplays,
- tkip->dot11RSNAStatsTKIPICVErrors,
- tkip->dot11RSNAStatsTKIPLocalMICFailures);
- return p;
+ seq_printf(m,
+ "key[%d] alg=TKIP key_set=%d "
+ "tx_pn=%02x%02x%02x%02x%02x%02x "
+ "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "replays=%d icv_errors=%d local_mic_failures=%d\n",
+ tkip->key_idx, tkip->key_set,
+ (tkip->tx_iv32 >> 24) & 0xff,
+ (tkip->tx_iv32 >> 16) & 0xff,
+ (tkip->tx_iv32 >> 8) & 0xff,
+ tkip->tx_iv32 & 0xff,
+ (tkip->tx_iv16 >> 8) & 0xff,
+ tkip->tx_iv16 & 0xff,
+ (tkip->rx_iv32 >> 24) & 0xff,
+ (tkip->rx_iv32 >> 16) & 0xff,
+ (tkip->rx_iv32 >> 8) & 0xff,
+ tkip->rx_iv32 & 0xff,
+ (tkip->rx_iv16 >> 8) & 0xff,
+ tkip->rx_iv16 & 0xff,
+ tkip->dot11RSNAStatsTKIPReplays,
+ tkip->dot11RSNAStatsTKIPICVErrors,
+ tkip->dot11RSNAStatsTKIPLocalMICFailures);
}
static struct lib80211_crypto_ops rtllib_crypt_tkip = {
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_wep.c b/drivers/staging/rtl8192e/rtllib_crypt_wep.c
index 8cdf389..c4df6e0 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_wep.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_wep.c
@@ -247,12 +247,10 @@ static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
}
-static char *prism2_wep_print_stats(char *p, void *priv)
+static void prism2_wep_print_stats(struct seq_file *m, void *priv)
{
struct prism2_wep_data *wep = priv;
- p += sprintf(p, "key[%d] alg=WEP len=%d\n",
- wep->key_idx, wep->key_len);
- return p;
+ seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
}
static struct lib80211_crypto_ops rtllib_crypt_wep = {
diff --git a/include/net/lib80211.h b/include/net/lib80211.h
index d178c26..be95b92 100644
--- a/include/net/lib80211.h
+++ b/include/net/lib80211.h
@@ -30,6 +30,8 @@
#include <linux/skbuff.h>
#include <linux/ieee80211.h>
#include <linux/timer.h>
+#include <linux/seq_file.h>
+
/* print_ssid() is intended to be used in debug (and possibly error)
* messages. It should never be used for passing ssid to user space. */
const char *print_ssid(char *buf, const char *ssid, u8 ssid_len);
@@ -75,7 +77,7 @@ struct lib80211_crypto_ops {
/* procfs handler for printing out key information and possible
* statistics */
- char *(*print_stats) (char *p, void *priv);
+ void (*print_stats) (struct seq_file *m, void *priv);
/* Crypto specific flag get/set for configuration settings */
unsigned long (*get_flags) (void *priv);
diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c
index 1526c21..dc0e59e 100644
--- a/net/wireless/lib80211_crypt_ccmp.c
+++ b/net/wireless/lib80211_crypt_ccmp.c
@@ -430,24 +430,23 @@ static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
return CCMP_TK_LEN;
}
-static char *lib80211_ccmp_print_stats(char *p, void *priv)
+static void lib80211_ccmp_print_stats(struct seq_file *m, void *priv)
{
struct lib80211_ccmp_data *ccmp = priv;
- p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
- "tx_pn=%02x%02x%02x%02x%02x%02x "
- "rx_pn=%02x%02x%02x%02x%02x%02x "
- "format_errors=%d replays=%d decrypt_errors=%d\n",
- ccmp->key_idx, ccmp->key_set,
- ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2],
- ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5],
- ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2],
- ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5],
- ccmp->dot11RSNAStatsCCMPFormatErrors,
- ccmp->dot11RSNAStatsCCMPReplays,
- ccmp->dot11RSNAStatsCCMPDecryptErrors);
-
- return p;
+ seq_printf(m,
+ "key[%d] alg=CCMP key_set=%d "
+ "tx_pn=%02x%02x%02x%02x%02x%02x "
+ "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "format_errors=%d replays=%d decrypt_errors=%d\n",
+ ccmp->key_idx, ccmp->key_set,
+ ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2],
+ ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5],
+ ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2],
+ ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5],
+ ccmp->dot11RSNAStatsCCMPFormatErrors,
+ ccmp->dot11RSNAStatsCCMPReplays,
+ ccmp->dot11RSNAStatsCCMPDecryptErrors);
}
static struct lib80211_crypto_ops lib80211_crypt_ccmp = {
diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c
index d475cfc..8c90ba7 100644
--- a/net/wireless/lib80211_crypt_tkip.c
+++ b/net/wireless/lib80211_crypt_tkip.c
@@ -703,30 +703,30 @@ static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
return TKIP_KEY_LEN;
}
-static char *lib80211_tkip_print_stats(char *p, void *priv)
+static void lib80211_tkip_print_stats(struct seq_file *m, void *priv)
{
struct lib80211_tkip_data *tkip = priv;
- p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
- "tx_pn=%02x%02x%02x%02x%02x%02x "
- "rx_pn=%02x%02x%02x%02x%02x%02x "
- "replays=%d icv_errors=%d local_mic_failures=%d\n",
- tkip->key_idx, tkip->key_set,
- (tkip->tx_iv32 >> 24) & 0xff,
- (tkip->tx_iv32 >> 16) & 0xff,
- (tkip->tx_iv32 >> 8) & 0xff,
- tkip->tx_iv32 & 0xff,
- (tkip->tx_iv16 >> 8) & 0xff,
- tkip->tx_iv16 & 0xff,
- (tkip->rx_iv32 >> 24) & 0xff,
- (tkip->rx_iv32 >> 16) & 0xff,
- (tkip->rx_iv32 >> 8) & 0xff,
- tkip->rx_iv32 & 0xff,
- (tkip->rx_iv16 >> 8) & 0xff,
- tkip->rx_iv16 & 0xff,
- tkip->dot11RSNAStatsTKIPReplays,
- tkip->dot11RSNAStatsTKIPICVErrors,
- tkip->dot11RSNAStatsTKIPLocalMICFailures);
- return p;
+ seq_printf(m,
+ "key[%d] alg=TKIP key_set=%d "
+ "tx_pn=%02x%02x%02x%02x%02x%02x "
+ "rx_pn=%02x%02x%02x%02x%02x%02x "
+ "replays=%d icv_errors=%d local_mic_failures=%d\n",
+ tkip->key_idx, tkip->key_set,
+ (tkip->tx_iv32 >> 24) & 0xff,
+ (tkip->tx_iv32 >> 16) & 0xff,
+ (tkip->tx_iv32 >> 8) & 0xff,
+ tkip->tx_iv32 & 0xff,
+ (tkip->tx_iv16 >> 8) & 0xff,
+ tkip->tx_iv16 & 0xff,
+ (tkip->rx_iv32 >> 24) & 0xff,
+ (tkip->rx_iv32 >> 16) & 0xff,
+ (tkip->rx_iv32 >> 8) & 0xff,
+ tkip->rx_iv32 & 0xff,
+ (tkip->rx_iv16 >> 8) & 0xff,
+ tkip->rx_iv16 & 0xff,
+ tkip->dot11RSNAStatsTKIPReplays,
+ tkip->dot11RSNAStatsTKIPICVErrors,
+ tkip->dot11RSNAStatsTKIPLocalMICFailures);
}
static struct lib80211_crypto_ops lib80211_crypt_tkip = {
diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c
index c130401..1c292e4 100644
--- a/net/wireless/lib80211_crypt_wep.c
+++ b/net/wireless/lib80211_crypt_wep.c
@@ -253,11 +253,10 @@ static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv)
return wep->key_len;
}
-static char *lib80211_wep_print_stats(char *p, void *priv)
+static void lib80211_wep_print_stats(struct seq_file *m, void *priv)
{
struct lib80211_wep_data *wep = priv;
- p += sprintf(p, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
- return p;
+ seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
}
static struct lib80211_crypto_ops lib80211_crypt_wep = {
^ permalink raw reply related
* [PATCH 16/26] atmel: Don't use create_proc_read_entry() [RFC]
From: David Howells @ 2013-04-11 13:29 UTC (permalink / raw)
To: linux-kernel; +Cc: Simon Kelley, netdev, linux-wireless, viro, John W. Linville
In-Reply-To: <20130411132739.32763.82609.stgit@warthog.procyon.org.uk>
Don't use create_proc_read_entry() as that is deprecated, but rather use
proc_create_data() and seq_file instead.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Simon Kelley <simon@thekelleys.org.uk>
cc: John W. Linville <linville@tuxdriver.com>
cc: linux-wireless@vger.kernel.org
cc: netdev@vger.kernel.org
---
drivers/net/wireless/atmel.c | 69 +++++++++++++++++++-----------------------
1 file changed, 31 insertions(+), 38 deletions(-)
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 4374079..23a3498 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -63,6 +63,7 @@
#include <net/iw_handler.h>
#include <linux/crc32.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
@@ -1409,30 +1410,28 @@ static int atmel_validate_channel(struct atmel_private *priv, int channel)
return 0;
}
-static int atmel_proc_output (char *buf, struct atmel_private *priv)
+static int atmel_proc_show(struct seq_file *m, void *v)
{
+ struct atmel_private *priv = m->private;
int i;
- char *p = buf;
char *s, *r, *c;
- p += sprintf(p, "Driver version:\t\t%d.%d\n",
- DRIVER_MAJOR, DRIVER_MINOR);
+ seq_printf(m, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR);
if (priv->station_state != STATION_STATE_DOWN) {
- p += sprintf(p, "Firmware version:\t%d.%d build %d\n"
- "Firmware location:\t",
- priv->host_info.major_version,
- priv->host_info.minor_version,
- priv->host_info.build_version);
+ seq_printf(m,
+ "Firmware version:\t%d.%d build %d\n"
+ "Firmware location:\t",
+ priv->host_info.major_version,
+ priv->host_info.minor_version,
+ priv->host_info.build_version);
if (priv->card_type != CARD_TYPE_EEPROM)
- p += sprintf(p, "on card\n");
+ seq_puts(m, "on card\n");
else if (priv->firmware)
- p += sprintf(p, "%s loaded by host\n",
- priv->firmware_id);
+ seq_printf(m, "%s loaded by host\n", priv->firmware_id);
else
- p += sprintf(p, "%s loaded by hotplug\n",
- priv->firmware_id);
+ seq_printf(m, "%s loaded by hotplug\n", priv->firmware_id);
switch (priv->card_type) {
case CARD_TYPE_PARALLEL_FLASH:
@@ -1453,12 +1452,12 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
if (priv->reg_domain == channel_table[i].reg_domain)
r = channel_table[i].name;
- p += sprintf(p, "MAC memory type:\t%s\n", c);
- p += sprintf(p, "Regulatory domain:\t%s\n", r);
- p += sprintf(p, "Host CRC checking:\t%s\n",
- priv->do_rx_crc ? "On" : "Off");
- p += sprintf(p, "WPA-capable firmware:\t%s\n",
- priv->use_wpa ? "Yes" : "No");
+ seq_printf(m, "MAC memory type:\t%s\n", c);
+ seq_printf(m, "Regulatory domain:\t%s\n", r);
+ seq_printf(m, "Host CRC checking:\t%s\n",
+ priv->do_rx_crc ? "On" : "Off");
+ seq_printf(m, "WPA-capable firmware:\t%s\n",
+ priv->use_wpa ? "Yes" : "No");
}
switch (priv->station_state) {
@@ -1490,26 +1489,22 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
s = "<unknown>";
}
- p += sprintf(p, "Current state:\t\t%s\n", s);
- return p - buf;
+ seq_printf(m, "Current state:\t\t%s\n", s);
+ return 0;
}
-static int atmel_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int atmel_proc_open(struct inode *inode, struct file *file)
{
- struct atmel_private *priv = data;
- int len = atmel_proc_output (page, priv);
- if (len <= off+count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
+ return single_open(file, atmel_proc_show, PDE_DATA(inode));
}
+static const struct file_operations atmel_proc_fops = {
+ .open = atmel_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static const struct net_device_ops atmel_netdev_ops = {
.ndo_open = atmel_open,
.ndo_stop = atmel_close,
@@ -1525,7 +1520,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
struct device *sys_dev,
int (*card_present)(void *), void *card)
{
- struct proc_dir_entry *ent;
struct net_device *dev;
struct atmel_private *priv;
int rc;
@@ -1630,8 +1624,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
netif_carrier_off(dev);
- ent = create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);
- if (!ent)
+ if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv));
printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n",
^ permalink raw reply related
* Re: [PATCH 1/2] bonding: fix netdev event NULL pointer dereference
From: Sergei Shtylyov @ 2013-04-11 13:40 UTC (permalink / raw)
To: Nikolay Aleksandrov; +Cc: netdev, andy, fubar, davem
In-Reply-To: <1365538644-1502-1-git-send-email-nikolay@redhat.com>
Hello.
On 10-04-2013 0:17, Nikolay Aleksandrov wrote:
> In commit 471cb5a33dcbd7c529684a2ac7ba4451414ee4a7 ("bonding: remove
> usage of dev->master") a bug was introduced which causes a NULL pointer
> dereference. If a bond device is in mode 6 (ALB) and a slave is added
> it will dereference a NULL pointer in bond_slave_netdev_event().
> This is because in bond_enslave we have bond_alb_init_slave() which
> changes the MAC address of the slave and causes a NETDEV_CHANGEADDR.
> Then we have in bond_slave_netdev_event():
> struct slave *slave = bond_slave_get_rtnl(slave_dev);
> struct bonding *bond = slave->bond;
> bond_slave_get_rtnl() dereferences slave_dev->rx_handler_data which at
> that time is NULL since netdev_rx_handler_register() is called later.
> This is fixed by checking if slave is NULL before dereferencing it.
> Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
[...]
Minor formatting nit.
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 171b10f..9995ddc 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -3168,11 +3168,21 @@ static int bond_slave_netdev_event(unsigned long event,
> struct net_device *slave_dev)
> {
> struct slave *slave = bond_slave_get_rtnl(slave_dev);
> - struct bonding *bond = slave->bond;
> - struct net_device *bond_dev = slave->bond->dev;
> + struct bonding *bond;
> + struct net_device *bond_dev;
> u32 old_speed;
> u8 old_duplex;
>
> + /*
> + * A netdev event can be generated while enslaving a device
> + * before netdev_rx_handler_register is called in which case
> + * slave will be NULL
> + */
The preferred multi-line comment style in the networking code is:
/* bla
* bla
*/
WBR, Sergei
^ permalink raw reply
* Netpoll triggers soft lockup
From: Bart Van Assche @ 2013-04-11 13:42 UTC (permalink / raw)
To: Neil Horman, David Miller, netdev@vger.kernel.org
Hi,
While testing a driver against kernel 3.9-rc6 I ran into a soft lockup
triggered by sending lots of kernel messages to a remote system via
netconsole. This behavior was probably introduced by commit ca99ca14c
("netpoll: protect napi_poll and poll_controller during
dev_[open|close]"). That commit introduced a mutex in
netpoll_poll_dev(), which can be called from interrupt context. Is there
anyone who can tell me whether this is a bug in commit ca99ca14c or in
netconsole ?
Read(10):------------[ cut here ]------------
WARNING: at kernel/mutex.c:434 mutex_trylock+0x16d/0x180()
Hardware name: P5Q DELUXE
Modules linked in: ib_srp scsi_transport_srp dm_mod qla2x00tgt(O)
qla2xxx_scst(O) scsi_transport_fc iscsi_scst(O) ib_srpt(O) scst_vdisk(O)
libcrc32c scst(O) crc32c brd netconsole configfs rdma_ucm rdma_cm iw_cm
ib_addr scsi_tgt af_packet snd_hda_codec_hdmi snd_hda_codec_analog
ib_ipoib ib_cm ib_uverbs ib_umad snd_hda_intel snd_hda_codec snd_hwdep
snd_pcm snd_seq snd_timer mlx4_ib ib_sa ib_mad cpufreq_conservative
ib_core cpufreq_userspace cpufreq_powersave snd_seq_device snd mlx4_core
sr_mod skge soundcore pcspkr acpi_cpufreq button ehci_pci sg i2c_i801
mperf snd_page_alloc cdrom microcode autofs4 ext3 jbd mbcache sd_mod
crc_t10dif radeon uhci_hcd ttm drm_kms_helper ehci_hcd drm i2c_algo_bit
i2c_core intel_agp intel_gtt agpgart usbcore usb_common processor
thermal_sys hwmon scsi_dh_alua scsi_dh ata_generic ata_piix ahci libahci
pata_marvell libata scsi_mod [last unloaded: scsi_transport_srp]
Pid: 178, comm: kworker/0:1H Tainted: G O 3.9.0-rc6-debug+ #0
Call Trace:
<IRQ> [<ffffffff8103d79f>] warn_slowpath_common+0x7f/0xc0
[<ffffffff8103d7fa>] warn_slowpath_null+0x1a/0x20
[<ffffffff814761dd>] mutex_trylock+0x16d/0x180
[<ffffffff813968c9>] netpoll_poll_dev+0x49/0xc30
[<ffffffff8136a2d2>] ? __alloc_skb+0x82/0x2a0
[<ffffffff81397715>] netpoll_send_skb_on_dev+0x265/0x410
[<ffffffff81397c5a>] netpoll_send_udp+0x28a/0x3a0
[<ffffffffa0541843>] ? write_msg+0x53/0x110 [netconsole]
[<ffffffffa05418bf>] write_msg+0xcf/0x110 [netconsole]
[<ffffffff8103eba1>] call_console_drivers.constprop.17+0xa1/0x1c0
[<ffffffff8103fb76>] console_unlock+0x2d6/0x450
[<ffffffff8104011e>] vprintk_emit+0x1ee/0x510
[<ffffffff8146f9f6>] printk+0x4d/0x4f
[<ffffffffa0004f1d>] scsi_print_command+0x7d/0xe0 [scsi_mod]
[<ffffffffa000b924>] scsi_io_completion+0x294/0x6c0 [scsi_mod]
[<ffffffffa000113d>] scsi_finish_command+0xbd/0x120 [scsi_mod]
[<ffffffffa000b58f>] scsi_softirq_done+0x13f/0x160 [scsi_mod]
[<ffffffff8121dbc0>] blk_done_softirq+0x80/0xa0
[<ffffffff81046e81>] ? __do_softirq+0xb1/0x3c0
[<ffffffff81046ed1>] __do_softirq+0x101/0x3c0
[<ffffffff810cc649>] ? handle_irq_event+0x59/0x80
[<ffffffff81047355>] irq_exit+0xb5/0xc0
[<ffffffff81484cd3>] do_IRQ+0x63/0xe0
[<ffffffff8147a82f>] common_interrupt+0x6f/0x6f
<EOI> [<ffffffff810a1ea2>] ? mark_held_locks+0xb2/0x130
[<ffffffff8147a46a>] ? _raw_spin_unlock_irq+0x3a/0x50
[<ffffffff8147a460>] ? _raw_spin_unlock_irq+0x30/0x50
[<ffffffff812148e5>] blk_delay_work+0x35/0x40
[<ffffffff8106135d>] process_one_work+0x1fd/0x650
[<ffffffff810612f2>] ? process_one_work+0x192/0x650
[<ffffffff81061b50>] worker_thread+0x110/0x380
[<ffffffff81061a40>] ? rescuer_thread+0x250/0x250
[<ffffffff81067d6b>] kthread+0xdb/0xe0
[<ffffffff81067c90>] ? kthread_create_on_node+0x140/0x140
[<ffffffff8148345c>] ret_from_fork+0x7c/0xb0
[<ffffffff81067c90>] ? kthread_create_on_node+0x140/0x140
---[ end trace e3e3a22d8bb51cb7 ]---
Thanks,
Bart.
^ permalink raw reply
* [PATCHv2 1/2] bonding: fix netdev event NULL pointer dereference
From: Nikolay Aleksandrov @ 2013-04-11 13:45 UTC (permalink / raw)
To: netdev; +Cc: andy, fubar, davem
In-Reply-To: <1365538644-1502-1-git-send-email-nikolay@redhat.com>
In commit 471cb5a33dcbd7c529684a2ac7ba4451414ee4a7 ("bonding: remove
usage of dev->master") a bug was introduced which causes a NULL pointer
dereference. If a bond device is in mode 6 (ALB) and a slave is added
it will dereference a NULL pointer in bond_slave_netdev_event().
This is because in bond_enslave we have bond_alb_init_slave() which
changes the MAC address of the slave and causes a NETDEV_CHANGEADDR.
Then we have in bond_slave_netdev_event():
struct slave *slave = bond_slave_get_rtnl(slave_dev);
struct bonding *bond = slave->bond;
bond_slave_get_rtnl() dereferences slave_dev->rx_handler_data which at
that time is NULL since netdev_rx_handler_register() is called later.
This is fixed by checking if slave is NULL before dereferencing it.
v2: Fix the comment styling
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
drivers/net/bonding/bond_main.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 171b10f..15c675c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3168,11 +3168,20 @@ static int bond_slave_netdev_event(unsigned long event,
struct net_device *slave_dev)
{
struct slave *slave = bond_slave_get_rtnl(slave_dev);
- struct bonding *bond = slave->bond;
- struct net_device *bond_dev = slave->bond->dev;
+ struct bonding *bond;
+ struct net_device *bond_dev;
u32 old_speed;
u8 old_duplex;
+ /* A netdev event can be generated while enslaving a device
+ * before netdev_rx_handler_register is called in which case
+ * slave will be NULL
+ */
+ if (!slave)
+ return NOTIFY_DONE;
+ bond_dev = slave->bond->dev;
+ bond = slave->bond;
+
switch (event) {
case NETDEV_UNREGISTER:
if (bond->setup_by_slave)
--
1.8.1.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox