Commit 45a6f3bc authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-4.12-20170425' of...

Merge tag 'linux-can-next-for-4.12-20170425' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2017-04-25

this is a pull request of 21 patches for net-next/master.

There are 4 patches by Stephane Grosjean for the PEAK PCAN-PCIe FD
CAN-FD boards. The next 7 patches are by Mario Huettel, which add
support for M_CAN IP version >= v3.1.x to the m_can driver. A patch by
Remigiusz Kołłątaj adds support for the Microchip CAN BUS Analyzer. 8
patches by Oliver Hartkopp complete the initial CAN network namespace
support. Wei Yongjun's patch for the ti_hecc driver fixes the return
value check in the probe function.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3133822f b655f0e9
...@@ -9,6 +9,24 @@ config CAN_VCAN ...@@ -9,6 +9,24 @@ config CAN_VCAN
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called vcan. will be called vcan.
config CAN_VXCAN
tristate "Virtual CAN Tunnel (vxcan)"
---help---
Similar to the virtual ethernet driver veth, vxcan implements a
local CAN traffic tunnel between two virtual CAN network devices.
When creating a vxcan, two vxcan devices are created as pair.
When one end receives the packet it appears on its pair and vice
versa. The vxcan can be used for cross namespace communication.
In opposite to vcan loopback devices the vxcan only forwards CAN
frames to its pair and does *not* provide a local echo of sent
CAN frames. To disable a potential echo in af_can.c the vxcan driver
announces IFF_ECHO in the interface flags. To have a clean start
in each namespace the CAN GW hop counter is set to zero.
This driver can also be built as a module. If so, the module
will be called vxcan.
config CAN_SLCAN config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)" tristate "Serial / USB serial CAN Adaptors (slcan)"
depends on TTY depends on TTY
...@@ -142,6 +160,7 @@ source "drivers/net/can/cc770/Kconfig" ...@@ -142,6 +160,7 @@ source "drivers/net/can/cc770/Kconfig"
source "drivers/net/can/ifi_canfd/Kconfig" source "drivers/net/can/ifi_canfd/Kconfig"
source "drivers/net/can/m_can/Kconfig" source "drivers/net/can/m_can/Kconfig"
source "drivers/net/can/mscan/Kconfig" source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/peak_canfd/Kconfig"
source "drivers/net/can/rcar/Kconfig" source "drivers/net/can/rcar/Kconfig"
source "drivers/net/can/sja1000/Kconfig" source "drivers/net/can/sja1000/Kconfig"
source "drivers/net/can/softing/Kconfig" source "drivers/net/can/softing/Kconfig"
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# #
obj-$(CONFIG_CAN_VCAN) += vcan.o obj-$(CONFIG_CAN_VCAN) += vcan.o
obj-$(CONFIG_CAN_VXCAN) += vxcan.o
obj-$(CONFIG_CAN_SLCAN) += slcan.o obj-$(CONFIG_CAN_SLCAN) += slcan.o
obj-$(CONFIG_CAN_DEV) += can-dev.o obj-$(CONFIG_CAN_DEV) += can-dev.o
...@@ -26,6 +27,7 @@ obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/ ...@@ -26,6 +27,7 @@ obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_MSCAN) += mscan/
obj-$(CONFIG_CAN_M_CAN) += m_can/ obj-$(CONFIG_CAN_M_CAN) += m_can/
obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_canfd/
obj-$(CONFIG_CAN_SJA1000) += sja1000/ obj-$(CONFIG_CAN_SJA1000) += sja1000/
obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
......
This diff is collapsed.
config CAN_PEAK_PCIEFD
depends on PCI
tristate "PEAK-System PCAN-PCIe FD cards"
---help---
This driver adds support for the PEAK-System PCI Express FD
CAN-FD cards family.
These 1x or 2x CAN-FD channels cards offer CAN 2.0 a/b as well as
CAN-FD access to the CAN bus. Besides the nominal bitrate of up to
1 Mbit/s, the data bytes of CAN-FD frames can be transmitted with
up to 12 Mbit/s. A galvanic isolation of the CAN ports protects the
electronics of the card and the respective computer against
disturbances of up to 500 Volts. The PCAN-PCI Express FD can be
operated with ambient temperatures in a range of -40 to +85 °C.
#
# Makefile for the PEAK-System CAN-FD IP module drivers
#
obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_pciefd.o
peak_pciefd-y := peak_pciefd_main.o peak_canfd.o
This diff is collapsed.
/*
* CAN driver for PEAK System micro-CAN based adapters
*
* Copyright (C) 2003-2011 PEAK System-Technik GmbH
* Copyright (C) 2011-2013 Stephane Grosjean <s.grosjean@peak-system.com>
*
* 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 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef PEAK_CANFD_USER_H
#define PEAK_CANFD_USER_H
#include <linux/can/dev/peak_canfd.h>
#define PCANFD_ECHO_SKB_DEF -1
/* data structure private to each uCAN interface */
struct peak_canfd_priv {
struct can_priv can; /* socket-can private data */
struct net_device *ndev; /* network device */
int index; /* channel index */
struct can_berr_counter bec; /* rx/tx err counters */
int echo_idx; /* echo skb free slot index */
spinlock_t echo_lock;
int cmd_len;
void *cmd_buffer;
int cmd_maxlen;
int (*pre_cmd)(struct peak_canfd_priv *priv);
int (*write_cmd)(struct peak_canfd_priv *priv);
int (*post_cmd)(struct peak_canfd_priv *priv);
int (*enable_tx_path)(struct peak_canfd_priv *priv);
void *(*alloc_tx_msg)(struct peak_canfd_priv *priv, u16 msg_size,
int *room_left);
int (*write_tx_msg)(struct peak_canfd_priv *priv,
struct pucan_tx_msg *msg);
};
struct net_device *alloc_peak_canfd_dev(int sizeof_priv, int index,
int echo_skb_max);
int peak_canfd_handle_msg(struct peak_canfd_priv *priv,
struct pucan_rx_msg *msg);
int peak_canfd_handle_msgs_list(struct peak_canfd_priv *priv,
struct pucan_rx_msg *rx_msg, int rx_count);
#endif
This diff is collapsed.
...@@ -898,9 +898,9 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -898,9 +898,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
} }
priv->base = devm_ioremap_resource(&pdev->dev, res); priv->base = devm_ioremap_resource(&pdev->dev, res);
if (!priv->base) { if (IS_ERR(priv->base)) {
dev_err(&pdev->dev, "hecc ioremap failed\n"); dev_err(&pdev->dev, "hecc ioremap failed\n");
return -ENOMEM; return PTR_ERR(priv->base);
} }
/* handle hecc-ram memory */ /* handle hecc-ram memory */
...@@ -911,9 +911,9 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -911,9 +911,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
} }
priv->hecc_ram = devm_ioremap_resource(&pdev->dev, res); priv->hecc_ram = devm_ioremap_resource(&pdev->dev, res);
if (!priv->hecc_ram) { if (IS_ERR(priv->hecc_ram)) {
dev_err(&pdev->dev, "hecc-ram ioremap failed\n"); dev_err(&pdev->dev, "hecc-ram ioremap failed\n");
return -ENOMEM; return PTR_ERR(priv->hecc_ram);
} }
/* handle mbx memory */ /* handle mbx memory */
...@@ -924,9 +924,9 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -924,9 +924,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
} }
priv->mbx = devm_ioremap_resource(&pdev->dev, res); priv->mbx = devm_ioremap_resource(&pdev->dev, res);
if (!priv->mbx) { if (IS_ERR(priv->mbx)) {
dev_err(&pdev->dev, "mbx ioremap failed\n"); dev_err(&pdev->dev, "mbx ioremap failed\n");
return -ENOMEM; return PTR_ERR(priv->mbx);
} }
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
......
...@@ -81,4 +81,10 @@ config CAN_8DEV_USB ...@@ -81,4 +81,10 @@ config CAN_8DEV_USB
This driver supports the USB2CAN interface This driver supports the USB2CAN interface
from 8 devices (http://www.8devices.com). from 8 devices (http://www.8devices.com).
config CAN_MCBA_USB
tristate "Microchip CAN BUS Analyzer interface"
---help---
This driver supports the CAN BUS Analyzer interface
from Microchip (http://www.microchip.com/development-tools/).
endmenu endmenu
...@@ -8,3 +8,4 @@ obj-$(CONFIG_CAN_GS_USB) += gs_usb.o ...@@ -8,3 +8,4 @@ obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/ obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
obj-$(CONFIG_CAN_MCBA_USB) += mcba_usb.o
This diff is collapsed.
...@@ -19,10 +19,10 @@ ...@@ -19,10 +19,10 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/dev/peak_canfd.h>
#include "pcan_usb_core.h" #include "pcan_usb_core.h"
#include "pcan_usb_pro.h" #include "pcan_usb_pro.h"
#include "pcan_ucan.h"
MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB FD adapter"); MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB FD adapter");
MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro FD adapter"); MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro FD adapter");
...@@ -238,7 +238,7 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf) ...@@ -238,7 +238,7 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
/* 1st, reset error counters: */ /* 1st, reset error counters: */
prc = (struct pucan_wr_err_cnt *)pc; prc = (struct pucan_wr_err_cnt *)pc;
prc->opcode_channel = pucan_cmd_opcode_channel(dev, prc->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_WR_ERR_CNT); PUCAN_CMD_WR_ERR_CNT);
/* select both counters */ /* select both counters */
...@@ -257,9 +257,10 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf) ...@@ -257,9 +257,10 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
puo->opcode_channel = puo->opcode_channel =
(dev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) ? (dev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) ?
pucan_cmd_opcode_channel(dev, pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_CLR_DIS_OPTION) : PUCAN_CMD_CLR_DIS_OPTION) :
pucan_cmd_opcode_channel(dev, PUCAN_CMD_SET_EN_OPTION); pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_SET_EN_OPTION);
puo->options = cpu_to_le16(PUCAN_OPTION_CANDFDISO); puo->options = cpu_to_le16(PUCAN_OPTION_CANDFDISO);
...@@ -274,7 +275,7 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf) ...@@ -274,7 +275,7 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
/* next, go back to operational mode */ /* next, go back to operational mode */
cmd = (struct pucan_command *)pc; cmd = (struct pucan_command *)pc;
cmd->opcode_channel = pucan_cmd_opcode_channel(dev, cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
(dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) ? (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) ?
PUCAN_CMD_LISTEN_ONLY_MODE : PUCAN_CMD_LISTEN_ONLY_MODE :
PUCAN_CMD_NORMAL_MODE); PUCAN_CMD_NORMAL_MODE);
...@@ -296,7 +297,7 @@ static int pcan_usb_fd_set_bus(struct peak_usb_device *dev, u8 onoff) ...@@ -296,7 +297,7 @@ static int pcan_usb_fd_set_bus(struct peak_usb_device *dev, u8 onoff)
struct pucan_command *cmd = (struct pucan_command *)pc; struct pucan_command *cmd = (struct pucan_command *)pc;
/* build cmd to go back to reset mode */ /* build cmd to go back to reset mode */
cmd->opcode_channel = pucan_cmd_opcode_channel(dev, cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_RESET_MODE); PUCAN_CMD_RESET_MODE);
l = sizeof(struct pucan_command); l = sizeof(struct pucan_command);
} }
...@@ -332,7 +333,7 @@ static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx, ...@@ -332,7 +333,7 @@ static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx,
} }
for (i = idx; i < n; i++, cmd++) { for (i = idx; i < n; i++, cmd++) {
cmd->opcode_channel = pucan_cmd_opcode_channel(dev, cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_FILTER_STD); PUCAN_CMD_FILTER_STD);
cmd->idx = cpu_to_le16(i); cmd->idx = cpu_to_le16(i);
cmd->mask = cpu_to_le32(mask); cmd->mask = cpu_to_le32(mask);
...@@ -352,7 +353,7 @@ static int pcan_usb_fd_set_options(struct peak_usb_device *dev, ...@@ -352,7 +353,7 @@ static int pcan_usb_fd_set_options(struct peak_usb_device *dev,
{ {
struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev); struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev);
cmd->opcode_channel = pucan_cmd_opcode_channel(dev, cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
(onoff) ? PUCAN_CMD_SET_EN_OPTION : (onoff) ? PUCAN_CMD_SET_EN_OPTION :
PUCAN_CMD_CLR_DIS_OPTION); PUCAN_CMD_CLR_DIS_OPTION);
...@@ -368,7 +369,7 @@ static int pcan_usb_fd_set_can_led(struct peak_usb_device *dev, u8 led_mode) ...@@ -368,7 +369,7 @@ static int pcan_usb_fd_set_can_led(struct peak_usb_device *dev, u8 led_mode)
{ {
struct pcan_ufd_led *cmd = pcan_usb_fd_cmd_buffer(dev); struct pcan_ufd_led *cmd = pcan_usb_fd_cmd_buffer(dev);
cmd->opcode_channel = pucan_cmd_opcode_channel(dev, cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PCAN_UFD_CMD_LED_SET); PCAN_UFD_CMD_LED_SET);
cmd->mode = led_mode; cmd->mode = led_mode;
...@@ -382,7 +383,7 @@ static int pcan_usb_fd_set_clock_domain(struct peak_usb_device *dev, ...@@ -382,7 +383,7 @@ static int pcan_usb_fd_set_clock_domain(struct peak_usb_device *dev,
{ {
struct pcan_ufd_clock *cmd = pcan_usb_fd_cmd_buffer(dev); struct pcan_ufd_clock *cmd = pcan_usb_fd_cmd_buffer(dev);
cmd->opcode_channel = pucan_cmd_opcode_channel(dev, cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PCAN_UFD_CMD_CLK_SET); PCAN_UFD_CMD_CLK_SET);
cmd->mode = clk_mode; cmd->mode = clk_mode;
...@@ -396,7 +397,7 @@ static int pcan_usb_fd_set_bittiming_slow(struct peak_usb_device *dev, ...@@ -396,7 +397,7 @@ static int pcan_usb_fd_set_bittiming_slow(struct peak_usb_device *dev,
{ {
struct pucan_timing_slow *cmd = pcan_usb_fd_cmd_buffer(dev); struct pucan_timing_slow *cmd = pcan_usb_fd_cmd_buffer(dev);
cmd->opcode_channel = pucan_cmd_opcode_channel(dev, cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_TIMING_SLOW); PUCAN_CMD_TIMING_SLOW);
cmd->sjw_t = PUCAN_TSLOW_SJW_T(bt->sjw - 1, cmd->sjw_t = PUCAN_TSLOW_SJW_T(bt->sjw - 1,
dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES); dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES);
...@@ -417,7 +418,7 @@ static int pcan_usb_fd_set_bittiming_fast(struct peak_usb_device *dev, ...@@ -417,7 +418,7 @@ static int pcan_usb_fd_set_bittiming_fast(struct peak_usb_device *dev,
{ {
struct pucan_timing_fast *cmd = pcan_usb_fd_cmd_buffer(dev); struct pucan_timing_fast *cmd = pcan_usb_fd_cmd_buffer(dev);
cmd->opcode_channel = pucan_cmd_opcode_channel(dev, cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_TIMING_FAST); PUCAN_CMD_TIMING_FAST);
cmd->sjw = PUCAN_TFAST_SJW(bt->sjw - 1); cmd->sjw = PUCAN_TFAST_SJW(bt->sjw - 1);
cmd->tseg2 = PUCAN_TFAST_TSEG2(bt->phase_seg2 - 1); cmd->tseg2 = PUCAN_TFAST_TSEG2(bt->phase_seg2 - 1);
......
/* /*
* vcan.c - Virtual CAN interface * vcan.c - Virtual CAN interface
* *
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -50,9 +50,12 @@ ...@@ -50,9 +50,12 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#define DRV_NAME "vcan"
MODULE_DESCRIPTION("virtual CAN interface"); MODULE_DESCRIPTION("virtual CAN interface");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>"); MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
MODULE_ALIAS_RTNL_LINK(DRV_NAME);
/* /*
...@@ -164,7 +167,7 @@ static void vcan_setup(struct net_device *dev) ...@@ -164,7 +167,7 @@ static void vcan_setup(struct net_device *dev)
} }
static struct rtnl_link_ops vcan_link_ops __read_mostly = { static struct rtnl_link_ops vcan_link_ops __read_mostly = {
.kind = "vcan", .kind = DRV_NAME,
.setup = vcan_setup, .setup = vcan_setup,
}; };
......
/*
* vxcan.c - Virtual CAN Tunnel for cross namespace communication
*
* This code is derived from drivers/net/can/vcan.c for the virtual CAN
* specific parts and from drivers/net/veth.c to implement the netlink API
* for network interface pairs in a common and established way.
*
* Copyright (c) 2017 Oliver Hartkopp <socketcan@hartkopp.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/skb.h>
#include <linux/can/vxcan.h>
#include <linux/slab.h>
#include <net/rtnetlink.h>
#define DRV_NAME "vxcan"
MODULE_DESCRIPTION("Virtual CAN Tunnel");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Oliver Hartkopp <socketcan@hartkopp.net>");
MODULE_ALIAS_RTNL_LINK(DRV_NAME);
struct vxcan_priv {
struct net_device __rcu *peer;
};
static netdev_tx_t vxcan_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct vxcan_priv *priv = netdev_priv(dev);
struct net_device *peer;
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
struct net_device_stats *peerstats, *srcstats = &dev->stats;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
rcu_read_lock();
peer = rcu_dereference(priv->peer);
if (unlikely(!peer)) {
kfree_skb(skb);
dev->stats.tx_dropped++;
goto out_unlock;
}
skb = can_create_echo_skb(skb);
if (!skb)
goto out_unlock;
/* reset CAN GW hop counter */
skb->csum_start = 0;
skb->pkt_type = PACKET_BROADCAST;
skb->dev = peer;
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (netif_rx_ni(skb) == NET_RX_SUCCESS) {
srcstats->tx_packets++;
srcstats->tx_bytes += cfd->len;
peerstats = &peer->stats;
peerstats->rx_packets++;
peerstats->rx_bytes += cfd->len;
}
out_unlock:
rcu_read_unlock();
return NETDEV_TX_OK;
}
static int vxcan_open(struct net_device *dev)
{
struct vxcan_priv *priv = netdev_priv(dev);
struct net_device *peer = rtnl_dereference(priv->peer);
if (!peer)
return -ENOTCONN;
if (peer->flags & IFF_UP) {
netif_carrier_on(dev);
netif_carrier_on(peer);
}
return 0;
}
static int vxcan_close(struct net_device *dev)
{
struct vxcan_priv *priv = netdev_priv(dev);
struct net_device *peer = rtnl_dereference(priv->peer);
netif_carrier_off(dev);
if (peer)
netif_carrier_off(peer);
return 0;
}
static int vxcan_get_iflink(const struct net_device *dev)
{
struct vxcan_priv *priv = netdev_priv(dev);
struct net_device *peer;
int iflink;
rcu_read_lock();
peer = rcu_dereference(priv->peer);
iflink = peer ? peer->ifindex : 0;
rcu_read_unlock();
return iflink;
}
static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
{
/* Do not allow changing the MTU while running */
if (dev->flags & IFF_UP)
return -EBUSY;
if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU)
return -EINVAL;
dev->mtu = new_mtu;
return 0;
}
static const struct net_device_ops vxcan_netdev_ops = {
.ndo_open = vxcan_open,
.ndo_stop = vxcan_close,
.ndo_start_xmit = vxcan_xmit,
.ndo_get_iflink = vxcan_get_iflink,
.ndo_change_mtu = vxcan_change_mtu,
};
static void vxcan_setup(struct net_device *dev)
{
dev->type = ARPHRD_CAN;
dev->mtu = CAN_MTU;
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->tx_queue_len = 0;
dev->flags = (IFF_NOARP|IFF_ECHO);
dev->netdev_ops = &vxcan_netdev_ops;
dev->destructor = free_netdev;
}
/* forward declaration for rtnl_create_link() */
static struct rtnl_link_ops vxcan_link_ops;
static int vxcan_newlink(struct net *net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct vxcan_priv *priv;
struct net_device *peer;
struct net *peer_net;
struct nlattr *peer_tb[IFLA_MAX + 1], **tbp = tb;
char ifname[IFNAMSIZ];
unsigned char name_assign_type;
struct ifinfomsg *ifmp = NULL;
int err;
/* register peer device */
if (data && data[VXCAN_INFO_PEER]) {
struct nlattr *nla_peer;
nla_peer = data[VXCAN_INFO_PEER];
ifmp = nla_data(nla_peer);
err = rtnl_nla_parse_ifla(peer_tb,
nla_data(nla_peer) +
sizeof(struct ifinfomsg),
nla_len(nla_peer) -
sizeof(struct ifinfomsg),
NULL);
if (err < 0)
return err;
tbp = peer_tb;
}
if (tbp[IFLA_IFNAME]) {
nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
name_assign_type = NET_NAME_USER;
} else {
snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d");
name_assign_type = NET_NAME_ENUM;
}
peer_net = rtnl_link_get_net(net, tbp);
if (IS_ERR(peer_net))
return PTR_ERR(peer_net);
peer = rtnl_create_link(peer_net, ifname, name_assign_type,
&vxcan_link_ops, tbp);
if (IS_ERR(peer)) {
put_net(peer_net);
return PTR_ERR(peer);
}
if (ifmp && dev->ifindex)
peer->ifindex = ifmp->ifi_index;
err = register_netdevice(peer);
put_net(peer_net);
peer_net = NULL;
if (err < 0) {
free_netdev(peer);
return err;
}
netif_carrier_off(peer);
err = rtnl_configure_link(peer, ifmp);
if (err < 0) {
unregister_netdevice(peer);
return err;
}
/* register first device */
if (tb[IFLA_IFNAME])
nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ);
else
snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d");
err = register_netdevice(dev);
if (err < 0) {
unregister_netdevice(peer);
return err;
}
netif_carrier_off(dev);
/* cross link the device pair */
priv = netdev_priv(dev);
rcu_assign_pointer(priv->peer, peer);
priv = netdev_priv(peer);
rcu_assign_pointer(priv->peer, dev);
return 0;
}
static void vxcan_dellink(struct net_device *dev, struct list_head *head)
{
struct vxcan_priv *priv;
struct net_device *peer;
priv = netdev_priv(dev);
peer = rtnl_dereference(priv->peer);
/* Note : dellink() is called from default_device_exit_batch(),
* before a rcu_synchronize() point. The devices are guaranteed
* not being freed before one RCU grace period.
*/
RCU_INIT_POINTER(priv->peer, NULL);
unregister_netdevice_queue(dev, head);
if (peer) {
priv = netdev_priv(peer);
RCU_INIT_POINTER(priv->peer, NULL);
unregister_netdevice_queue(peer, head);
}
}
static const struct nla_policy vxcan_policy[VXCAN_INFO_MAX + 1] = {
[VXCAN_INFO_PEER] = { .len = sizeof(struct ifinfomsg) },
};
static struct net *vxcan_get_link_net(const struct net_device *dev)
{
struct vxcan_priv *priv = netdev_priv(dev);
struct net_device *peer = rtnl_dereference(priv->peer);
return peer ? dev_net(peer) : dev_net(dev);
}
static struct rtnl_link_ops vxcan_link_ops = {
.kind = DRV_NAME,
.priv_size = sizeof(struct vxcan_priv),
.setup = vxcan_setup,
.newlink = vxcan_newlink,
.dellink = vxcan_dellink,
.policy = vxcan_policy,
.maxtype = VXCAN_INFO_MAX,
.get_link_net = vxcan_get_link_net,
};
static __init int vxcan_init(void)
{
pr_info("vxcan: Virtual CAN Tunnel driver\n");
return rtnl_link_register(&vxcan_link_ops);
}
static __exit void vxcan_exit(void)
{
rtnl_link_unregister(&vxcan_link_ops);
}
module_init(vxcan_init);
module_exit(vxcan_exit);
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de> * Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
* Urs Thuermann <urs.thuermann@volkswagen.de> * Urs Thuermann <urs.thuermann@volkswagen.de>
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved. * All rights reserved.
* *
*/ */
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#define CAN_VERSION "20120528" #define CAN_VERSION "20170425"
/* increment this number each time you change some user-space interface */ /* increment this number each time you change some user-space interface */
#define CAN_ABI_VERSION "9" #define CAN_ABI_VERSION "9"
......
...@@ -23,11 +23,14 @@ ...@@ -23,11 +23,14 @@
#define PUCAN_CMD_LISTEN_ONLY_MODE 0x003 #define PUCAN_CMD_LISTEN_ONLY_MODE 0x003
#define PUCAN_CMD_TIMING_SLOW 0x004 #define PUCAN_CMD_TIMING_SLOW 0x004
#define PUCAN_CMD_TIMING_FAST 0x005 #define PUCAN_CMD_TIMING_FAST 0x005
#define PUCAN_CMD_SET_STD_FILTER 0x006
#define PUCAN_CMD_RESERVED2 0x007
#define PUCAN_CMD_FILTER_STD 0x008 #define PUCAN_CMD_FILTER_STD 0x008
#define PUCAN_CMD_TX_ABORT 0x009 #define PUCAN_CMD_TX_ABORT 0x009
#define PUCAN_CMD_WR_ERR_CNT 0x00a #define PUCAN_CMD_WR_ERR_CNT 0x00a
#define PUCAN_CMD_SET_EN_OPTION 0x00b #define PUCAN_CMD_SET_EN_OPTION 0x00b
#define PUCAN_CMD_CLR_DIS_OPTION 0x00c #define PUCAN_CMD_CLR_DIS_OPTION 0x00c
#define PUCAN_CMD_RX_BARRIER 0x010
#define PUCAN_CMD_END_OF_COLLECTION 0x3ff #define PUCAN_CMD_END_OF_COLLECTION 0x3ff
/* uCAN received messages list */ /* uCAN received messages list */
...@@ -35,6 +38,10 @@ ...@@ -35,6 +38,10 @@
#define PUCAN_MSG_ERROR 0x0002 #define PUCAN_MSG_ERROR 0x0002
#define PUCAN_MSG_STATUS 0x0003 #define PUCAN_MSG_STATUS 0x0003
#define PUCAN_MSG_BUSLOAD 0x0004 #define PUCAN_MSG_BUSLOAD 0x0004
#define PUCAN_MSG_CACHE_CRITICAL 0x0102
/* uCAN transmitted messages */
#define PUCAN_MSG_CAN_TX 0x1000 #define PUCAN_MSG_CAN_TX 0x1000
/* uCAN command common header */ /* uCAN command common header */
...@@ -43,6 +50,12 @@ struct __packed pucan_command { ...@@ -43,6 +50,12 @@ struct __packed pucan_command {
u16 args[3]; u16 args[3];
}; };
/* return the opcode from the opcode_channel field of a command */
static inline u16 pucan_cmd_get_opcode(struct pucan_command *c)
{
return le16_to_cpu(c->opcode_channel) & 0x3ff;
}
#define PUCAN_TSLOW_BRP_BITS 10 #define PUCAN_TSLOW_BRP_BITS 10
#define PUCAN_TSLOW_TSGEG1_BITS 8 #define PUCAN_TSLOW_TSGEG1_BITS 8
#define PUCAN_TSLOW_TSGEG2_BITS 7 #define PUCAN_TSLOW_TSGEG2_BITS 7
...@@ -108,6 +121,27 @@ struct __packed pucan_filter_std { ...@@ -108,6 +121,27 @@ struct __packed pucan_filter_std {
__le32 mask; /* CAN-ID bitmask in idx range */ __le32 mask; /* CAN-ID bitmask in idx range */
}; };
#define PUCAN_FLTSTD_ROW_IDX_MAX ((1 << PUCAN_FLTSTD_ROW_IDX_BITS) - 1)
/* uCAN SET_STD_FILTER command fields */
struct __packed pucan_std_filter {
__le16 opcode_channel;
u8 unused;
u8 idx;
__le32 mask; /* CAN-ID bitmask in idx range */
};
/* uCAN TX_ABORT commands fields */
#define PUCAN_TX_ABORT_FLUSH 0x0001
struct __packed pucan_tx_abort {
__le16 opcode_channel;
__le16 flags;
u32 unused;
};
/* uCAN WR_ERR_CNT command fields */ /* uCAN WR_ERR_CNT command fields */
#define PUCAN_WRERRCNT_TE 0x4000 /* Tx error cntr write Enable */ #define PUCAN_WRERRCNT_TE 0x4000 /* Tx error cntr write Enable */
#define PUCAN_WRERRCNT_RE 0x8000 /* Rx error cntr write Enable */ #define PUCAN_WRERRCNT_RE 0x8000 /* Rx error cntr write Enable */
...@@ -184,6 +218,12 @@ struct __packed pucan_error_msg { ...@@ -184,6 +218,12 @@ struct __packed pucan_error_msg {
u8 rx_err_cnt; u8 rx_err_cnt;
}; };
static inline int pucan_error_get_channel(const struct pucan_error_msg *msg)
{
return msg->channel_type_d & 0x0f;
}
#define PUCAN_RX_BARRIER 0x10
#define PUCAN_BUS_PASSIVE 0x20 #define PUCAN_BUS_PASSIVE 0x20
#define PUCAN_BUS_WARNING 0x40 #define PUCAN_BUS_WARNING 0x40
#define PUCAN_BUS_BUSOFF 0x80 #define PUCAN_BUS_BUSOFF 0x80
...@@ -197,6 +237,31 @@ struct __packed pucan_status_msg { ...@@ -197,6 +237,31 @@ struct __packed pucan_status_msg {
u8 unused[3]; u8 unused[3];
}; };
static inline int pucan_status_get_channel(const struct pucan_status_msg *msg)
{
return msg->channel_p_w_b & 0x0f;
}
static inline int pucan_status_is_rx_barrier(const struct pucan_status_msg *msg)
{
return msg->channel_p_w_b & PUCAN_RX_BARRIER;
}
static inline int pucan_status_is_passive(const struct pucan_status_msg *msg)
{
return msg->channel_p_w_b & PUCAN_BUS_PASSIVE;
}
static inline int pucan_status_is_warning(const struct pucan_status_msg *msg)
{
return msg->channel_p_w_b & PUCAN_BUS_WARNING;
}
static inline int pucan_status_is_busoff(const struct pucan_status_msg *msg)
{
return msg->channel_p_w_b & PUCAN_BUS_BUSOFF;
}
/* uCAN transmitted message format */ /* uCAN transmitted message format */
#define PUCAN_MSG_CHANNEL_DLC(c, d) (((c) & 0xf) | ((d) << 4)) #define PUCAN_MSG_CHANNEL_DLC(c, d) (((c) & 0xf) | ((d) << 4))
...@@ -213,32 +278,31 @@ struct __packed pucan_tx_msg { ...@@ -213,32 +278,31 @@ struct __packed pucan_tx_msg {
}; };
/* build the cmd opcode_channel field with respect to the correct endianness */ /* build the cmd opcode_channel field with respect to the correct endianness */
static inline __le16 pucan_cmd_opcode_channel(struct peak_usb_device *dev, static inline __le16 pucan_cmd_opcode_channel(int index, int opcode)
int opcode)
{ {
return cpu_to_le16(((dev->ctrl_idx) << 12) | ((opcode) & 0x3ff)); return cpu_to_le16(((index) << 12) | ((opcode) & 0x3ff));
} }
/* return the channel number part from any received message channel_dlc field */ /* return the channel number part from any received message channel_dlc field */
static inline int pucan_msg_get_channel(struct pucan_rx_msg *rm) static inline int pucan_msg_get_channel(const struct pucan_rx_msg *msg)
{ {
return rm->channel_dlc & 0xf; return msg->channel_dlc & 0xf;
} }
/* return the dlc value from any received message channel_dlc field */ /* return the dlc value from any received message channel_dlc field */
static inline int pucan_msg_get_dlc(struct pucan_rx_msg *rm) static inline int pucan_msg_get_dlc(const struct pucan_rx_msg *msg)
{ {
return rm->channel_dlc >> 4; return msg->channel_dlc >> 4;
} }
static inline int pucan_ermsg_get_channel(struct pucan_error_msg *em) static inline int pucan_ermsg_get_channel(const struct pucan_error_msg *msg)
{ {
return em->channel_type_d & 0x0f; return msg->channel_type_d & 0x0f;
} }
static inline int pucan_stmsg_get_channel(struct pucan_status_msg *sm) static inline int pucan_stmsg_get_channel(const struct pucan_status_msg *msg)
{ {
return sm->channel_p_w_b & 0x0f; return msg->channel_p_w_b & 0x0f;
} }
#endif #endif
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
struct dev_rcv_lists; struct dev_rcv_lists;
struct s_stats;
struct s_pstats;
struct netns_can { struct netns_can {
#if IS_ENABLED(CONFIG_PROC_FS) #if IS_ENABLED(CONFIG_PROC_FS)
...@@ -21,11 +23,18 @@ struct netns_can { ...@@ -21,11 +23,18 @@ struct netns_can {
struct proc_dir_entry *pde_rcvlist_sff; struct proc_dir_entry *pde_rcvlist_sff;
struct proc_dir_entry *pde_rcvlist_eff; struct proc_dir_entry *pde_rcvlist_eff;
struct proc_dir_entry *pde_rcvlist_err; struct proc_dir_entry *pde_rcvlist_err;
struct proc_dir_entry *bcmproc_dir;
#endif #endif
/* receive filters subscribed for 'all' CAN devices */ /* receive filters subscribed for 'all' CAN devices */
struct dev_rcv_lists *can_rx_alldev_list; struct dev_rcv_lists *can_rx_alldev_list;
spinlock_t can_rcvlists_lock; spinlock_t can_rcvlists_lock;
struct timer_list can_stattimer;/* timer for statistics update */
struct s_stats *can_stats; /* packet statistics */
struct s_pstats *can_pstats; /* receive list statistics */
/* CAN GW per-net gateway jobs */
struct hlist_head cgw_list;
}; };
#endif /* __NETNS_CAN_H__ */ #endif /* __NETNS_CAN_H__ */
#ifndef _UAPI_CAN_VXCAN_H
#define _UAPI_CAN_VXCAN_H
enum {
VXCAN_INFO_UNSPEC,
VXCAN_INFO_PEER,
__VXCAN_INFO_MAX
#define VXCAN_INFO_MAX (__VXCAN_INFO_MAX - 1)
};
#endif
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* af_can.c - Protocol family CAN core module * af_can.c - Protocol family CAN core module
* (used by different CAN protocol modules) * (used by different CAN protocol modules)
* *
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -75,18 +75,12 @@ static int stats_timer __read_mostly = 1; ...@@ -75,18 +75,12 @@ static int stats_timer __read_mostly = 1;
module_param(stats_timer, int, S_IRUGO); module_param(stats_timer, int, S_IRUGO);
MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)"); MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)");
static int can_net_id;
static struct kmem_cache *rcv_cache __read_mostly; static struct kmem_cache *rcv_cache __read_mostly;
/* table of registered CAN protocols */ /* table of registered CAN protocols */
static const struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; static const struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
static DEFINE_MUTEX(proto_tab_lock); static DEFINE_MUTEX(proto_tab_lock);
struct timer_list can_stattimer; /* timer for statistics update */
struct s_stats can_stats; /* packet statistics */
struct s_pstats can_pstats; /* receive list statistics */
static atomic_t skbcounter = ATOMIC_INIT(0); static atomic_t skbcounter = ATOMIC_INIT(0);
/* /*
...@@ -223,6 +217,7 @@ int can_send(struct sk_buff *skb, int loop) ...@@ -223,6 +217,7 @@ int can_send(struct sk_buff *skb, int loop)
{ {
struct sk_buff *newskb = NULL; struct sk_buff *newskb = NULL;
struct canfd_frame *cfd = (struct canfd_frame *)skb->data; struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
struct s_stats *can_stats = dev_net(skb->dev)->can.can_stats;
int err = -EINVAL; int err = -EINVAL;
if (skb->len == CAN_MTU) { if (skb->len == CAN_MTU) {
...@@ -311,8 +306,8 @@ int can_send(struct sk_buff *skb, int loop) ...@@ -311,8 +306,8 @@ int can_send(struct sk_buff *skb, int loop)
netif_rx_ni(newskb); netif_rx_ni(newskb);
/* update statistics */ /* update statistics */
can_stats.tx_frames++; can_stats->tx_frames++;
can_stats.tx_frames_delta++; can_stats->tx_frames_delta++;
return 0; return 0;
...@@ -470,6 +465,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id, ...@@ -470,6 +465,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
struct receiver *r; struct receiver *r;
struct hlist_head *rl; struct hlist_head *rl;
struct dev_rcv_lists *d; struct dev_rcv_lists *d;
struct s_pstats *can_pstats = net->can.can_pstats;
int err = 0; int err = 0;
/* insert new receiver (dev,canid,mask) -> (func,data) */ /* insert new receiver (dev,canid,mask) -> (func,data) */
...@@ -501,9 +497,9 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id, ...@@ -501,9 +497,9 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
hlist_add_head_rcu(&r->list, rl); hlist_add_head_rcu(&r->list, rl);
d->entries++; d->entries++;
can_pstats.rcv_entries++; can_pstats->rcv_entries++;
if (can_pstats.rcv_entries_max < can_pstats.rcv_entries) if (can_pstats->rcv_entries_max < can_pstats->rcv_entries)
can_pstats.rcv_entries_max = can_pstats.rcv_entries; can_pstats->rcv_entries_max = can_pstats->rcv_entries;
} else { } else {
kmem_cache_free(rcv_cache, r); kmem_cache_free(rcv_cache, r);
err = -ENODEV; err = -ENODEV;
...@@ -545,6 +541,7 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, ...@@ -545,6 +541,7 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
{ {
struct receiver *r = NULL; struct receiver *r = NULL;
struct hlist_head *rl; struct hlist_head *rl;
struct s_pstats *can_pstats = net->can.can_pstats;
struct dev_rcv_lists *d; struct dev_rcv_lists *d;
if (dev && dev->type != ARPHRD_CAN) if (dev && dev->type != ARPHRD_CAN)
...@@ -591,8 +588,8 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, ...@@ -591,8 +588,8 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
hlist_del_rcu(&r->list); hlist_del_rcu(&r->list);
d->entries--; d->entries--;
if (can_pstats.rcv_entries > 0) if (can_pstats->rcv_entries > 0)
can_pstats.rcv_entries--; can_pstats->rcv_entries--;
/* remove device structure requested by NETDEV_UNREGISTER */ /* remove device structure requested by NETDEV_UNREGISTER */
if (d->remove_on_zero_entries && !d->entries) { if (d->remove_on_zero_entries && !d->entries) {
...@@ -686,11 +683,13 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb) ...@@ -686,11 +683,13 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
static void can_receive(struct sk_buff *skb, struct net_device *dev) static void can_receive(struct sk_buff *skb, struct net_device *dev)
{ {
struct dev_rcv_lists *d; struct dev_rcv_lists *d;
struct net *net = dev_net(dev);
struct s_stats *can_stats = net->can.can_stats;
int matches; int matches;
/* update statistics */ /* update statistics */
can_stats.rx_frames++; can_stats->rx_frames++;
can_stats.rx_frames_delta++; can_stats->rx_frames_delta++;
/* create non-zero unique skb identifier together with *skb */ /* create non-zero unique skb identifier together with *skb */
while (!(can_skb_prv(skb)->skbcnt)) while (!(can_skb_prv(skb)->skbcnt))
...@@ -699,10 +698,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev) ...@@ -699,10 +698,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
rcu_read_lock(); rcu_read_lock();
/* deliver the packet to sockets listening on all devices */ /* deliver the packet to sockets listening on all devices */
matches = can_rcv_filter(dev_net(dev)->can.can_rx_alldev_list, skb); matches = can_rcv_filter(net->can.can_rx_alldev_list, skb);
/* find receive list for this device */ /* find receive list for this device */
d = find_dev_rcv_lists(dev_net(dev), dev); d = find_dev_rcv_lists(net, dev);
if (d) if (d)
matches += can_rcv_filter(d, skb); matches += can_rcv_filter(d, skb);
...@@ -712,8 +711,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev) ...@@ -712,8 +711,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
consume_skb(skb); consume_skb(skb);
if (matches > 0) { if (matches > 0) {
can_stats.matches++; can_stats->matches++;
can_stats.matches_delta++; can_stats->matches_delta++;
} }
} }
...@@ -878,8 +877,20 @@ static int can_pernet_init(struct net *net) ...@@ -878,8 +877,20 @@ static int can_pernet_init(struct net *net)
net->can.can_rx_alldev_list = net->can.can_rx_alldev_list =
kzalloc(sizeof(struct dev_rcv_lists), GFP_KERNEL); kzalloc(sizeof(struct dev_rcv_lists), GFP_KERNEL);
if (IS_ENABLED(CONFIG_PROC_FS)) net->can.can_stats = kzalloc(sizeof(struct s_stats), GFP_KERNEL);
net->can.can_pstats = kzalloc(sizeof(struct s_pstats), GFP_KERNEL);
if (IS_ENABLED(CONFIG_PROC_FS)) {
/* the statistics are updated every second (timer triggered) */
if (stats_timer) {
setup_timer(&net->can.can_stattimer, can_stat_update,
(unsigned long)net);
mod_timer(&net->can.can_stattimer,
round_jiffies(jiffies + HZ));
}
net->can.can_stats->jiffies_init = jiffies;
can_init_proc(net); can_init_proc(net);
}
return 0; return 0;
} }
...@@ -888,8 +899,11 @@ static void can_pernet_exit(struct net *net) ...@@ -888,8 +899,11 @@ static void can_pernet_exit(struct net *net)
{ {
struct net_device *dev; struct net_device *dev;
if (IS_ENABLED(CONFIG_PROC_FS)) if (IS_ENABLED(CONFIG_PROC_FS)) {
can_remove_proc(net); can_remove_proc(net);
if (stats_timer)
del_timer_sync(&net->can.can_stattimer);
}
/* remove created dev_rcv_lists from still registered CAN devices */ /* remove created dev_rcv_lists from still registered CAN devices */
rcu_read_lock(); rcu_read_lock();
...@@ -903,6 +917,10 @@ static void can_pernet_exit(struct net *net) ...@@ -903,6 +917,10 @@ static void can_pernet_exit(struct net *net)
} }
} }
rcu_read_unlock(); rcu_read_unlock();
kfree(net->can.can_rx_alldev_list);
kfree(net->can.can_stats);
kfree(net->can.can_pstats);
} }
/* /*
...@@ -933,8 +951,6 @@ static struct notifier_block can_netdev_notifier __read_mostly = { ...@@ -933,8 +951,6 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
static struct pernet_operations can_pernet_ops __read_mostly = { static struct pernet_operations can_pernet_ops __read_mostly = {
.init = can_pernet_init, .init = can_pernet_init,
.exit = can_pernet_exit, .exit = can_pernet_exit,
.id = &can_net_id,
.size = 0,
}; };
static __init int can_init(void) static __init int can_init(void)
...@@ -952,14 +968,6 @@ static __init int can_init(void) ...@@ -952,14 +968,6 @@ static __init int can_init(void)
if (!rcv_cache) if (!rcv_cache)
return -ENOMEM; return -ENOMEM;
if (IS_ENABLED(CONFIG_PROC_FS)) {
if (stats_timer) {
/* the statistics are updated every second (timer triggered) */
setup_timer(&can_stattimer, can_stat_update, 0);
mod_timer(&can_stattimer, round_jiffies(jiffies + HZ));
}
}
register_pernet_subsys(&can_pernet_ops); register_pernet_subsys(&can_pernet_ops);
/* protocol register */ /* protocol register */
...@@ -973,11 +981,6 @@ static __init int can_init(void) ...@@ -973,11 +981,6 @@ static __init int can_init(void)
static __exit void can_exit(void) static __exit void can_exit(void)
{ {
if (IS_ENABLED(CONFIG_PROC_FS)) {
if (stats_timer)
del_timer_sync(&can_stattimer);
}
/* protocol unregister */ /* protocol unregister */
dev_remove_pack(&canfd_packet); dev_remove_pack(&canfd_packet);
dev_remove_pack(&can_packet); dev_remove_pack(&can_packet);
......
...@@ -110,18 +110,9 @@ struct s_pstats { ...@@ -110,18 +110,9 @@ struct s_pstats {
unsigned long rcv_entries_max; unsigned long rcv_entries_max;
}; };
/* receive filters subscribed for 'all' CAN devices */
extern struct dev_rcv_lists can_rx_alldev_list;
/* function prototypes for the CAN networklayer procfs (proc.c) */ /* function prototypes for the CAN networklayer procfs (proc.c) */
void can_init_proc(struct net *net); void can_init_proc(struct net *net);
void can_remove_proc(struct net *net); void can_remove_proc(struct net *net);
void can_stat_update(unsigned long data); void can_stat_update(unsigned long data);
/* structures and variables from af_can.c needed in proc.c for reading */
extern struct timer_list can_stattimer; /* timer for statistics update */
extern struct s_stats can_stats; /* packet statistics */
extern struct s_pstats can_pstats; /* receive list statistics */
extern struct hlist_head can_rx_dev_list; /* rx dispatcher structures */
#endif /* AF_CAN_H */ #endif /* AF_CAN_H */
/* /*
* bcm.c - Broadcast Manager to filter/send (cyclic) CAN content * bcm.c - Broadcast Manager to filter/send (cyclic) CAN content
* *
* Copyright (c) 2002-2016 Volkswagen Group Electronic Research * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
(CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \ (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \
(CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG)) (CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG))
#define CAN_BCM_VERSION "20161123" #define CAN_BCM_VERSION "20170425"
MODULE_DESCRIPTION("PF_CAN broadcast manager protocol"); MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
...@@ -118,8 +118,6 @@ struct bcm_op { ...@@ -118,8 +118,6 @@ struct bcm_op {
struct net_device *rx_reg_dev; struct net_device *rx_reg_dev;
}; };
static struct proc_dir_entry *proc_dir;
struct bcm_sock { struct bcm_sock {
struct sock sk; struct sock sk;
int bound; int bound;
...@@ -149,7 +147,7 @@ static inline ktime_t bcm_timeval_to_ktime(struct bcm_timeval tv) ...@@ -149,7 +147,7 @@ static inline ktime_t bcm_timeval_to_ktime(struct bcm_timeval tv)
/* /*
* procfs functions * procfs functions
*/ */
static char *bcm_proc_getifname(char *result, int ifindex) static char *bcm_proc_getifname(struct net *net, char *result, int ifindex)
{ {
struct net_device *dev; struct net_device *dev;
...@@ -157,7 +155,7 @@ static char *bcm_proc_getifname(char *result, int ifindex) ...@@ -157,7 +155,7 @@ static char *bcm_proc_getifname(char *result, int ifindex)
return "any"; return "any";
rcu_read_lock(); rcu_read_lock();
dev = dev_get_by_index_rcu(&init_net, ifindex); dev = dev_get_by_index_rcu(net, ifindex);
if (dev) if (dev)
strcpy(result, dev->name); strcpy(result, dev->name);
else else
...@@ -170,7 +168,8 @@ static char *bcm_proc_getifname(char *result, int ifindex) ...@@ -170,7 +168,8 @@ static char *bcm_proc_getifname(char *result, int ifindex)
static int bcm_proc_show(struct seq_file *m, void *v) static int bcm_proc_show(struct seq_file *m, void *v)
{ {
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
struct sock *sk = (struct sock *)m->private; struct net *net = m->private;
struct sock *sk = (struct sock *)PDE_DATA(m->file->f_inode);
struct bcm_sock *bo = bcm_sk(sk); struct bcm_sock *bo = bcm_sk(sk);
struct bcm_op *op; struct bcm_op *op;
...@@ -178,7 +177,7 @@ static int bcm_proc_show(struct seq_file *m, void *v) ...@@ -178,7 +177,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
seq_printf(m, " / sk %pK", sk); seq_printf(m, " / sk %pK", sk);
seq_printf(m, " / bo %pK", bo); seq_printf(m, " / bo %pK", bo);
seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs); seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
seq_printf(m, " / bound %s", bcm_proc_getifname(ifname, bo->ifindex)); seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
seq_printf(m, " <<<\n"); seq_printf(m, " <<<\n");
list_for_each_entry(op, &bo->rx_ops, list) { list_for_each_entry(op, &bo->rx_ops, list) {
...@@ -190,7 +189,7 @@ static int bcm_proc_show(struct seq_file *m, void *v) ...@@ -190,7 +189,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
continue; continue;
seq_printf(m, "rx_op: %03X %-5s ", op->can_id, seq_printf(m, "rx_op: %03X %-5s ", op->can_id,
bcm_proc_getifname(ifname, op->ifindex)); bcm_proc_getifname(net, ifname, op->ifindex));
if (op->flags & CAN_FD_FRAME) if (op->flags & CAN_FD_FRAME)
seq_printf(m, "(%u)", op->nframes); seq_printf(m, "(%u)", op->nframes);
...@@ -219,7 +218,7 @@ static int bcm_proc_show(struct seq_file *m, void *v) ...@@ -219,7 +218,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
list_for_each_entry(op, &bo->tx_ops, list) { list_for_each_entry(op, &bo->tx_ops, list) {
seq_printf(m, "tx_op: %03X %s ", op->can_id, seq_printf(m, "tx_op: %03X %s ", op->can_id,
bcm_proc_getifname(ifname, op->ifindex)); bcm_proc_getifname(net, ifname, op->ifindex));
if (op->flags & CAN_FD_FRAME) if (op->flags & CAN_FD_FRAME)
seq_printf(m, "(%u) ", op->nframes); seq_printf(m, "(%u) ", op->nframes);
...@@ -242,7 +241,7 @@ static int bcm_proc_show(struct seq_file *m, void *v) ...@@ -242,7 +241,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
static int bcm_proc_open(struct inode *inode, struct file *file) static int bcm_proc_open(struct inode *inode, struct file *file)
{ {
return single_open(file, bcm_proc_show, PDE_DATA(inode)); return single_open_net(inode, file, bcm_proc_show);
} }
static const struct file_operations bcm_proc_fops = { static const struct file_operations bcm_proc_fops = {
...@@ -267,7 +266,7 @@ static void bcm_can_tx(struct bcm_op *op) ...@@ -267,7 +266,7 @@ static void bcm_can_tx(struct bcm_op *op)
if (!op->ifindex) if (!op->ifindex)
return; return;
dev = dev_get_by_index(&init_net, op->ifindex); dev = dev_get_by_index(sock_net(op->sk), op->ifindex);
if (!dev) { if (!dev) {
/* RFC: should this bcm_op remove itself here? */ /* RFC: should this bcm_op remove itself here? */
return; return;
...@@ -764,7 +763,7 @@ static void bcm_remove_op(struct bcm_op *op) ...@@ -764,7 +763,7 @@ static void bcm_remove_op(struct bcm_op *op)
static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op) static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
{ {
if (op->rx_reg_dev == dev) { if (op->rx_reg_dev == dev) {
can_rx_unregister(&init_net, dev, op->can_id, can_rx_unregister(dev_net(dev), dev, op->can_id,
REGMASK(op->can_id), bcm_rx_handler, op); REGMASK(op->can_id), bcm_rx_handler, op);
/* mark as removed subscription */ /* mark as removed subscription */
...@@ -800,7 +799,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh, ...@@ -800,7 +799,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
if (op->rx_reg_dev) { if (op->rx_reg_dev) {
struct net_device *dev; struct net_device *dev;
dev = dev_get_by_index(&init_net, dev = dev_get_by_index(sock_net(op->sk),
op->ifindex); op->ifindex);
if (dev) { if (dev) {
bcm_rx_unreg(dev, op); bcm_rx_unreg(dev, op);
...@@ -808,7 +807,8 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh, ...@@ -808,7 +807,8 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
} }
} }
} else } else
can_rx_unregister(&init_net, NULL, op->can_id, can_rx_unregister(sock_net(op->sk), NULL,
op->can_id,
REGMASK(op->can_id), REGMASK(op->can_id),
bcm_rx_handler, op); bcm_rx_handler, op);
...@@ -1220,9 +1220,9 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, ...@@ -1220,9 +1220,9 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
if (ifindex) { if (ifindex) {
struct net_device *dev; struct net_device *dev;
dev = dev_get_by_index(&init_net, ifindex); dev = dev_get_by_index(sock_net(sk), ifindex);
if (dev) { if (dev) {
err = can_rx_register(&init_net, dev, err = can_rx_register(sock_net(sk), dev,
op->can_id, op->can_id,
REGMASK(op->can_id), REGMASK(op->can_id),
bcm_rx_handler, op, bcm_rx_handler, op,
...@@ -1233,7 +1233,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, ...@@ -1233,7 +1233,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
} }
} else } else
err = can_rx_register(&init_net, NULL, op->can_id, err = can_rx_register(sock_net(sk), NULL, op->can_id,
REGMASK(op->can_id), REGMASK(op->can_id),
bcm_rx_handler, op, "bcm", sk); bcm_rx_handler, op, "bcm", sk);
if (err) { if (err) {
...@@ -1273,7 +1273,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk, ...@@ -1273,7 +1273,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk,
return err; return err;
} }
dev = dev_get_by_index(&init_net, ifindex); dev = dev_get_by_index(sock_net(sk), ifindex);
if (!dev) { if (!dev) {
kfree_skb(skb); kfree_skb(skb);
return -ENODEV; return -ENODEV;
...@@ -1338,7 +1338,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -1338,7 +1338,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if (ifindex) { if (ifindex) {
struct net_device *dev; struct net_device *dev;
dev = dev_get_by_index(&init_net, ifindex); dev = dev_get_by_index(sock_net(sk), ifindex);
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
...@@ -1419,7 +1419,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg, ...@@ -1419,7 +1419,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
struct bcm_op *op; struct bcm_op *op;
int notify_enodev = 0; int notify_enodev = 0;
if (!net_eq(dev_net(dev), &init_net)) if (!net_eq(dev_net(dev), sock_net(sk)))
return NOTIFY_DONE; return NOTIFY_DONE;
if (dev->type != ARPHRD_CAN) if (dev->type != ARPHRD_CAN)
...@@ -1491,6 +1491,7 @@ static int bcm_init(struct sock *sk) ...@@ -1491,6 +1491,7 @@ static int bcm_init(struct sock *sk)
static int bcm_release(struct socket *sock) static int bcm_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct net *net = sock_net(sk);
struct bcm_sock *bo; struct bcm_sock *bo;
struct bcm_op *op, *next; struct bcm_op *op, *next;
...@@ -1522,14 +1523,14 @@ static int bcm_release(struct socket *sock) ...@@ -1522,14 +1523,14 @@ static int bcm_release(struct socket *sock)
if (op->rx_reg_dev) { if (op->rx_reg_dev) {
struct net_device *dev; struct net_device *dev;
dev = dev_get_by_index(&init_net, op->ifindex); dev = dev_get_by_index(net, op->ifindex);
if (dev) { if (dev) {
bcm_rx_unreg(dev, op); bcm_rx_unreg(dev, op);
dev_put(dev); dev_put(dev);
} }
} }
} else } else
can_rx_unregister(&init_net, NULL, op->can_id, can_rx_unregister(net, NULL, op->can_id,
REGMASK(op->can_id), REGMASK(op->can_id),
bcm_rx_handler, op); bcm_rx_handler, op);
...@@ -1537,8 +1538,8 @@ static int bcm_release(struct socket *sock) ...@@ -1537,8 +1538,8 @@ static int bcm_release(struct socket *sock)
} }
/* remove procfs entry */ /* remove procfs entry */
if (proc_dir && bo->bcm_proc_read) if (net->can.bcmproc_dir && bo->bcm_proc_read)
remove_proc_entry(bo->procname, proc_dir); remove_proc_entry(bo->procname, net->can.bcmproc_dir);
/* remove device reference */ /* remove device reference */
if (bo->bound) { if (bo->bound) {
...@@ -1561,6 +1562,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, ...@@ -1561,6 +1562,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct bcm_sock *bo = bcm_sk(sk); struct bcm_sock *bo = bcm_sk(sk);
struct net *net = sock_net(sk);
int ret = 0; int ret = 0;
if (len < sizeof(*addr)) if (len < sizeof(*addr))
...@@ -1577,7 +1579,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, ...@@ -1577,7 +1579,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
if (addr->can_ifindex) { if (addr->can_ifindex) {
struct net_device *dev; struct net_device *dev;
dev = dev_get_by_index(&init_net, addr->can_ifindex); dev = dev_get_by_index(net, addr->can_ifindex);
if (!dev) { if (!dev) {
ret = -ENODEV; ret = -ENODEV;
goto fail; goto fail;
...@@ -1596,11 +1598,11 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, ...@@ -1596,11 +1598,11 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
bo->ifindex = 0; bo->ifindex = 0;
} }
if (proc_dir) { if (net->can.bcmproc_dir) {
/* unique socket address as filename */ /* unique socket address as filename */
sprintf(bo->procname, "%lu", sock_i_ino(sk)); sprintf(bo->procname, "%lu", sock_i_ino(sk));
bo->bcm_proc_read = proc_create_data(bo->procname, 0644, bo->bcm_proc_read = proc_create_data(bo->procname, 0644,
proc_dir, net->can.bcmproc_dir,
&bcm_proc_fops, sk); &bcm_proc_fops, sk);
if (!bo->bcm_proc_read) { if (!bo->bcm_proc_read) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -1687,6 +1689,31 @@ static const struct can_proto bcm_can_proto = { ...@@ -1687,6 +1689,31 @@ static const struct can_proto bcm_can_proto = {
.prot = &bcm_proto, .prot = &bcm_proto,
}; };
static int canbcm_pernet_init(struct net *net)
{
/* create /proc/net/can-bcm directory */
if (IS_ENABLED(CONFIG_PROC_FS)) {
net->can.bcmproc_dir =
proc_net_mkdir(net, "can-bcm", net->proc_net);
}
return 0;
}
static void canbcm_pernet_exit(struct net *net)
{
/* remove /proc/net/can-bcm directory */
if (IS_ENABLED(CONFIG_PROC_FS)) {
if (net->can.bcmproc_dir)
remove_proc_entry("can-bcm", net->proc_net);
}
}
static struct pernet_operations canbcm_pernet_ops __read_mostly = {
.init = canbcm_pernet_init,
.exit = canbcm_pernet_exit,
};
static int __init bcm_module_init(void) static int __init bcm_module_init(void)
{ {
int err; int err;
...@@ -1699,17 +1726,14 @@ static int __init bcm_module_init(void) ...@@ -1699,17 +1726,14 @@ static int __init bcm_module_init(void)
return err; return err;
} }
/* create /proc/net/can-bcm directory */ register_pernet_subsys(&canbcm_pernet_ops);
proc_dir = proc_mkdir("can-bcm", init_net.proc_net);
return 0; return 0;
} }
static void __exit bcm_module_exit(void) static void __exit bcm_module_exit(void)
{ {
can_proto_unregister(&bcm_can_proto); can_proto_unregister(&bcm_can_proto);
unregister_pernet_subsys(&canbcm_pernet_ops);
if (proc_dir)
remove_proc_entry("can-bcm", init_net.proc_net);
} }
module_init(bcm_module_init); module_init(bcm_module_init);
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment