* Re: [PATCH net-next v3] packet: tx_ring: allow the user to choose tx data offset
From: David Miller @ 2012-11-07 23:55 UTC (permalink / raw)
To: Paul.Chavent; +Cc: netdev
In-Reply-To: <1352279447-2980-1-git-send-email-paul.chavent@onera.fr>
From: Paul Chavent <Paul.Chavent@onera.fr>
Date: Wed, 7 Nov 2012 10:10:47 +0100
> The tx data offset of packet mmap tx ring used to be :
> (TPACKET2_HDRLEN - sizeof(struct sockaddr_ll))
>
> The problem is that, with SOCK_RAW socket, the payload (14 bytes after
> the beginning of the user data) is misaligned.
>
> This patch allows to let the user gives an offset for it's tx data if
> he desires.
>
> Set sock option PACKET_TX_HAS_OFF to 1, then specify in each frame of
> your tx ring tp_net for SOCK_DGRAM, or tp_mac for SOCK_RAW.
>
> Signed-off-by: Paul Chavent <paul.chavent@onera.fr>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH 2/2] net: fec: reduce spin lock time in fec_ptp_adjfreq
From: David Miller @ 2012-11-07 23:53 UTC (permalink / raw)
To: Frank.Li
Cc: lznuaa, richardcochran, shawn.guo, linux-arm-kernel, netdev,
bhutchings
In-Reply-To: <1352268889-16836-1-git-send-email-Frank.Li@freescale.com>
From: Frank Li <Frank.Li@freescale.com>
Date: Wed, 7 Nov 2012 14:14:49 +0800
> move below calculate out of spin lock section
> diff = fep->cc.mult;
> diff *= ppb;
> diff = div_u64(diff, 1000000000ULL);
>
> diff is local variable and not neccesary in spin lock
>
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
Also applied, thanks.
^ permalink raw reply
* Re: [PATCH 1/2] net: fec: default select FEC_PTP at mx6 platform
From: David Miller @ 2012-11-07 23:52 UTC (permalink / raw)
To: Frank.Li
Cc: lznuaa, richardcochran, shawn.guo, linux-arm-kernel, netdev,
bhutchings
In-Reply-To: <1352268883-16800-1-git-send-email-Frank.Li@freescale.com>
From: Frank Li <Frank.Li@freescale.com>
Date: Wed, 7 Nov 2012 14:14:43 +0800
> Remove PPS.
> Limit FEC_PTP option for i.MX chip only.
> FEC_PTP default is on at mx6 platform.
>
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
Applied to net-next.
But please be explicit about which tree your patches are for in the
subject line in the future.
^ permalink raw reply
* Re: [PATCH] tcp: Avoid infinite loop on recvmsg bug
From: Eric Dumazet @ 2012-11-07 23:42 UTC (permalink / raw)
To: Julius Werner
Cc: linux-kernel, netdev, Patrick McHardy, Hideaki YOSHIFUJI,
James Morris, Alexey Kuznetsov, David S. Miller, Dave Jones,
Sameer Nanda, Mandeep Singh Baines
In-Reply-To: <1352331192.2748.10.camel@edumazet-glaptop>
On Wed, 2012-11-07 at 15:33 -0800, Eric Dumazet wrote:
> So you probably are fighting a bug we already fixed in upstream kernel.
>
> (commit c8628155ece363 "tcp: reduce out_of_order memory use" did not
> played well with cloned skbs.)
>
> This issue was already discussed on netdev in the past.
If you use a 3.4 kernel, you want the following patch.
(I guess you could reproduce the crash easily running a tcpdump in //)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 257b617..9f8f68c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4496,7 +4496,9 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
* to avoid future tcp_collapse_ofo_queue(),
* probably the most expensive function in tcp stack.
*/
- if (skb->len <= skb_tailroom(skb1) && !tcp_hdr(skb)->fin) {
+ if (skb->len <= skb_tailroom(skb1) &&
+ !tcp_hdr(skb)->fin &&
+ !skb_cloned(skb1)) {
NET_INC_STATS_BH(sock_net(sk),
LINUX_MIB_TCPRCVCOALESCE);
BUG_ON(skb_copy_bits(skb, 0,
^ permalink raw reply related
* Re: tc filter u32 match
From: Nieścierowicz Adam @ 2012-11-07 23:36 UTC (permalink / raw)
To: Jamal Hadi Salim, Netdev
In-Reply-To: <1337853878.3513.11.camel@mojatatu>
W dniu 24.05.2012 12:04, Jamal Hadi Salim napisał(a):
> On Tue, 2012-05-22 at 15:42 +0200, Nieścierowicz Adam wrote:
>
>> Hello, I'm in the process of building a new shaper, when adding
>> support
>> for 802.1q vlan noticed that u32 can catch network traffic without
>> giving 4 bytes offset. How is this possible?
>
> Because we look at where the network header starts?
> Why do you expect 4 bytes to be counted?
>
>> My environment: eth2 - network card eth2.200 - vlan /sbin/tc filter
>> add
>> dev eth2 parent 1:0 prio 5 handle 35: protocol ip u32 divisor 256
>> /sbin/tc filter add dev eth2 protocol ip parent 1:0 prio 5 u32 ht
>> 800::
>> match ip dst 31.41.208.32/27 hashkey mask 0x000000ff at 16 link 35:
>> /sbin/tc filter add dev eth2 protocol ip parent 1: prio 1 u32 ht
>> 35:24:
>> match ip dst 31.41.208.36 flowid 1:2e5 Here you can see the hits in
>> the
>> rule filter parent 1: protocol ip pref 5 u32 fh 35:24:800 order 2048
>> key ht 35 bkt 24 flowid 1:2e5 (rule hit 44037 success 44037) match
>> 1f29d024/ffffffff at 16 (success 44037 )
>
> I dont see an issue. This looks correct.
>
>>> I found a similar question here
>>
>
http://serverfault.com/questions/370795/tc-u32-how-to-match-l2-protocols-in-recent-kernels
>>
>
> There may have been bugs in the past that someone missed or didnt
> report here (likely around the time there was a lot of changes
> happening with vlan offloading). Try the latest kernel and
> if it behaves badly, send a report and a reproducible test case.
Hello Again,
I changed the kernel to 3.6.0 and ip traffic classification on the
interface and vlan works fine.
Unfortunately I am not able to classify
PPPoE traffic, I checked filters with offset: 16, 20, 24, 28
Is it possible to classify PPPoE traffic on the main interface as it
was in previous kernels?
^ permalink raw reply
* Re: [PATCH] tcp: Avoid infinite loop on recvmsg bug
From: Eric Dumazet @ 2012-11-07 23:33 UTC (permalink / raw)
To: Julius Werner
Cc: linux-kernel, netdev, Patrick McHardy, Hideaki YOSHIFUJI,
James Morris, Alexey Kuznetsov, David S. Miller, Dave Jones,
Sameer Nanda, Mandeep Singh Baines
In-Reply-To: <CAODwPW8mBJspF3k5SCBR-BShNvBLQpD-vyhLRh5Cq-4h=VZDgg@mail.gmail.com>
On Wed, 2012-11-07 at 13:14 -0800, Julius Werner wrote:
> > What I find very sad in all this is that you didnt mention the driver
> > that was triggering this bug.
>
> Sorry, I was just trying to keep this thread focussed on one patch.
> The bug report that led me to this is publicly accessible at
> http://crosbug.com/35827. We have encountered the problem only once,
> on an Acer AC700 Chromebook that ran automated tests. The ethernet
> interface for the offending socket was provided by a USB-to-Ethernet
> dongle using the smsc95xx/usbnet module (v1.0.4).
This driver uses interesting skb_clone() games and skb->truesize lies :
skb->truesize = size + sizeof(struct sk_buff);
So you probably are fighting a bug we already fixed in upstream kernel.
(commit c8628155ece363 "tcp: reduce out_of_order memory use" did not
played well with cloned skbs.)
This issue was already discussed on netdev in the past.
^ permalink raw reply
* Re: [PATCH 0/8] at91_ether share stats/address setting with macb
From: David Miller @ 2012-11-07 22:45 UTC (permalink / raw)
To: manabian; +Cc: nicolas.ferre, plagnioj, netdev
In-Reply-To: <1352312097-31320-1-git-send-email-manabian@gmail.com>
From: Joachim Eastwood <manabian@gmail.com>
Date: Wed, 7 Nov 2012 19:14:49 +0100
> Patch 1-2 add support for some special at91_ether features to macb address setting code. This will allow us to have one address setting function that can be shared.
>
> Patch 4 removes the at91_ether address set/get code and make use of the exported functions for macb.
>
> Patch 5 remove the at91_ether statistics functions and replace them with equivalent function from macb.
>
> Patch 6 removes an unused member from the at91_ether/macb private struct.
>
> Patch 7 is a clean up of the print outs from at91_ether.
>
> Patch 8 is a misc clean up patch which fixes some comment and style issues.
>
>
> Most of the code left in at91_ether now deal with configuration and DMA rx/tx which is hard to share with macb since this is specific for the IP block in AT91RM9200.
>
> Next I'll work on adding PHY GPIO interrupt to the macb driver. at91_ether had this functionality before it began using mdio functions from macb.
All applied to net-next, thanks.
^ permalink raw reply
* Re: [PATCH net-next 0/7] be2net: patch set
From: David Miller @ 2012-11-07 22:00 UTC (permalink / raw)
To: sathya.perla; +Cc: netdev
In-Reply-To: <4f3dfb12-ef85-48ce-9c67-f5e58ed6f105@CMEXHTCAS2.ad.emulex.com>
From: Sathya Perla <sathya.perla@emulex.com>
Date: Wed, 7 Nov 2012 09:18:54 +0530
> Pls apply.
>
> Sathya Perla (7):
> be2net: remove LANCER A0 workaround
> be2net: fix wrong usage of adapter->generation
> be2net: do not use sli_family to identify skyhawk-R chip
> be2net: re-factor bar mapping code
> be2net: fix access to SEMAPHORE reg
> be2net: remove roce on lancer
> be2net: remove adapter->eq_next_idx
Looks good, all applied to net-next, thanks.
^ permalink raw reply
* Re: [PATCH 0/2] Fix CDC_EEM with 802.1Q VLAN and 1500 MTU
From: David Miller @ 2012-11-07 21:56 UTC (permalink / raw)
To: iancoolidge-Re5JQEeQqe8AvxtiuMwx3w
Cc: oliver-Q6YOFhsQ4GZ7tPAFqOLdPg,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, balbi-l0cyMroinI0,
linux-usb-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1352235611-13066-1-git-send-email-iancoolidge-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Patch #2 does not apply cleanl to the net tree.
Please respin and repost this entire series again.
Thanks.
--
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] tcp: Avoid infinite loop on recvmsg bug
From: Julius Werner @ 2012-11-07 21:14 UTC (permalink / raw)
To: Eric Dumazet
Cc: linux-kernel, netdev, Patrick McHardy, Hideaki YOSHIFUJI,
James Morris, Alexey Kuznetsov, David S. Miller, Dave Jones,
Sameer Nanda, Mandeep Singh Baines
In-Reply-To: <1352317219.5552.6.camel@edumazet-glaptop>
> What I find very sad in all this is that you didnt mention the driver
> that was triggering this bug.
Sorry, I was just trying to keep this thread focussed on one patch.
The bug report that led me to this is publicly accessible at
http://crosbug.com/35827. We have encountered the problem only once,
on an Acer AC700 Chromebook that ran automated tests. The ethernet
interface for the offending socket was provided by a USB-to-Ethernet
dongle using the smsc95xx/usbnet module (v1.0.4).
Don't get me wrong, I do understand the importance of finding the
underlying cause of this... I just don't think I have much of a chance
with one report. I can go through the above-mentioned module and see
if something looks suspicious in the skb handling code if I can find
the time. But on the other hand the fact remains that this condition
is not handled well... not just for this particular case, but for all
future kernel and driver bugs that may trigger it again. I am not
trying to "hide" any issues, I am all for making them as visible as
possible... but as Dave pointed out, kernel panics may not be the best
way to do that either, and I think damage mitigation also has some
value. The current code clearly does the worst of both worlds, so
please let's just improve it one way or the other.
^ permalink raw reply
* Re: [PATCH net] cxgb4: Initialize data structures before using.
From: David Miller @ 2012-11-07 20:43 UTC (permalink / raw)
To: vipul; +Cc: netdev, divy, dm, jay
In-Reply-To: <1352209029-4291-1-git-send-email-vipul@chelsio.com>
From: Vipul Pandya <vipul@chelsio.com>
Date: Tue, 6 Nov 2012 19:07:09 +0530
> We should not assume reserve fields to be don't cares as fields may change.
> Clearing data structures before using.
>
> Signed-off-by: Jay Hernandez <jay@chelsio.com>
> Signed-off-by: Vipul Pandya <vipul@chelsio.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH v2] af-packet: fix oops when socket is not present
From: David Miller @ 2012-11-07 20:42 UTC (permalink / raw)
To: eric; +Cc: netdev
In-Reply-To: <1352203810-957-1-git-send-email-eric@regit.org>
From: Eric Leblond <eric@regit.org>
Date: Tue, 6 Nov 2012 13:10:10 +0100
> Due to a NULL dereference, the following patch is causing oops
> in normal trafic condition:
>
> commit c0de08d04215031d68fa13af36f347a6cfa252ca
> Author: Eric Leblond <eric@regit.org>
> Date: Thu Aug 16 22:02:58 2012 +0000
>
> af_packet: don't emit packet on orig fanout group
>
> This buggy patch was a feature fix and has reached most stable
> branches.
>
> When skb->sk is NULL and when packet fanout is used, there is a
> crash in match_fanout_group where skb->sk is accessed.
> This patch fixes the issue by returning false as soon as the
> socket is NULL: this correspond to the wanted behavior because
> the kernel as to resend the skb to all the listening socket in
> this case.
>
> Signed-off-by: Eric Leblond <eric@regit.org>
Applied and queued up for -stable, thanks.
^ permalink raw reply
* Re: [PATCH 2/2] smsc95xx: set MII_BUSY bit to read/write PHY regs
From: David Miller @ 2012-11-07 20:39 UTC (permalink / raw)
To: steve.glendinning; +Cc: netdev
In-Reply-To: <1352196533-2674-1-git-send-email-steve.glendinning@shawell.net>
From: Steve Glendinning <steve.glendinning@shawell.net>
Date: Tue, 6 Nov 2012 10:08:53 +0000
> The device datasheet specifies the BUSY bit must be set when reading
> or writing phy registers. This patch ensures we do that.
>
> Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
Steve, what's the story here? Where is patch #1?
^ permalink raw reply
* Re: [PATCH] pkt_sched: enable QFQ to support TSO/GSO
From: David Miller @ 2012-11-07 20:37 UTC (permalink / raw)
To: paolo.valente; +Cc: jhs, shemminger, linux-kernel, netdev, rizzo, fchecconi
In-Reply-To: <20121106062924.GA2930@paolo-ThinkPad-W520>
From: Paolo Valente <paolo.valente@unimore.it>
Date: Tue, 6 Nov 2012 07:29:24 +0100
> If the max packet size for some class (configured through tc) is
> violated by the actual size of the packets of that class, then QFQ
> would not schedule classes correctly, and the data structures
> implementing the bucket lists may get corrupted. This problem occurs
> with TSO/GSO even if the max packet size is set to the MTU, and is,
> e.g., the cause of the failure reported in [1]. Two patches have been
> proposed to solve this problem in [2], one of them is a preliminary
> version of this patch.
>
> This patch addresses the above issues by: 1) setting QFQ parameters to
> proper values for supporting TSO/GSO (in particular, setting the
> maximum possible packet size to 64KB), 2) automatically increasing the
> max packet size for a class, lmax, when a packet with a larger size
> than the current value of lmax arrives.
>
> The drawback of the first point is that the maximum weight for a class
> is now limited to 4096, which is equal to 1/16 of the maximum weight
> sum.
>
> Finally, this patch also forcibly caps the timestamps of a class if
> they are too high to be stored in the bucket list. This capping, taken
> from QFQ+ [3], handles the unfrequent case described in the comment to
> the function slot_insert.
>
> [1] http://marc.info/?l=linux-netdev&m=134968777902077&w=2
> [2] http://marc.info/?l=linux-netdev&m=135096573507936&w=2
> [3] http://marc.info/?l=linux-netdev&m=134902691421670&w=2
>
> Signed-off-by: Paolo Valente <paolo.valente@unimore.it>
> Tested-by: Cong Wang <amwang@redhat.com>
> Acked-by: Stephen Hemminger <shemminger@vyatta.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH net-next] mlx4: change TX coalescing defaults
From: David Miller @ 2012-11-07 20:31 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev, yevgenyp, ogerlitz, j.vimal
In-Reply-To: <1352168442.3140.32.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 05 Nov 2012 18:20:42 -0800
> From: Eric Dumazet <edumazet@google.com>
>
> mlx4 currently uses a too high tx coalescing setting, deferring
> TX completion interrupts by up to 128 us.
>
> With the recent skb_orphan() removal in commit 8112ec3b872,
> performance of a single TCP flow is capped to ~4 Gbps, unless
> we increase tcp_limit_output_bytes.
>
> I suggest using 16 us instead of 128 us, allowing a finer control.
>
> Performance of a single TCP flow is restored to previous levels,
> while keeping TCP small queues fully enabled with default sysctl.
>
> This patch is also a BQL prereq.
>
> Reported-by: Vimalkumar <j.vimal@gmail.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied, thanks Eric.
^ permalink raw reply
* Re: [PATCH v5] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Marc Kleine-Budde @ 2012-11-07 20:29 UTC (permalink / raw)
To: Olivier Sobrie; +Cc: Wolfgang Grandegger, linux-can, netdev, linux-usb
In-Reply-To: <1349162164-16149-1-git-send-email-olivier@sobrie.be>
[-- Attachment #1: Type: text/plain, Size: 48491 bytes --]
On 10/02/2012 09:16 AM, Olivier Sobrie wrote:
> This driver provides support for several Kvaser CAN/USB devices.
> Such kind of devices supports up to three CAN network interfaces.
>
> It has been tested with a Kvaser USB Leaf Light (one network interface)
> connected to a pch_can interface.
> The firmware version of the Kvaser device was 2.5.205.
>
> List of Kvaser devices supported by the driver:
> - Kvaser Leaf Light
> - Kvaser Leaf Professional HS
> - Kvaser Leaf SemiPro HS
> - Kvaser Leaf Professional LS
> - Kvaser Leaf Professional SWC
> - Kvaser Leaf Professional LIN
> - Kvaser Leaf SemiPro LS
> - Kvaser Leaf SemiPro SWC
> - Kvaser Memorator II HS/HS
> - Kvaser USBcan Professional HS/HS
> - Kvaser Leaf Light GI
> - Kvaser Leaf Professional HS (OBD-II connector)
> - Kvaser Memorator Professional HS/LS
> - Kvaser Leaf Light "China"
> - Kvaser BlackBird SemiPro
> - Kvaser USBcan R
>
> Signed-off-by: Daniel Berglund <db@kvaser.com>
> Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
Sorry I forgot about the review.
Looks quite good, some comments inline.
> ---
> Hi,
>
> This new patch fixes the errors pointed out by Marc and Wolfgang.
>
> Changes since v4:
> - add missing usb_free_urb()
> - put error message in a separate function
> - handle return code of kvaser_usb_init_one() in probe function
>
> Olivier
>
> drivers/net/can/usb/Kconfig | 29 +
> drivers/net/can/usb/Makefile | 1 +
> drivers/net/can/usb/kvaser_usb.c | 1596 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 1626 insertions(+)
> create mode 100644 drivers/net/can/usb/kvaser_usb.c
>
> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
> index 0a68768..a4e4bee 100644
> --- a/drivers/net/can/usb/Kconfig
> +++ b/drivers/net/can/usb/Kconfig
> @@ -13,6 +13,35 @@ config CAN_ESD_USB2
> This driver supports the CAN-USB/2 interface
> from esd electronic system design gmbh (http://www.esd.eu).
>
> +config CAN_KVASER_USB
> + tristate "Kvaser CAN/USB interface"
> + ---help---
> + This driver adds support for Kvaser CAN/USB devices like Kvaser
> + Leaf Light.
> +
> + The driver gives support for the following devices:
> + - Kvaser Leaf Light
> + - Kvaser Leaf Professional HS
> + - Kvaser Leaf SemiPro HS
> + - Kvaser Leaf Professional LS
> + - Kvaser Leaf Professional SWC
> + - Kvaser Leaf Professional LIN
> + - Kvaser Leaf SemiPro LS
> + - Kvaser Leaf SemiPro SWC
> + - Kvaser Memorator II HS/HS
> + - Kvaser USBcan Professional HS/HS
> + - Kvaser Leaf Light GI
> + - Kvaser Leaf Professional HS (OBD-II connector)
> + - Kvaser Memorator Professional HS/LS
> + - Kvaser Leaf Light "China"
> + - Kvaser BlackBird SemiPro
> + - Kvaser USBcan R
> +
> + If unsure, say N.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called kvaser_usb.
> +
> config CAN_PEAK_USB
> tristate "PEAK PCAN-USB/USB Pro interfaces"
> ---help---
> diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
> index da6d1d3..80a2ee4 100644
> --- a/drivers/net/can/usb/Makefile
> +++ b/drivers/net/can/usb/Makefile
> @@ -4,6 +4,7 @@
>
> obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
> obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
> +obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
> obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
>
> ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> new file mode 100644
> index 0000000..bd48807
> --- /dev/null
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -0,0 +1,1596 @@
> +/*
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * Parts of this driver are based on the following:
> + * - Kvaser linux leaf driver (version 4.78)
> + * - CAN driver for esd CAN-USB/2
> + *
> + * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
> + * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
> + * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> + */
> +
> +#include <linux/init.h>
> +#include <linux/completion.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/usb.h>
> +
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +
> +#define MAX_TX_URBS 16
> +#define MAX_RX_URBS 4
> +#define START_TIMEOUT 1000 /* msecs */
> +#define STOP_TIMEOUT 1000 /* msecs */
> +#define USB_SEND_TIMEOUT 1000 /* msecs */
> +#define USB_RECV_TIMEOUT 1000 /* msecs */
> +#define RX_BUFFER_SIZE 3072
> +#define CAN_USB_CLOCK 8000000
> +#define MAX_NET_DEVICES 3
> +
> +/* Kvaser USB devices */
> +#define KVASER_VENDOR_ID 0x0bfd
> +#define USB_LEAF_DEVEL_PRODUCT_ID 10
> +#define USB_LEAF_LITE_PRODUCT_ID 11
> +#define USB_LEAF_PRO_PRODUCT_ID 12
> +#define USB_LEAF_SPRO_PRODUCT_ID 14
> +#define USB_LEAF_PRO_LS_PRODUCT_ID 15
> +#define USB_LEAF_PRO_SWC_PRODUCT_ID 16
> +#define USB_LEAF_PRO_LIN_PRODUCT_ID 17
> +#define USB_LEAF_SPRO_LS_PRODUCT_ID 18
> +#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19
> +#define USB_MEMO2_DEVEL_PRODUCT_ID 22
> +#define USB_MEMO2_HSHS_PRODUCT_ID 23
> +#define USB_UPRO_HSHS_PRODUCT_ID 24
> +#define USB_LEAF_LITE_GI_PRODUCT_ID 25
> +#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26
> +#define USB_MEMO2_HSLS_PRODUCT_ID 27
> +#define USB_LEAF_LITE_CH_PRODUCT_ID 28
> +#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29
> +#define USB_OEM_MERCURY_PRODUCT_ID 34
> +#define USB_OEM_LEAF_PRODUCT_ID 35
> +#define USB_CAN_R_PRODUCT_ID 39
> +
> +/* USB devices features */
> +#define KVASER_HAS_SILENT_MODE BIT(0)
> +#define KVASER_HAS_TXRX_ERRORS BIT(1)
> +
> +/* Message header size */
> +#define MSG_HEADER_LEN 2
> +
> +/* Can message flags */
> +#define MSG_FLAG_ERROR_FRAME BIT(0)
> +#define MSG_FLAG_OVERRUN BIT(1)
> +#define MSG_FLAG_NERR BIT(2)
> +#define MSG_FLAG_WAKEUP BIT(3)
> +#define MSG_FLAG_REMOTE_FRAME BIT(4)
> +#define MSG_FLAG_RESERVED BIT(5)
> +#define MSG_FLAG_TX_ACK BIT(6)
> +#define MSG_FLAG_TX_REQUEST BIT(7)
> +
> +/* Can states */
> +#define M16C_STATE_BUS_RESET BIT(0)
> +#define M16C_STATE_BUS_ERROR BIT(4)
> +#define M16C_STATE_BUS_PASSIVE BIT(5)
> +#define M16C_STATE_BUS_OFF BIT(6)
> +
> +/* Can msg ids */
> +#define CMD_RX_STD_MESSAGE 12
> +#define CMD_TX_STD_MESSAGE 13
> +#define CMD_RX_EXT_MESSAGE 14
> +#define CMD_TX_EXT_MESSAGE 15
> +#define CMD_SET_BUS_PARAMS 16
> +#define CMD_GET_BUS_PARAMS 17
> +#define CMD_GET_BUS_PARAMS_REPLY 18
> +#define CMD_GET_CHIP_STATE 19
> +#define CMD_CHIP_STATE_EVENT 20
> +#define CMD_SET_CTRL_MODE 21
> +#define CMD_GET_CTRL_MODE 22
> +#define CMD_GET_CTRL_MODE_REPLY 23
> +#define CMD_RESET_CHIP 24
> +#define CMD_RESET_CARD 25
> +#define CMD_START_CHIP 26
> +#define CMD_START_CHIP_REPLY 27
> +#define CMD_STOP_CHIP 28
> +#define CMD_STOP_CHIP_REPLY 29
> +#define CMD_GET_CARD_INFO2 32
> +#define CMD_GET_CARD_INFO 34
> +#define CMD_GET_CARD_INFO_REPLY 35
> +#define CMD_GET_SOFTWARE_INFO 38
> +#define CMD_GET_SOFTWARE_INFO_REPLY 39
> +#define CMD_ERROR_EVENT 45
> +#define CMD_FLUSH_QUEUE 48
> +#define CMD_RESET_ERROR_COUNTER 49
> +#define CMD_TX_ACKNOWLEDGE 50
> +#define CMD_CAN_ERROR_EVENT 51
> +#define CMD_USB_THROTTLE 77
> +#define CMD_LOG_MESSAGE 106
> +
> +/* error factors */
> +#define M16C_EF_ACKE BIT(0)
> +#define M16C_EF_CRCE BIT(1)
> +#define M16C_EF_FORME BIT(2)
> +#define M16C_EF_STFE BIT(3)
> +#define M16C_EF_BITE0 BIT(4)
> +#define M16C_EF_BITE1 BIT(5)
> +#define M16C_EF_RCVE BIT(6)
> +#define M16C_EF_TRE BIT(7)
> +
> +/* bittiming parameters */
> +#define KVASER_USB_TSEG1_MIN 1
> +#define KVASER_USB_TSEG1_MAX 16
> +#define KVASER_USB_TSEG2_MIN 1
> +#define KVASER_USB_TSEG2_MAX 8
> +#define KVASER_USB_SJW_MAX 4
> +#define KVASER_USB_BRP_MIN 1
> +#define KVASER_USB_BRP_MAX 64
> +#define KVASER_USB_BRP_INC 1
> +
> +/* ctrl modes */
> +#define KVASER_CTRL_MODE_NORMAL 1
> +#define KVASER_CTRL_MODE_SILENT 2
> +#define KVASER_CTRL_MODE_SELFRECEPTION 3
> +#define KVASER_CTRL_MODE_OFF 4
> +
> +struct kvaser_msg_simple {
> + u8 tid;
> + u8 channel;
> +} __packed;
> +
> +struct kvaser_msg_cardinfo {
> + u8 tid;
> + u8 nchannels;
> + __le32 serial_number;
> + __le32 padding;
> + __le32 clock_resolution;
> + __le32 mfgdate;
> + u8 ean[8];
> + u8 hw_revision;
> + u8 usb_hs_mode;
> + __le16 padding2;
> +} __packed;
> +
> +struct kvaser_msg_cardinfo2 {
> + u8 tid;
> + u8 channel;
> + u8 pcb_id[24];
> + __le32 oem_unlock_code;
> +} __packed;
> +
> +struct kvaser_msg_softinfo {
> + u8 tid;
> + u8 channel;
> + __le32 sw_options;
> + __le32 fw_version;
> + __le16 max_outstanding_tx;
> + __le16 padding[9];
> +} __packed;
> +
> +struct kvaser_msg_busparams {
> + u8 tid;
> + u8 channel;
> + __le32 bitrate;
> + u8 tseg1;
> + u8 tseg2;
> + u8 sjw;
> + u8 no_samp;
> +} __packed;
> +
> +struct kvaser_msg_tx_can {
> + u8 channel;
> + u8 tid;
> + u8 msg[14];
> + u8 padding;
> + u8 flags;
> +} __packed;
> +
> +struct kvaser_msg_rx_can {
> + u8 channel;
> + u8 flag;
> + __le16 time[3];
> + u8 msg[14];
> +} __packed;
> +
> +struct kvaser_msg_chip_state_event {
> + u8 tid;
> + u8 channel;
> + __le16 time[3];
> + u8 tx_errors_count;
> + u8 rx_errors_count;
> + u8 status;
> + u8 padding[3];
> +} __packed;
> +
> +struct kvaser_msg_tx_acknowledge {
> + u8 channel;
> + u8 tid;
> + __le16 time[3];
> + u8 flags;
> + u8 time_offset;
> +} __packed;
> +
> +struct kvaser_msg_error_event {
> + u8 tid;
> + u8 flags;
> + __le16 time[3];
> + u8 channel;
> + u8 padding;
> + u8 tx_errors_count;
> + u8 rx_errors_count;
> + u8 status;
> + u8 error_factor;
> +} __packed;
> +
> +struct kvaser_msg_ctrl_mode {
> + u8 tid;
> + u8 channel;
> + u8 ctrl_mode;
> + u8 padding[3];
> +} __packed;
> +
> +struct kvaser_msg_flush_queue {
> + u8 tid;
> + u8 channel;
> + u8 flags;
> + u8 padding[3];
> +} __packed;
> +
> +struct kvaser_msg_log_message {
> + u8 channel;
> + u8 flags;
> + __le16 time[3];
> + u8 dlc;
> + u8 time_offset;
> + __le32 id;
> + u8 data[8];
> +} __packed;
> +
> +struct kvaser_msg {
> + u8 len;
> + u8 id;
> + union {
> + struct kvaser_msg_simple simple;
> + struct kvaser_msg_cardinfo cardinfo;
> + struct kvaser_msg_cardinfo2 cardinfo2;
> + struct kvaser_msg_softinfo softinfo;
> + struct kvaser_msg_busparams busparams;
> + struct kvaser_msg_tx_can tx_can;
> + struct kvaser_msg_rx_can rx_can;
> + struct kvaser_msg_chip_state_event chip_state_event;
> + struct kvaser_msg_tx_acknowledge tx_acknowledge;
> + struct kvaser_msg_error_event error_event;
> + struct kvaser_msg_ctrl_mode ctrl_mode;
> + struct kvaser_msg_flush_queue flush_queue;
> + struct kvaser_msg_log_message log_message;
> + } u;
> +} __packed;
> +
> +struct kvaser_usb_tx_urb_context {
> + struct kvaser_usb_net_priv *priv;
> + u32 echo_index;
> + int dlc;
> +};
> +
> +struct kvaser_usb {
> + struct usb_device *udev;
> + struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
> +
> + struct usb_endpoint_descriptor *bulk_in, *bulk_out;
> + struct usb_anchor rx_submitted;
> +
> + u32 fw_version;
> + unsigned int nchannels;
> +
> + bool rxinitdone;
> + void *rxbuf[MAX_RX_URBS];
> + dma_addr_t rxbuf_dma[MAX_RX_URBS];
> +};
> +
> +struct kvaser_usb_net_priv {
> + struct can_priv can;
> +
> + atomic_t active_tx_urbs;
> + struct usb_anchor tx_submitted;
> + struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
> +
> + struct completion start_comp, stop_comp;
> +
> + struct kvaser_usb *dev;
> + struct net_device *netdev;
> + int channel;
> +
> + struct can_berr_counter bec;
> +};
> +
> +static struct usb_device_id kvaser_usb_table[] = {
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS |
> + KVASER_HAS_SILENT_MODE },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
> + .driver_info = KVASER_HAS_TXRX_ERRORS },
> + { }
> +};
> +MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
> +
> +static inline int kvaser_usb_send_msg(const struct kvaser_usb *dev,
> + struct kvaser_msg *msg)
> +{
> + int actual_len;
> +
> + return usb_bulk_msg(dev->udev,
> + usb_sndbulkpipe(dev->udev,
> + dev->bulk_out->bEndpointAddress),
> + msg, msg->len, &actual_len,
> + USB_SEND_TIMEOUT);
> +}
> +
> +static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
> + struct kvaser_msg *msg)
> +{
> + struct kvaser_msg *tmp;
> + void *buf;
> + int actual_len;
> + int err;
> + int pos = 0;
> +
> + buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + err = usb_bulk_msg(dev->udev,
> + usb_rcvbulkpipe(dev->udev,
> + dev->bulk_in->bEndpointAddress),
> + buf, RX_BUFFER_SIZE, &actual_len,
> + USB_RECV_TIMEOUT);
> + if (err < 0)
> + goto end;
> +
> + while (pos <= actual_len - MSG_HEADER_LEN) {
> + tmp = buf + pos;
> +
> + if (!tmp->len)
> + break;
> +
> + if (pos + tmp->len > actual_len) {
> + dev_err(dev->udev->dev.parent, "Format error\n");
> + break;
> + }
> +
> + if (tmp->id == id) {
> + memcpy(msg, tmp, tmp->len);
> + goto end;
> + }
> +
> + pos += tmp->len;
> + }
> +
> + err = -EINVAL;
> +
> +end:
> + kfree(buf);
> +
> + return err;
> +}
> +
> +static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev,
> + u8 msg_id, int channel)
> +{
> + struct kvaser_msg msg = {
> + .len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple),
> + .id = msg_id,
> + .u.simple.channel = channel,
> + .u.simple.tid = 0xff,
> + };
> +
> + return kvaser_usb_send_msg(dev, &msg);
> +}
> +
> +static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
> +{
> + struct kvaser_msg msg;
> + int err;
> +
> + err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0);
> + if (err)
> + return err;
> +
> + err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg);
> + if (err)
> + return err;
> +
> + dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
> +
> + return 0;
> +}
> +
> +static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
> +{
> + struct kvaser_msg msg;
> + int err;
> +
> + err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0);
> + if (err)
> + return err;
> +
> + err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg);
> + if (err)
> + return err;
> +
> + dev->nchannels = msg.u.cardinfo.nchannels;
> +
> + return 0;
> +}
> +
> +static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
> + const struct kvaser_msg *msg)
> +{
> + struct net_device_stats *stats;
> + struct kvaser_usb_tx_urb_context *context;
> + struct kvaser_usb_net_priv *priv;
> + struct sk_buff *skb;
> + struct can_frame *cf;
> + u8 channel = msg->u.tx_acknowledge.channel;
> + u8 tid = msg->u.tx_acknowledge.tid;
> +
> + if (channel >= dev->nchannels) {
> + dev_err(dev->udev->dev.parent,
> + "Invalid channel number (%d)\n", channel);
> + return;
> + }
> +
> + priv = dev->nets[channel];
> +
> + if (!netif_device_present(priv->netdev))
> + return;
> +
> + stats = &priv->netdev->stats;
> +
> + context = &priv->tx_contexts[tid % MAX_TX_URBS];
> +
> + /* Sometimes the state change doesn't come after a bus-off event */
> + if (priv->can.restart_ms &&
> + (priv->can.state >= CAN_STATE_BUS_OFF)) {
> + skb = alloc_can_err_skb(priv->netdev, &cf);
> + if (skb) {
> + cf->can_id |= CAN_ERR_RESTARTED;
> + netif_rx(skb);
> +
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> + } else {
> + netdev_err(priv->netdev,
> + "No memory left for err_skb\n");
> + }
> +
> + priv->can.can_stats.restarts++;
> + netif_carrier_on(priv->netdev);
> +
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + }
> +
> + stats->tx_packets++;
> + stats->tx_bytes += context->dlc;
> + can_get_echo_skb(priv->netdev, context->echo_index);
> +
> + context->echo_index = MAX_TX_URBS;
> + atomic_dec(&priv->active_tx_urbs);
> +
> + netif_wake_queue(priv->netdev);
> +}
> +
> +static void kvaser_usb_simple_msg_callback(struct urb *urb)
> +{
> + struct net_device *netdev = urb->context;
> +
> + kfree(urb->transfer_buffer);
> +
> + if (urb->status)
> + netdev_warn(netdev, "urb status received: %d\n",
> + urb->status);
> +}
> +
> +static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
> + u8 msg_id)
> +{
> + struct kvaser_usb *dev = priv->dev;
> + struct net_device *netdev = priv->netdev;
> + struct kvaser_msg *msg;
> + struct urb *urb;
> + void *buf;
> + int err;
> +
> + urb = usb_alloc_urb(0, GFP_ATOMIC);
> + if (!urb) {
> + netdev_err(netdev, "No memory left for URBs\n");
> + return -ENOMEM;
> + }
> +
> + buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
> + if (!buf) {
> + netdev_err(netdev, "No memory left for USB buffer\n");
> + usb_free_urb(urb);
> + return -ENOMEM;
> + }
> +
> + msg = (struct kvaser_msg *)buf;
> + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple);
> + msg->id = msg_id;
> + msg->u.simple.channel = priv->channel;
> +
> + usb_fill_bulk_urb(urb, dev->udev,
> + usb_sndbulkpipe(dev->udev,
> + dev->bulk_out->bEndpointAddress),
> + buf, msg->len,
> + kvaser_usb_simple_msg_callback, priv);
> + usb_anchor_urb(urb, &priv->tx_submitted);
> +
> + err = usb_submit_urb(urb, GFP_ATOMIC);
> + if (err) {
> + netdev_err(netdev, "Error transmitting URB\n");
> + usb_unanchor_urb(urb);
> + usb_free_urb(urb);
> + kfree(buf);
> + return err;
> + }
> +
> + usb_free_urb(urb);
> +
> + return 0;
> +}
> +
> +static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
> +{
> + int i;
> +
> + usb_kill_anchored_urbs(&priv->tx_submitted);
> + atomic_set(&priv->active_tx_urbs, 0);
> +
> + for (i = 0; i < MAX_TX_URBS; i++)
> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> +}
> +
> +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> + const struct kvaser_msg *msg)
> +{
> + struct can_frame *cf;
> + struct sk_buff *skb;
> + struct net_device_stats *stats;
> + struct kvaser_usb_net_priv *priv;
> + unsigned int new_state;
> + u8 channel, status, txerr, rxerr, error_factor;
> +
> + switch (msg->id) {
> + case CMD_CAN_ERROR_EVENT:
> + channel = msg->u.error_event.channel;
> + status = msg->u.error_event.status;
> + txerr = msg->u.error_event.tx_errors_count;
> + rxerr = msg->u.error_event.rx_errors_count;
> + error_factor = msg->u.error_event.error_factor;
> + break;
> + case CMD_LOG_MESSAGE:
> + channel = msg->u.log_message.channel;
> + status = msg->u.log_message.data[0];
> + txerr = msg->u.log_message.data[2];
> + rxerr = msg->u.log_message.data[3];
> + error_factor = msg->u.log_message.data[1];
> + break;
> + case CMD_CHIP_STATE_EVENT:
> + channel = msg->u.chip_state_event.channel;
> + status = msg->u.chip_state_event.status;
> + txerr = msg->u.chip_state_event.tx_errors_count;
> + rxerr = msg->u.chip_state_event.rx_errors_count;
> + error_factor = 0;
> + break;
> + default:
> + dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
> + msg->id);
> + return;
> + }
> +
> + if (channel >= dev->nchannels) {
> + dev_err(dev->udev->dev.parent,
> + "Invalid channel number (%d)\n", channel);
> + return;
> + }
> +
> + priv = dev->nets[channel];
> + stats = &priv->netdev->stats;
> +
> + if (status & M16C_STATE_BUS_RESET) {
> + kvaser_usb_unlink_tx_urbs(priv);
> + return;
> + }
> +
> + skb = alloc_can_err_skb(priv->netdev, &cf);
> + if (!skb) {
> + stats->rx_dropped++;
> + return;
> + }
> +
> + new_state = priv->can.state;
> +
> + netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
> +
> + if (status & M16C_STATE_BUS_OFF) {
> + cf->can_id |= CAN_ERR_BUSOFF;
> +
> + priv->can.can_stats.bus_off++;
> + if (!priv->can.restart_ms)
> + kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP);
> +
> + netif_carrier_off(priv->netdev);
> +
> + new_state = CAN_STATE_BUS_OFF;
> + } else if (status & M16C_STATE_BUS_PASSIVE) {
> + if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
> + cf->can_id |= CAN_ERR_CRTL;
> +
> + if (txerr || rxerr)
> + cf->data[1] = (txerr > rxerr)
> + ? CAN_ERR_CRTL_TX_PASSIVE
> + : CAN_ERR_CRTL_RX_PASSIVE;
> + else
> + cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE |
> + CAN_ERR_CRTL_RX_PASSIVE;
> +
> + priv->can.can_stats.error_passive++;
> + }
> +
> + new_state = CAN_STATE_ERROR_PASSIVE;
> + }
> +
> + if (status == M16C_STATE_BUS_ERROR) {
> + if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
> + ((txerr >= 96) || (rxerr >= 96))) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] = (txerr > rxerr)
> + ? CAN_ERR_CRTL_TX_WARNING
> + : CAN_ERR_CRTL_RX_WARNING;
> +
> + priv->can.can_stats.error_warning++;
> + new_state = CAN_STATE_ERROR_WARNING;
> + } else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) {
> + cf->can_id |= CAN_ERR_PROT;
> + cf->data[2] = CAN_ERR_PROT_ACTIVE;
> +
> + new_state = CAN_STATE_ERROR_ACTIVE;
> + }
> + }
> +
> + if (!status) {
> + cf->can_id |= CAN_ERR_PROT;
> + cf->data[2] = CAN_ERR_PROT_ACTIVE;
> +
> + new_state = CAN_STATE_ERROR_ACTIVE;
> + }
> +
> + if (priv->can.restart_ms &&
> + (priv->can.state >= CAN_STATE_BUS_OFF) &&
> + (new_state < CAN_STATE_BUS_OFF)) {
> + cf->can_id |= CAN_ERR_RESTARTED;
> + netif_carrier_on(priv->netdev);
> +
> + priv->can.can_stats.restarts++;
> + }
> +
> + if (error_factor) {
> + priv->can.can_stats.bus_error++;
> + stats->rx_errors++;
> +
> + cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
> +
> + if (error_factor & M16C_EF_ACKE)
> + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
> + if (error_factor & M16C_EF_CRCE)
> + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> + CAN_ERR_PROT_LOC_CRC_DEL);
> + if (error_factor & M16C_EF_FORME)
> + cf->data[2] |= CAN_ERR_PROT_FORM;
> + if (error_factor & M16C_EF_STFE)
> + cf->data[2] |= CAN_ERR_PROT_STUFF;
> + if (error_factor & M16C_EF_BITE0)
> + cf->data[2] |= CAN_ERR_PROT_BIT0;
> + if (error_factor & M16C_EF_BITE1)
> + cf->data[2] |= CAN_ERR_PROT_BIT1;
> + if (error_factor & M16C_EF_TRE)
> + cf->data[2] |= CAN_ERR_PROT_TX;
> + }
> +
> + cf->data[6] = txerr;
> + cf->data[7] = rxerr;
> +
> + priv->bec.txerr = txerr;
> + priv->bec.rxerr = rxerr;
> +
> + priv->can.state = new_state;
> +
> + netif_rx(skb);
> +
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> +}
> +
> +static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
> + const struct kvaser_msg *msg)
> +{
> + struct can_frame *cf;
> + struct sk_buff *skb;
> + struct net_device_stats *stats = &priv->netdev->stats;
> +
> + if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
> + MSG_FLAG_NERR)) {
> + netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
> + msg->u.rx_can.flag);
> +
> + stats->rx_errors++;
> + return;
> + }
> +
> + if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
> + skb = alloc_can_err_skb(priv->netdev, &cf);
> + if (!skb) {
> + stats->tx_dropped++;
Should be rx, as we are in the rx function.
> + return;
> + }
> +
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
> +
> + stats->rx_over_errors++;
> + stats->rx_errors++;
> +
> + netif_rx(skb);
> +
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> + }
> +}
> +
> +static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
> + const struct kvaser_msg *msg)
> +{
> + struct kvaser_usb_net_priv *priv;
> + struct can_frame *cf;
> + struct sk_buff *skb;
> + struct net_device_stats *stats;
> + u8 channel = msg->u.rx_can.channel;
> +
> + if (channel >= dev->nchannels) {
> + dev_err(dev->udev->dev.parent,
> + "Invalid channel number (%d)\n", channel);
> + return;
> + }
> +
> + priv = dev->nets[channel];
> + stats = &priv->netdev->stats;
> +
> + if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | MSG_FLAG_NERR |
> + MSG_FLAG_OVERRUN)) {
> + kvaser_usb_rx_can_err(priv, msg);
> + return;
> + } else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
> + netdev_warn(priv->netdev,
> + "Unhandled frame (flags: 0x%02x)",
> + msg->u.rx_can.flag);
> + return;
> + }
> +
> + skb = alloc_can_skb(priv->netdev, &cf);
> + if (!skb) {
> + stats->tx_dropped++;
> + return;
> + }
> +
> + cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
> + (msg->u.rx_can.msg[1] & 0x3f);
> + cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
> +
> + if (msg->id == CMD_RX_EXT_MESSAGE) {
> + cf->can_id <<= 18;
> + cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
> + ((msg->u.rx_can.msg[3] & 0xff) << 6) |
> + (msg->u.rx_can.msg[4] & 0x3f);
> + cf->can_id |= CAN_EFF_FLAG;
> + }
> +
> + if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
> + cf->can_id |= CAN_RTR_FLAG;
> + else
> + memcpy(cf->data, &msg->u.rx_can.msg[6], cf->can_dlc);
> +
> + netif_rx(skb);
> +
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> +}
> +
> +static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
> + const struct kvaser_msg *msg)
> +{
> + struct kvaser_usb_net_priv *priv;
> + u8 channel = msg->u.simple.channel;
> +
> + if (channel >= dev->nchannels) {
> + dev_err(dev->udev->dev.parent,
> + "Invalid channel number (%d)\n", channel);
> + return;
> + }
> +
> + priv = dev->nets[channel];
> +
> + if (completion_done(&priv->start_comp) &&
> + netif_queue_stopped(priv->netdev)) {
> + netif_wake_queue(priv->netdev);
> + } else {
> + netif_start_queue(priv->netdev);
> + complete(&priv->start_comp);
> + }
> +}
> +
> +static void kvaser_usb_stop_chip_reply(const struct kvaser_usb *dev,
> + const struct kvaser_msg *msg)
> +{
> + struct kvaser_usb_net_priv *priv;
> + u8 channel = msg->u.simple.channel;
> +
> + if (channel >= dev->nchannels) {
> + dev_err(dev->udev->dev.parent,
> + "Invalid channel number (%d)\n", channel);
> + return;
> + }
> +
> + priv = dev->nets[channel];
> +
> + complete(&priv->stop_comp);
> +}
> +
> +static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
> + const struct kvaser_msg *msg)
> +{
> + switch (msg->id) {
> + case CMD_START_CHIP_REPLY:
> + kvaser_usb_start_chip_reply(dev, msg);
> + break;
> +
> + case CMD_STOP_CHIP_REPLY:
> + kvaser_usb_stop_chip_reply(dev, msg);
> + break;
> +
> + case CMD_RX_STD_MESSAGE:
> + case CMD_RX_EXT_MESSAGE:
> + kvaser_usb_rx_can_msg(dev, msg);
> + break;
> +
> + case CMD_CHIP_STATE_EVENT:
> + case CMD_CAN_ERROR_EVENT:
> + kvaser_usb_rx_error(dev, msg);
> + break;
> +
> + case CMD_LOG_MESSAGE:
> + if (msg->u.log_message.flags & MSG_FLAG_ERROR_FRAME)
> + kvaser_usb_rx_error(dev, msg);
> + break;
> +
> + case CMD_TX_ACKNOWLEDGE:
> + kvaser_usb_tx_acknowledge(dev, msg);
> + break;
> +
> + default:
> + dev_warn(dev->udev->dev.parent,
> + "Unhandled message (%d)\n", msg->id);
> + break;
> + }
> +}
> +
> +static void kvaser_usb_read_bulk_callback(struct urb *urb)
> +{
> + struct kvaser_usb *dev = urb->context;
> + struct kvaser_msg *msg;
> + int pos = 0;
> + int err, i;
> +
> + switch (urb->status) {
> + case 0:
> + break;
> + case -ENOENT:
> + case -ESHUTDOWN:
> + return;
> + default:
> + dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n",
> + urb->status);
> + goto resubmit_urb;
> + }
> +
> + while (pos <= urb->actual_length - MSG_HEADER_LEN) {
> + msg = urb->transfer_buffer + pos;
> +
> + if (!msg->len)
> + break;
> +
> + if (pos + msg->len > urb->actual_length) {
> + dev_err(dev->udev->dev.parent, "Format error\n");
> + break;
> + }
> +
> + kvaser_usb_handle_message(dev, msg);
> +
> + pos += msg->len;
> + }
> +
> +resubmit_urb:
> + usb_fill_bulk_urb(urb, dev->udev,
> + usb_rcvbulkpipe(dev->udev,
> + dev->bulk_in->bEndpointAddress),
> + urb->transfer_buffer, RX_BUFFER_SIZE,
> + kvaser_usb_read_bulk_callback, dev);
> +
> + err = usb_submit_urb(urb, GFP_ATOMIC);
> + if (err == -ENODEV) {
> + for (i = 0; i < dev->nchannels; i++) {
> + if (!dev->nets[i])
> + continue;
> +
> + netif_device_detach(dev->nets[i]->netdev);
> + }
> + } else if (err) {
> + dev_err(dev->udev->dev.parent,
> + "Failed resubmitting read bulk urb: %d\n", err);
> + }
> +
> + return;
> +}
> +
> +static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
> +{
> + int i, err = 0;
> +
> + if (dev->rxinitdone)
> + return 0;
> +
> + for (i = 0; i < MAX_RX_URBS; i++) {
> + struct urb *urb = NULL;
> + u8 *buf = NULL;
> + dma_addr_t buf_dma;
> +
> + urb = usb_alloc_urb(0, GFP_KERNEL);
> + if (!urb) {
> + dev_warn(dev->udev->dev.parent,
> + "No memory left for URBs\n");
> + err = -ENOMEM;
> + break;
> + }
> +
> + buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE,
> + GFP_KERNEL, &buf_dma);
> + if (!buf) {
> + dev_warn(dev->udev->dev.parent,
> + "No memory left for USB buffer\n");
> + usb_free_urb(urb);
> + err = -ENOMEM;
> + break;
> + }
> +
> + usb_fill_bulk_urb(urb, dev->udev,
> + usb_rcvbulkpipe(dev->udev,
> + dev->bulk_in->bEndpointAddress),
> + buf, RX_BUFFER_SIZE,
> + kvaser_usb_read_bulk_callback,
> + dev);
> + urb->transfer_dma = buf_dma;
> + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> + usb_anchor_urb(urb, &dev->rx_submitted);
> +
> + err = usb_submit_urb(urb, GFP_KERNEL);
> + if (err) {
> + usb_unanchor_urb(urb);
> + usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
> + buf_dma);
> + usb_free_urb(urb);
> + break;
> + }
> +
> + dev->rxbuf[i] = buf;
> + dev->rxbuf_dma[i] = buf_dma;
> +
> + usb_free_urb(urb);
> + }
> +
> + if (i == 0) {
> + dev_warn(dev->udev->dev.parent,
> + "Cannot setup read URBs, error %d\n", err);
> + return err;
> + } else if (i < MAX_RX_URBS) {
> + dev_warn(dev->udev->dev.parent,
> + "RX performances may be slow\n");
> + }
> +
> + dev->rxinitdone = true;
> +
> + return 0;
> +}
> +
> +static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv)
> +{
> + struct kvaser_msg msg = {
> + .id = CMD_SET_CTRL_MODE,
> + .len = MSG_HEADER_LEN +
> + sizeof(struct kvaser_msg_ctrl_mode),
> + .u.ctrl_mode.tid = 0xff,
> + .u.ctrl_mode.channel = priv->channel,
> + };
> +
> + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
> + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT;
> + else
> + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL;
> +
> + return kvaser_usb_send_msg(priv->dev, &msg);
> +}
> +
> +static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv)
> +{
> + int err;
> +
> + init_completion(&priv->start_comp);
> +
> + err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP,
> + priv->channel);
> + if (err)
> + return err;
> +
> + if (!wait_for_completion_timeout(&priv->start_comp,
> + msecs_to_jiffies(START_TIMEOUT)))
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static int kvaser_usb_open(struct net_device *netdev)
> +{
> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> + struct kvaser_usb *dev = priv->dev;
> + int err;
> +
> + err = open_candev(netdev);
> + if (err)
> + return err;
> +
> + err = kvaser_usb_setup_rx_urbs(dev);
> + if (err)
> + goto error;
> +
> + err = kvaser_usb_set_opt_mode(priv);
> + if (err)
> + goto error;
> +
> + err = kvaser_usb_start_chip(priv);
> + if (err) {
> + netdev_warn(netdev, "Cannot start device, error %d\n", err);
> + goto error;
> + }
> +
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> + return 0;
> +
> +error:
> + close_candev(netdev);
> + return err;
> +}
> +
> +static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
> +{
> + int i;
> +
> + usb_kill_anchored_urbs(&dev->rx_submitted);
> +
> + for (i = 0; i < MAX_RX_URBS; i++)
> + usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
> + dev->rxbuf[i],
> + dev->rxbuf_dma[i]);
> +
> + for (i = 0; i < MAX_NET_DEVICES; i++) {
> + struct kvaser_usb_net_priv *priv = dev->nets[i];
> +
> + if (priv)
> + kvaser_usb_unlink_tx_urbs(priv);
> + }
> +}
> +
> +static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv)
> +{
> + int err;
> +
> + init_completion(&priv->stop_comp);
> +
> + err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP,
> + priv->channel);
> + if (err)
> + return err;
> +
> + if (!wait_for_completion_timeout(&priv->stop_comp,
> + msecs_to_jiffies(STOP_TIMEOUT)))
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv)
> +{
> + struct kvaser_msg msg = {
> + .id = CMD_FLUSH_QUEUE,
> + .len = MSG_HEADER_LEN +
> + sizeof(struct kvaser_msg_flush_queue),
> + .u.flush_queue.channel = priv->channel,
> + .u.flush_queue.flags = 0x00,
> + };
> +
> + return kvaser_usb_send_msg(priv->dev, &msg);
> +}
> +
> +static int kvaser_usb_close(struct net_device *netdev)
> +{
> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> + struct kvaser_usb *dev = priv->dev;
> + int err;
> +
> + netif_stop_queue(netdev);
> +
> + err = kvaser_usb_flush_queue(priv);
> + if (err)
> + netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
> +
> + if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel))
> + netdev_warn(netdev, "Cannot reset card, error %d\n", err);
> +
> + err = kvaser_usb_stop_chip(priv);
> + if (err)
> + netdev_warn(netdev, "Cannot stop device, error %d\n", err);
> +
> + priv->can.state = CAN_STATE_STOPPED;
> + close_candev(priv->netdev);
> +
> + return 0;
> +}
> +
> +static void kvaser_usb_write_bulk_callback(struct urb *urb)
> +{
> + struct kvaser_usb_tx_urb_context *context = urb->context;
> + struct kvaser_usb_net_priv *priv;
> + struct net_device *netdev;
> +
> + if (WARN_ON(!context))
> + return;
> +
> + priv = context->priv;
> + netdev = priv->netdev;
> +
> + kfree(urb->transfer_buffer);
> +
> + if (!netif_device_present(netdev))
> + return;
> +
> + if (urb->status)
> + netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
> +}
> +
> +static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> + struct net_device *netdev)
> +{
> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> + struct kvaser_usb *dev = priv->dev;
> + struct net_device_stats *stats = &netdev->stats;
> + struct can_frame *cf = (struct can_frame *)skb->data;
> + struct kvaser_usb_tx_urb_context *context = NULL;
> + struct urb *urb;
> + void *buf;
> + struct kvaser_msg *msg;
> + int i, err;
> + int ret = NETDEV_TX_OK;
> +
> + if (can_dropped_invalid_skb(netdev, skb))
> + return NETDEV_TX_OK;
> +
> + urb = usb_alloc_urb(0, GFP_ATOMIC);
> + if (!urb) {
> + netdev_err(netdev, "No memory left for URBs\n");
> + stats->tx_dropped++;
Move the dev_kfree_skb to the end and goto there.
> + dev_kfree_skb(skb);
> + return NETDEV_TX_OK;
> + }
> +
> + buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
> + if (!buf) {
> + netdev_err(netdev, "No memory left for USB buffer\n");
> + stats->tx_dropped++;
You cann usb_free_urb twice...here and in the error handling at the end.
> + dev_kfree_skb(skb);
> + usb_free_urb(urb);
> + goto nobufmem;
> + }
> +
> + msg = buf;
> + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
> + msg->u.tx_can.flags = 0;
> + msg->u.tx_can.channel = priv->channel;
> +
> + if (cf->can_id & CAN_EFF_FLAG) {
> + msg->id = CMD_TX_EXT_MESSAGE;
> + msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
> + msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f;
> + msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f;
> + msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff;
> + msg->u.tx_can.msg[4] = cf->can_id & 0x3f;
> + } else {
> + msg->id = CMD_TX_STD_MESSAGE;
> + msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f;
> + msg->u.tx_can.msg[1] = cf->can_id & 0x3f;
> + }
> +
> + msg->u.tx_can.msg[5] = cf->can_dlc;
> + memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
> +
> + if (cf->can_id & CAN_RTR_FLAG)
> + msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
> +
> + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
> + if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
> + context = &priv->tx_contexts[i];
> + break;
> + }
> + }
> +
> + if (!context) {
> + netdev_warn(netdev, "cannot find free context\n");
> + ret = NETDEV_TX_BUSY;
> + goto releasebuf;
> + }
> +
> + context->priv = priv;
> + context->echo_index = i;
> + context->dlc = cf->can_dlc;
> +
> + msg->u.tx_can.tid = context->echo_index;
> +
> + usb_fill_bulk_urb(urb, dev->udev,
> + usb_sndbulkpipe(dev->udev,
> + dev->bulk_out->bEndpointAddress),
> + buf, msg->len,
> + kvaser_usb_write_bulk_callback, context);
> + usb_anchor_urb(urb, &priv->tx_submitted);
> +
> + can_put_echo_skb(skb, netdev, context->echo_index);
> +
> + atomic_inc(&priv->active_tx_urbs);
> +
> + if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
> + netif_stop_queue(netdev);
> +
> + err = usb_submit_urb(urb, GFP_ATOMIC);
> + if (unlikely(err)) {
> + can_free_echo_skb(netdev, context->echo_index);
> +
> + atomic_dec(&priv->active_tx_urbs);
> + usb_unanchor_urb(urb);
> +
> + stats->tx_dropped++;
> +
> + if (err == -ENODEV)
> + netif_device_detach(netdev);
> + else
> + netdev_warn(netdev, "Failed tx_urb %d\n", err);
> +
> + goto releasebuf;
> + }
> +
> + usb_free_urb(urb);
> +
> + return NETDEV_TX_OK;
> +
> +releasebuf:
> + kfree(buf);
> +nobufmem:
> + usb_free_urb(urb);
> + return ret;
> +}
> +
> +static const struct net_device_ops kvaser_usb_netdev_ops = {
> + .ndo_open = kvaser_usb_open,
> + .ndo_stop = kvaser_usb_close,
> + .ndo_start_xmit = kvaser_usb_start_xmit,
> +};
> +
> +static struct can_bittiming_const kvaser_usb_bittiming_const = {
> + .name = "kvaser_usb",
> + .tseg1_min = KVASER_USB_TSEG1_MIN,
> + .tseg1_max = KVASER_USB_TSEG1_MAX,
> + .tseg2_min = KVASER_USB_TSEG2_MIN,
> + .tseg2_max = KVASER_USB_TSEG2_MAX,
> + .sjw_max = KVASER_USB_SJW_MAX,
> + .brp_min = KVASER_USB_BRP_MIN,
> + .brp_max = KVASER_USB_BRP_MAX,
> + .brp_inc = KVASER_USB_BRP_INC,
> +};
> +
> +static int kvaser_usb_set_bittiming(struct net_device *netdev)
> +{
> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> + struct can_bittiming *bt = &priv->can.bittiming;
> + struct kvaser_usb *dev = priv->dev;
> + struct kvaser_msg msg = {
> + .id = CMD_SET_BUS_PARAMS,
> + .len = MSG_HEADER_LEN +
> + sizeof(struct kvaser_msg_busparams),
> + .u.busparams.channel = priv->channel,
> + .u.busparams.tid = 0xff,
> + .u.busparams.bitrate = cpu_to_le32(bt->bitrate),
> + .u.busparams.sjw = bt->sjw,
> + .u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1,
> + .u.busparams.tseg2 = bt->phase_seg2,
> + };
> +
> + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
> + msg.u.busparams.no_samp = 3;
> + else
> + msg.u.busparams.no_samp = 1;
> +
> + return kvaser_usb_send_msg(dev, &msg);
> +}
> +
> +static int kvaser_usb_set_mode(struct net_device *netdev,
> + enum can_mode mode)
> +{
> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> + int err;
> +
> + switch (mode) {
> + case CAN_MODE_START:
> + err = kvaser_usb_simple_msg_async(priv, CMD_START_CHIP);
> + if (err)
> + return err;
> + break;
> + default:
> + return -EOPNOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static int kvaser_usb_get_berr_counter(const struct net_device *netdev,
> + struct can_berr_counter *bec)
> +{
> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> +
> + *bec = priv->bec;
> +
> + return 0;
> +}
> +
> +static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
> +{
> + int i;
> +
> + for (i = 0; i < dev->nchannels; i++) {
> + if (!dev->nets[i])
> + continue;
> +
> + unregister_netdev(dev->nets[i]->netdev);
> + }
> +
> + kvaser_usb_unlink_all_urbs(dev);
> +
> + for (i = 0; i < dev->nchannels; i++) {
> + if (!dev->nets[i])
> + continue;
> +
> + free_candev(dev->nets[i]->netdev);
> + }
> +}
> +
> +static int kvaser_usb_init_one(struct usb_interface *intf,
> + const struct usb_device_id *id, int channel)
> +{
> + struct kvaser_usb *dev = usb_get_intfdata(intf);
> + struct net_device *netdev;
> + struct kvaser_usb_net_priv *priv;
> + int i, err;
> +
> + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
> + if (!netdev) {
> + dev_err(&intf->dev, "Cannot alloc candev\n");
> + return -ENOMEM;
> + }
> +
> + priv = netdev_priv(netdev);
> +
> + init_completion(&priv->start_comp);
> + init_completion(&priv->stop_comp);
> +
> + init_usb_anchor(&priv->tx_submitted);
> + atomic_set(&priv->active_tx_urbs, 0);
> +
> + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> +
> + priv->dev = dev;
> + priv->netdev = netdev;
> + priv->channel = channel;
> +
> + priv->can.state = CAN_STATE_STOPPED;
> + priv->can.clock.freq = CAN_USB_CLOCK;
> + priv->can.bittiming_const = &kvaser_usb_bittiming_const;
> + priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
> + priv->can.do_set_mode = kvaser_usb_set_mode;
> + if (id->driver_info & KVASER_HAS_TXRX_ERRORS)
> + priv->can.do_get_berr_counter = kvaser_usb_get_berr_counter;
> + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
> + if (id->driver_info & KVASER_HAS_SILENT_MODE)
> + priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
> +
> + netdev->flags |= IFF_ECHO;
> +
> + netdev->netdev_ops = &kvaser_usb_netdev_ops;
> +
> + SET_NETDEV_DEV(netdev, &intf->dev);
> +
> + dev->nets[channel] = priv;
> +
> + err = register_candev(netdev);
> + if (err) {
> + dev_err(&intf->dev, "Failed to register can device\n");
> + free_candev(netdev);
> + dev->nets[channel] = NULL;
> + return err;
> + }
> +
> + netdev_dbg(netdev, "device registered\n");
> +
> + return 0;
> +}
> +
> +static void kvaser_usb_get_endpoints(const struct usb_interface *intf,
> + struct usb_endpoint_descriptor **in,
> + struct usb_endpoint_descriptor **out)
> +{
> + const struct usb_host_interface *iface_desc;
> + struct usb_endpoint_descriptor *endpoint;
> + int i;
> +
> + iface_desc = &intf->altsetting[0];
> +
> + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
> + endpoint = &iface_desc->endpoint[i].desc;
> +
> + if (usb_endpoint_is_bulk_in(endpoint))
> + *in = endpoint;
> +
> + if (usb_endpoint_is_bulk_out(endpoint))
> + *out = endpoint;
> + }
> +}
> +
> +static int kvaser_usb_probe(struct usb_interface *intf,
> + const struct usb_device_id *id)
> +{
> + struct kvaser_usb *dev;
> + int err = -ENOMEM;
> + int i;
> +
> + dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
> + if (!dev)
> + return -ENOMEM;
> +
> + kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
> + if (!dev->bulk_in || !dev->bulk_out) {
> + dev_err(&intf->dev, "Cannot get usb endpoint(s)");
> + return err;
> + }
> +
> + dev->udev = interface_to_usbdev(intf);
> +
> + init_usb_anchor(&dev->rx_submitted);
> +
> + usb_set_intfdata(intf, dev);
> +
> + for (i = 0; i < MAX_NET_DEVICES; i++)
> + kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
> +
> + err = kvaser_usb_get_software_info(dev);
> + if (err) {
> + dev_err(&intf->dev,
> + "Cannot get software infos, error %d\n", err);
> + return err;
> + }
> +
> + err = kvaser_usb_get_card_info(dev);
> + if (err) {
> + dev_err(&intf->dev,
> + "Cannot get card infos, error %d\n", err);
> + return err;
> + }
> +
> + dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
> + ((dev->fw_version >> 24) & 0xff),
> + ((dev->fw_version >> 16) & 0xff),
> + (dev->fw_version & 0xffff));
> +
> + for (i = 0; i < dev->nchannels; i++) {
> + err = kvaser_usb_init_one(intf, id, i);
> + if (err) {
> + kvaser_usb_remove_interfaces(dev);
> + return err;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void kvaser_usb_disconnect(struct usb_interface *intf)
> +{
> + struct kvaser_usb *dev = usb_get_intfdata(intf);
> +
> + usb_set_intfdata(intf, NULL);
> +
> + if (!dev)
> + return;
> +
> + kvaser_usb_remove_interfaces(dev);
> +}
> +
> +static struct usb_driver kvaser_usb_driver = {
> + .name = "kvaser_usb",
> + .probe = kvaser_usb_probe,
> + .disconnect = kvaser_usb_disconnect,
> + .id_table = kvaser_usb_table
^^^
nitpick, please add a "," there.
> +};
>
can you please add MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
> +module_usb_driver(kvaser_usb_driver);
> +
> +MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
> +MODULE_DESCRIPTION("CAN driver for Kvaser CAN/USB devices");
> +MODULE_LICENSE("GPL v2");
>
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]
^ permalink raw reply
* Re: Optics (SFP) monitoring on ixgbe and igbe
From: Ben Hutchings @ 2012-11-07 19:58 UTC (permalink / raw)
To: footplus; +Cc: netdev
In-Reply-To: <CAPN4dA8WUdox2k_F_9cYw=hR=xZHia=z3CXwy-36_t9Hh58zBg@mail.gmail.com>
On Wed, 2012-11-07 at 13:27 +0100, Aurélien wrote:
> Hello,
>
> I'm looking to propose a patch for optics monitoring on igbe and ixgbe
> cards which support SFP and SFP+. I have one of each card. While
> searching for previous work done by others on this domain, i found the
> following:
>
> https://github.com/jelaas/bifrost-build-x86_64/tree/master/all/kernel-x86_64-3.3.0-rc2-1
> (the DOM-* files)
>
> I did not yet test this patch (i'll do in a few days), but just by
> looking at the patches, do you think this could get incorporated in
> the current state, provided some administrative work is done, or would
> it require more architectural rework / documentation / other ?
>
> Could you point me to the next steps required for the functionality to
> be merged in a future mainline kernel/ethtool ? Is there a better
> place than netdev@ to discuss this matter ?
We just added the ETHTOOL_GMODULEINFO and ETHTOOL_GMODULEEEPROM
interface for this purpose. The diagnostics obviously aren't really an
EEPROM but I don't think that matters.
These drivers should report a type of ETH_MODULE_SFF_8472 (assuming a
module is present) and expose an 'EEPROM' with the real EEPROM in the
first 256 bytes and the diagnostic registers in the next 256 bytes.
Decoding of the diagnostic registers can be done in ethtool itself.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH 1/1] isdn: Make CONFIG_ISDN depend on CONFIG_NETDEVICES
From: David Miller @ 2012-11-07 19:42 UTC (permalink / raw)
To: alan; +Cc: lee.jones, linux-kernel, isdn, netdev
In-Reply-To: <20121107150436.3d25ee51@pyramind.ukuu.org.uk>
From: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date: Wed, 7 Nov 2012 15:04:36 +0000
> On Wed, 7 Nov 2012 10:55:03 +0100
> Lee Jones <lee.jones@linaro.org> wrote:
>
>> It doesn't make much sense to enable ISDN services if you don't
>> intend to connect to a network.
>
> I would disagree. However what I don't understand and you've not
> explained is why the current code is a bug or a problem ?
>
> This seems to be a make-work inconvenience causing patch that serves no
> useful purpose ?
The ISDN drivers are peppered with CONFIG_NETDEVICES protection,
but there are missing cases in several locations.
This is ugly, and causes build problems, so adding the dependency
is the cleanest and most correct soluation and I fully intend
to apply this patch.
^ permalink raw reply
* Re: [PATCH] tcp: Avoid infinite loop on recvmsg bug
From: Eric Dumazet @ 2012-11-07 19:40 UTC (permalink / raw)
To: Julius Werner
Cc: linux-kernel, netdev, Patrick McHardy, Hideaki YOSHIFUJI,
James Morris, Alexey Kuznetsov, David S. Miller, Dave Jones,
Sameer Nanda, Mandeep Singh Baines
In-Reply-To: <1352316791-16491-1-git-send-email-jwerner@chromium.org>
On Wed, 2012-11-07 at 11:33 -0800, Julius Werner wrote:
> tcp_recvmsg contains a sanity check that WARNs when there is a gap
> between the socket's copied_seq and the first buffer in the
> sk_receive_queue. In theory, the TCP stack makes sure that This Should
> Never Happen (TM)... however, practice shows that there are still a few
> bug reports from it out there (and one in my inbox).
>
> Unfortunately, when it does happen for whatever reason, the situation
> is not handled very well: the kernel logs a warning and breaks out of
> the loop that walks the receive queue. It proceeds to find nothing else
> to do on the socket and hits sk_wait_data, which cannot block because
> the receive queue is not empty. As no data was read, the outer while
> loop repeats (logging the same warning again) ad infinitum until the
> system's syslog exhausts all available hard drive capacity.
>
> This patch addresses that issue by closing the socket outright and
> throwing EBADFD to userspace (which seems most appropriate to me at this
> point). As the underlying bug condition is "impossible" and therefore by
> definition unrecoverable, this is the only sensible action other than a
> full panic.
>
> Signed-off-by: Julius Werner <jwerner@chromium.org>
> ---
> net/ipv4/tcp.c | 7 ++++++-
> 1 files changed, 6 insertions(+), 1 deletions(-)
>
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 197c000..d612308 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -1628,7 +1628,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
> "recvmsg bug: copied %X seq %X rcvnxt %X fl %X\n",
> *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt,
> flags))
> - break;
> + goto selfdestruct;
>
> offset = *seq - TCP_SKB_CB(skb)->seq;
> if (tcp_hdr(skb)->syn)
> @@ -1936,6 +1936,11 @@ recv_urg:
> recv_sndq:
> err = tcp_peek_sndq(sk, msg, len);
> goto out;
> +
> +selfdestruct:
> + err = -EBADFD;
> + tcp_done(sk);
> + goto out;
> }
> EXPORT_SYMBOL(tcp_recvmsg);
>
What I find very sad in all this is that you didnt mention the driver
that was triggering this bug.
So instead of making real progress, we are discussing of some dubious
'fixes'
^ permalink raw reply
* [PATCH] tcp: Avoid infinite loop on recvmsg bug
From: Julius Werner @ 2012-11-07 19:33 UTC (permalink / raw)
To: linux-kernel
Cc: netdev, Patrick McHardy, Hideaki YOSHIFUJI, James Morris,
Alexey Kuznetsov, David S. Miller, Eric Dumazet, Dave Jones,
Sameer Nanda, Mandeep Singh Baines, Julius Werner
In-Reply-To: <CAODwPW9kiG-jo=n0zedv5KT-8-gJcEUrdC3F2mAEjt78tne18g@mail.gmail.com>
tcp_recvmsg contains a sanity check that WARNs when there is a gap
between the socket's copied_seq and the first buffer in the
sk_receive_queue. In theory, the TCP stack makes sure that This Should
Never Happen (TM)... however, practice shows that there are still a few
bug reports from it out there (and one in my inbox).
Unfortunately, when it does happen for whatever reason, the situation
is not handled very well: the kernel logs a warning and breaks out of
the loop that walks the receive queue. It proceeds to find nothing else
to do on the socket and hits sk_wait_data, which cannot block because
the receive queue is not empty. As no data was read, the outer while
loop repeats (logging the same warning again) ad infinitum until the
system's syslog exhausts all available hard drive capacity.
This patch addresses that issue by closing the socket outright and
throwing EBADFD to userspace (which seems most appropriate to me at this
point). As the underlying bug condition is "impossible" and therefore by
definition unrecoverable, this is the only sensible action other than a
full panic.
Signed-off-by: Julius Werner <jwerner@chromium.org>
---
net/ipv4/tcp.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 197c000..d612308 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1628,7 +1628,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
"recvmsg bug: copied %X seq %X rcvnxt %X fl %X\n",
*seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt,
flags))
- break;
+ goto selfdestruct;
offset = *seq - TCP_SKB_CB(skb)->seq;
if (tcp_hdr(skb)->syn)
@@ -1936,6 +1936,11 @@ recv_urg:
recv_sndq:
err = tcp_peek_sndq(sk, msg, len);
goto out;
+
+selfdestruct:
+ err = -EBADFD;
+ tcp_done(sk);
+ goto out;
}
EXPORT_SYMBOL(tcp_recvmsg);
--
1.7.8.6
^ permalink raw reply related
* Re: [PATCH] tcp: Replace infinite loop on recvmsg bug with proper crashusers
From: Julius Werner @ 2012-11-07 19:32 UTC (permalink / raw)
To: Dave Jones, Eric Dumazet, Julius Werner, linux-kernel, netdev,
Patrick McHardy, Hideaki YOSHIFUJI, James Morris,
Alexey Kuznetsov, David S. Miller, Sameer Nanda,
Mandeep Singh Baines, Eric Dumazet
In-Reply-To: <20121107171541.GA24482@redhat.com>
I tend to agree with Dave that it's not in the user's best interest to
have a full-on BUG() here, and that we can get our reports just as
well by fishing them from the log through abrt or something similar. I
will just submit my alternative patch too and let you decide which one
you prefer.
This version shuts down the socket, so the broken receive queue will
not be used again and eventually freed. Other sockets and the system
as a whole will stay usable and probably still work if the bug is a
very rare coincidence. Of course, the driver will still be buggy, but
the same would stay true after a reboot (which is what most people do
after a panic). The userland caller gets an unexpected error code,
which is not the same as receiving a proper FIN and is the only thing
we can do to communicate this.
^ permalink raw reply
* Re: [PATCH net] cxgb4: Initialize data structures before using.
From: David Miller @ 2012-11-07 19:31 UTC (permalink / raw)
To: viral.vkm; +Cc: vipul, netdev, divy, dm, jay
In-Reply-To: <CANX6Dak5pFutKVn7hV_8-tYx4h67-gS2ud=CrArN--9e=ica5Q@mail.gmail.com>
From: Viral Mehta <viral.vkm@gmail.com>
Date: Wed, 7 Nov 2012 16:42:09 +0530
> Hi,
>
> On Tue, Nov 6, 2012 at 7:07 PM, Vipul Pandya <vipul@chelsio.com> wrote:
>>
>> We should not assume reserve fields to be don't cares as fields may change.
>> Clearing data structures before using.
>>
>> Signed-off-by: Jay Hernandez <jay@chelsio.com>
>> Signed-off-by: Vipul Pandya <vipul@chelsio.com>
>> ---
>> drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 4 ++++
>> 1 files changed, 4 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
>> index 32eec15..01fa5b7 100644
>> --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
>> +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
>> @@ -2519,6 +2519,7 @@ int t4_fw_bye(struct adapter *adap, unsigned int mbox)
>> {
>> struct fw_bye_cmd c;
>>
>> + memset(&c, 0, sizeof(c));
>
> struct fw_byte_cmd c = {0};
>
> Isn't it better ?
There is no fundamental difference, as far as the compiler and
optimizations are concerned, it's pretty much identical.
^ permalink raw reply
* Re: Possible bug with r8169 driver
From: Francois Romieu @ 2012-11-07 19:06 UTC (permalink / raw)
To: Nolwenn; +Cc: hayeswang, netdev, 'nic_swsd'
In-Reply-To: <6037895.4WQG8HALS9@bureau>
Nolwenn <donolwenn@gmail.com> :
[...]
> Few weeks later, does I have to do something or it will be fix in the next
> kernel ?
You do not have anything to do.
It is included in David Miller's net branch and will thereof proceed into
Linus's main branch.
--
Ueimor
^ permalink raw reply
* Re: [PATCH 03/12] batman-adv: add UNICAST_4ADDR packet type
From: Sven Eckelmann @ 2012-11-07 19:25 UTC (permalink / raw)
To: b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1403033.aGBWZgaJ6z-1RWNDQYo44h8XcdJbWeDu3TFMtCCXL7YSoIsB4E12gc@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1027 bytes --]
On Wednesday 07 November 2012 20:17:08 Sven Eckelmann wrote:
> On Wednesday 07 November 2012 20:11:33 Antonio Quartulli wrote:
> > +/**
> > + * struct batadv_unicast_4addr_packet - extended unicast packet
> > + * @u: common unicast packet header
> > + * @src: address of the source
> > + * @subtype: packet subtype
> > + */
> > +struct batadv_unicast_4addr_packet {
> > + struct batadv_unicast_packet u;
> > + uint8_t src[ETH_ALEN];
> > + uint8_t subtype;
> > + uint8_t reserved;
> > + /* "4 bytes boundary + 2 bytes" long to make the payload after the
> > + * following ethernet header again 4 bytes boundary aligned
> > + */
> > +};
>
> This doesn't work as you think. Now you have 2 extra padding bytes at the
> end of the batadv_unicast_4addr_packet and therefore make the payload (IPv4
> header..) after the following ethernet header again wrongly aligned.
Sry, my fault. Mixed it up with another packed which had a __be32 included
(batadv_bcast_packet).
Kind regards,
Sven
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [B.A.T.M.A.N.] [PATCH 03/12] batman-adv: add UNICAST_4ADDR packet type
From: Sven Eckelmann @ 2012-11-07 19:17 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Antonio Quartulli, davem, netdev
In-Reply-To: <1352315502-20324-4-git-send-email-ordex@autistici.org>
[-- Attachment #1: Type: text/plain, Size: 828 bytes --]
On Wednesday 07 November 2012 20:11:33 Antonio Quartulli wrote:
> +/**
> + * struct batadv_unicast_4addr_packet - extended unicast packet
> + * @u: common unicast packet header
> + * @src: address of the source
> + * @subtype: packet subtype
> + */
> +struct batadv_unicast_4addr_packet {
> + struct batadv_unicast_packet u;
> + uint8_t src[ETH_ALEN];
> + uint8_t subtype;
> + uint8_t reserved;
> + /* "4 bytes boundary + 2 bytes" long to make the payload after the
> + * following ethernet header again 4 bytes boundary aligned
> + */
> +};
This doesn't work as you think. Now you have 2 extra padding bytes at the end
of the batadv_unicast_4addr_packet and therefore make the payload (IPv4
header..) after the following ethernet header again wrongly aligned.
Kind regards,
Sven
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
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