mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-davem' of git://gitorious.org/linux-can/linux-can-next
Marc Kleine-Budde says: ==================== this is a pull-request for net-next/master. There is are 9 patches by Fabio Baltieri and Kurt Van Dijck which add LED infrastructure and support for CAN devices. Bernd Krumboeck adds a driver for the USB CAN adapter from 8 devices. Oliver Hartkopp improves the CAN gateway functionality. There are 4 patches by me, which clean up the CAN's Kconfig. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
61550022b9
|
@ -1,9 +1,7 @@
|
|||
menu "CAN Device Drivers"
|
||||
depends on CAN
|
||||
|
||||
config CAN_VCAN
|
||||
tristate "Virtual Local CAN Interface (vcan)"
|
||||
depends on CAN
|
||||
---help---
|
||||
Similar to the network loopback devices, vcan offers a
|
||||
virtual local CAN interface.
|
||||
|
@ -13,7 +11,6 @@ config CAN_VCAN
|
|||
|
||||
config CAN_SLCAN
|
||||
tristate "Serial / USB serial CAN Adaptors (slcan)"
|
||||
depends on CAN
|
||||
---help---
|
||||
CAN driver for several 'low cost' CAN interfaces that are attached
|
||||
via serial lines or via USB-to-serial adapters using the LAWICEL
|
||||
|
@ -33,16 +30,16 @@ config CAN_SLCAN
|
|||
|
||||
config CAN_DEV
|
||||
tristate "Platform CAN drivers with Netlink support"
|
||||
depends on CAN
|
||||
default y
|
||||
---help---
|
||||
Enables the common framework for platform CAN drivers with Netlink
|
||||
support. This is the standard library for CAN drivers.
|
||||
If unsure, say Y.
|
||||
|
||||
if CAN_DEV
|
||||
|
||||
config CAN_CALC_BITTIMING
|
||||
bool "CAN bit-timing calculation"
|
||||
depends on CAN_DEV
|
||||
default y
|
||||
---help---
|
||||
If enabled, CAN bit-timing parameters will be calculated for the
|
||||
|
@ -54,15 +51,26 @@ config CAN_CALC_BITTIMING
|
|||
arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
|
||||
If unsure, say Y.
|
||||
|
||||
config CAN_LEDS
|
||||
bool "Enable LED triggers for Netlink based drivers"
|
||||
depends on LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
---help---
|
||||
This option adds two LED triggers for packet receive and transmit
|
||||
events on each supported CAN device.
|
||||
|
||||
Say Y here if you are working on a system with led-class supported
|
||||
LEDs and you want to use them as canbus activity indicators.
|
||||
|
||||
config CAN_AT91
|
||||
tristate "Atmel AT91 onchip CAN controller"
|
||||
depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5)
|
||||
depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
|
||||
---help---
|
||||
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
|
||||
and AT91SAM9X5 processors.
|
||||
|
||||
config CAN_TI_HECC
|
||||
depends on CAN_DEV && ARCH_OMAP3
|
||||
depends on ARCH_OMAP3
|
||||
tristate "TI High End CAN Controller"
|
||||
---help---
|
||||
Driver for TI HECC (High End CAN Controller) module found on many
|
||||
|
@ -70,12 +78,12 @@ config CAN_TI_HECC
|
|||
|
||||
config CAN_MCP251X
|
||||
tristate "Microchip MCP251x SPI CAN controllers"
|
||||
depends on CAN_DEV && SPI && HAS_DMA
|
||||
depends on SPI && HAS_DMA
|
||||
---help---
|
||||
Driver for the Microchip MCP251x SPI CAN controllers.
|
||||
|
||||
config CAN_BFIN
|
||||
depends on CAN_DEV && (BF534 || BF536 || BF537 || BF538 || BF539 || BF54x)
|
||||
depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
|
||||
tristate "Analog Devices Blackfin on-chip CAN"
|
||||
---help---
|
||||
Driver for the Analog Devices Blackfin on-chip CAN controllers
|
||||
|
@ -85,7 +93,7 @@ config CAN_BFIN
|
|||
|
||||
config CAN_JANZ_ICAN3
|
||||
tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
|
||||
depends on CAN_DEV && MFD_JANZ_CMODIO
|
||||
depends on MFD_JANZ_CMODIO
|
||||
---help---
|
||||
Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
|
||||
connects to a MODULbus carrier board.
|
||||
|
@ -98,13 +106,13 @@ config HAVE_CAN_FLEXCAN
|
|||
|
||||
config CAN_FLEXCAN
|
||||
tristate "Support for Freescale FLEXCAN based chips"
|
||||
depends on CAN_DEV && HAVE_CAN_FLEXCAN
|
||||
depends on HAVE_CAN_FLEXCAN
|
||||
---help---
|
||||
Say Y here if you want to support for Freescale FlexCAN.
|
||||
|
||||
config PCH_CAN
|
||||
tristate "Intel EG20T PCH CAN controller"
|
||||
depends on CAN_DEV && PCI
|
||||
depends on PCI
|
||||
---help---
|
||||
This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
|
||||
is an IOH for x86 embedded processor (Intel Atom E6xx series).
|
||||
|
@ -112,7 +120,7 @@ config PCH_CAN
|
|||
|
||||
config CAN_GRCAN
|
||||
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
|
||||
depends on CAN_DEV && OF
|
||||
depends on OF
|
||||
---help---
|
||||
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
|
||||
Note that the driver supports little endian, even though little
|
||||
|
@ -131,9 +139,10 @@ source "drivers/net/can/usb/Kconfig"
|
|||
|
||||
source "drivers/net/can/softing/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
config CAN_DEBUG_DEVICES
|
||||
bool "CAN devices debugging messages"
|
||||
depends on CAN
|
||||
---help---
|
||||
Say Y here if you want the CAN device drivers to produce a bunch of
|
||||
debug messages to the system log. Select this if you are having
|
||||
|
|
|
@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o
|
|||
obj-$(CONFIG_CAN_DEV) += can-dev.o
|
||||
can-dev-y := dev.o
|
||||
|
||||
can-dev-$(CONFIG_CAN_LEDS) += led.o
|
||||
|
||||
obj-y += usb/
|
||||
obj-y += softing/
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/led.h>
|
||||
|
||||
#define AT91_MB_MASK(i) ((1 << (i)) - 1)
|
||||
|
||||
|
@ -641,6 +642,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
|
|||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_RX);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -875,6 +878,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
|
|||
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
|
||||
can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
|
||||
dev->stats.tx_packets++;
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1128,6 +1132,8 @@ static int at91_open(struct net_device *dev)
|
|||
goto out_close;
|
||||
}
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_OPEN);
|
||||
|
||||
/* start chip and queuing */
|
||||
at91_chip_start(dev);
|
||||
napi_enable(&priv->napi);
|
||||
|
@ -1159,6 +1165,8 @@ static int at91_close(struct net_device *dev)
|
|||
|
||||
close_candev(dev);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1321,6 +1329,8 @@ static int at91_can_probe(struct platform_device *pdev)
|
|||
goto exit_free;
|
||||
}
|
||||
|
||||
devm_can_led_init(dev);
|
||||
|
||||
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
|
||||
priv->reg_base, dev->irq);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
menuconfig CAN_C_CAN
|
||||
tristate "Bosch C_CAN/D_CAN devices"
|
||||
depends on CAN_DEV && HAS_IOMEM
|
||||
depends on HAS_IOMEM
|
||||
|
||||
if CAN_C_CAN
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <linux/can.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/led.h>
|
||||
|
||||
#include "c_can.h"
|
||||
|
||||
|
@ -477,6 +478,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
|
|||
stats->rx_packets++;
|
||||
stats->rx_bytes += frame->can_dlc;
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_RX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -751,6 +754,7 @@ static void c_can_do_tx(struct net_device *dev)
|
|||
C_CAN_IFACE(MSGCTRL_REG, 0))
|
||||
& IF_MCONT_DLC_MASK;
|
||||
stats->tx_packets++;
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
c_can_inval_msg_object(dev, 0, msg_obj_no);
|
||||
} else {
|
||||
break;
|
||||
|
@ -1115,6 +1119,8 @@ static int c_can_open(struct net_device *dev)
|
|||
|
||||
napi_enable(&priv->napi);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_OPEN);
|
||||
|
||||
/* start the c_can controller */
|
||||
c_can_start(dev);
|
||||
|
||||
|
@ -1143,6 +1149,8 @@ static int c_can_close(struct net_device *dev)
|
|||
c_can_reset_ram(priv, false);
|
||||
c_can_pm_runtime_put_sync(priv);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1268,6 +1276,8 @@ int register_c_can_dev(struct net_device *dev)
|
|||
err = register_candev(dev);
|
||||
if (err)
|
||||
c_can_pm_runtime_disable(priv);
|
||||
else
|
||||
devm_can_led_init(dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
menuconfig CAN_CC770
|
||||
tristate "Bosch CC770 and Intel AN82527 devices"
|
||||
depends on CAN_DEV && HAS_IOMEM
|
||||
depends on HAS_IOMEM
|
||||
|
||||
if CAN_CC770
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
#include <linux/if_arp.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/can/led.h>
|
||||
#include <net/rtnetlink.h>
|
||||
|
||||
#define MOD_DESC "CAN device driver interface"
|
||||
|
@ -501,13 +503,18 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
|||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = netdev_alloc_skb(dev, sizeof(struct can_frame));
|
||||
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
||||
sizeof(struct can_frame));
|
||||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reserve(skb, sizeof(struct can_skb_priv));
|
||||
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
|
||||
|
||||
*cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
|
||||
memset(*cf, 0, sizeof(struct can_frame));
|
||||
|
||||
|
@ -794,10 +801,25 @@ void unregister_candev(struct net_device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_candev);
|
||||
|
||||
/*
|
||||
* Test if a network device is a candev based device
|
||||
* and return the can_priv* if so.
|
||||
*/
|
||||
struct can_priv *safe_candev_priv(struct net_device *dev)
|
||||
{
|
||||
if ((dev->type != ARPHRD_CAN) || (dev->rtnl_link_ops != &can_link_ops))
|
||||
return NULL;
|
||||
|
||||
return netdev_priv(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(safe_candev_priv);
|
||||
|
||||
static __init int can_dev_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
can_led_notifier_init();
|
||||
|
||||
err = rtnl_link_register(&can_link_ops);
|
||||
if (!err)
|
||||
printk(KERN_INFO MOD_DESC "\n");
|
||||
|
@ -809,6 +831,8 @@ module_init(can_dev_init);
|
|||
static __exit void can_dev_exit(void)
|
||||
{
|
||||
rtnl_link_unregister(&can_link_ops);
|
||||
|
||||
can_led_notifier_exit();
|
||||
}
|
||||
module_exit(can_dev_exit);
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/can.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/led.h>
|
||||
#include <linux/can/platform/flexcan.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -564,6 +565,8 @@ static int flexcan_read_frame(struct net_device *dev)
|
|||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_RX);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -652,6 +655,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|||
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
|
||||
stats->tx_bytes += can_get_echo_skb(dev, 0);
|
||||
stats->tx_packets++;
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
flexcan_write((1 << FLEXCAN_TX_BUF_ID), ®s->iflag1);
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
@ -865,6 +869,9 @@ static int flexcan_open(struct net_device *dev)
|
|||
err = flexcan_chip_start(dev);
|
||||
if (err)
|
||||
goto out_close;
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_OPEN);
|
||||
|
||||
napi_enable(&priv->napi);
|
||||
netif_start_queue(dev);
|
||||
|
||||
|
@ -893,6 +900,8 @@ static int flexcan_close(struct net_device *dev)
|
|||
|
||||
close_candev(dev);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1092,6 +1101,8 @@ static int flexcan_probe(struct platform_device *pdev)
|
|||
goto failed_register;
|
||||
}
|
||||
|
||||
devm_can_led_init(dev);
|
||||
|
||||
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
|
||||
priv->base, dev->irq);
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
|
||||
* Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
#include <linux/can/led.h>
|
||||
|
||||
static unsigned long led_delay = 50;
|
||||
module_param(led_delay, ulong, 0644);
|
||||
MODULE_PARM_DESC(led_delay,
|
||||
"blink delay time for activity leds (msecs, default: 50).");
|
||||
|
||||
/* Trigger a LED event in response to a CAN device event */
|
||||
void can_led_event(struct net_device *netdev, enum can_led_event event)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(netdev);
|
||||
|
||||
switch (event) {
|
||||
case CAN_LED_EVENT_OPEN:
|
||||
led_trigger_event(priv->tx_led_trig, LED_FULL);
|
||||
led_trigger_event(priv->rx_led_trig, LED_FULL);
|
||||
break;
|
||||
case CAN_LED_EVENT_STOP:
|
||||
led_trigger_event(priv->tx_led_trig, LED_OFF);
|
||||
led_trigger_event(priv->rx_led_trig, LED_OFF);
|
||||
break;
|
||||
case CAN_LED_EVENT_TX:
|
||||
if (led_delay)
|
||||
led_trigger_blink_oneshot(priv->tx_led_trig,
|
||||
&led_delay, &led_delay, 1);
|
||||
break;
|
||||
case CAN_LED_EVENT_RX:
|
||||
if (led_delay)
|
||||
led_trigger_blink_oneshot(priv->rx_led_trig,
|
||||
&led_delay, &led_delay, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_led_event);
|
||||
|
||||
static void can_led_release(struct device *gendev, void *res)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(to_net_dev(gendev));
|
||||
|
||||
led_trigger_unregister_simple(priv->tx_led_trig);
|
||||
led_trigger_unregister_simple(priv->rx_led_trig);
|
||||
}
|
||||
|
||||
/* Register CAN LED triggers for a CAN device
|
||||
*
|
||||
* This is normally called from a driver's probe function
|
||||
*/
|
||||
void devm_can_led_init(struct net_device *netdev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(netdev);
|
||||
void *res;
|
||||
|
||||
res = devres_alloc(can_led_release, 0, GFP_KERNEL);
|
||||
if (!res) {
|
||||
netdev_err(netdev, "cannot register LED triggers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name),
|
||||
"%s-tx", netdev->name);
|
||||
snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name),
|
||||
"%s-rx", netdev->name);
|
||||
|
||||
led_trigger_register_simple(priv->tx_led_trig_name,
|
||||
&priv->tx_led_trig);
|
||||
led_trigger_register_simple(priv->rx_led_trig_name,
|
||||
&priv->rx_led_trig);
|
||||
|
||||
devres_add(&netdev->dev, res);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_can_led_init);
|
||||
|
||||
/* NETDEV rename notifier to rename the associated led triggers too */
|
||||
static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
|
||||
void *data)
|
||||
{
|
||||
struct net_device *netdev = data;
|
||||
struct can_priv *priv = safe_candev_priv(netdev);
|
||||
char name[CAN_LED_NAME_SZ];
|
||||
|
||||
if (!priv)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (msg == NETDEV_CHANGENAME) {
|
||||
snprintf(name, sizeof(name), "%s-tx", netdev->name);
|
||||
led_trigger_rename_static(name, priv->tx_led_trig);
|
||||
|
||||
snprintf(name, sizeof(name), "%s-rx", netdev->name);
|
||||
led_trigger_rename_static(name, priv->rx_led_trig);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/* notifier block for netdevice event */
|
||||
static struct notifier_block can_netdev_notifier __read_mostly = {
|
||||
.notifier_call = can_led_notifier,
|
||||
};
|
||||
|
||||
int __init can_led_notifier_init(void)
|
||||
{
|
||||
return register_netdevice_notifier(&can_netdev_notifier);
|
||||
}
|
||||
|
||||
void __exit can_led_notifier_exit(void)
|
||||
{
|
||||
unregister_netdevice_notifier(&can_netdev_notifier);
|
||||
}
|
|
@ -60,6 +60,7 @@
|
|||
|
||||
#include <linux/can/core.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/led.h>
|
||||
#include <linux/can/platform/mcp251x.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -494,6 +495,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
|
|||
|
||||
priv->net->stats.rx_packets++;
|
||||
priv->net->stats.rx_bytes += frame->can_dlc;
|
||||
|
||||
can_led_event(priv->net, CAN_LED_EVENT_RX);
|
||||
|
||||
netif_rx_ni(skb);
|
||||
}
|
||||
|
||||
|
@ -707,6 +711,8 @@ static int mcp251x_stop(struct net_device *net)
|
|||
|
||||
mutex_unlock(&priv->mcp_lock);
|
||||
|
||||
can_led_event(net, CAN_LED_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -905,6 +911,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
|
|||
if (intf & CANINTF_TX) {
|
||||
net->stats.tx_packets++;
|
||||
net->stats.tx_bytes += priv->tx_len - 1;
|
||||
can_led_event(net, CAN_LED_EVENT_TX);
|
||||
if (priv->tx_len) {
|
||||
can_get_echo_skb(net, 0);
|
||||
priv->tx_len = 0;
|
||||
|
@ -968,6 +975,9 @@ static int mcp251x_open(struct net_device *net)
|
|||
mcp251x_open_clean(net);
|
||||
goto open_unlock;
|
||||
}
|
||||
|
||||
can_led_event(net, CAN_LED_EVENT_OPEN);
|
||||
|
||||
netif_wake_queue(net);
|
||||
|
||||
open_unlock:
|
||||
|
@ -1077,10 +1087,15 @@ static int mcp251x_can_probe(struct spi_device *spi)
|
|||
pdata->transceiver_enable(0);
|
||||
|
||||
ret = register_candev(net);
|
||||
if (!ret) {
|
||||
dev_info(&spi->dev, "probed\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto error_probe;
|
||||
|
||||
devm_can_led_init(net);
|
||||
|
||||
dev_info(&spi->dev, "probed\n");
|
||||
|
||||
return ret;
|
||||
|
||||
error_probe:
|
||||
if (!mcp251x_enable_dma)
|
||||
kfree(priv->spi_rx_buf);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
config CAN_MSCAN
|
||||
depends on CAN_DEV && (PPC || M68K)
|
||||
depends on PPC || M68K
|
||||
tristate "Support for Freescale MSCAN based chips"
|
||||
---help---
|
||||
The Motorola Scalable Controller Area Network (MSCAN) definition
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
menuconfig CAN_SJA1000
|
||||
tristate "Philips/NXP SJA1000 devices"
|
||||
depends on CAN_DEV && HAS_IOMEM
|
||||
depends on HAS_IOMEM
|
||||
|
||||
if CAN_SJA1000
|
||||
|
||||
|
@ -99,11 +99,11 @@ config CAN_TSCAN1
|
|||
tristate "TS-CAN1 PC104 boards"
|
||||
depends on ISA
|
||||
help
|
||||
This driver is for Technologic Systems' TSCAN-1 PC104 boards.
|
||||
http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
|
||||
The driver supports multiple boards and automatically configures them:
|
||||
PLD IO base addresses are read from jumpers JP1 and JP2,
|
||||
IRQ numbers are read from jumpers JP4 and JP5,
|
||||
SJA1000 IO base addresses are chosen heuristically (first that works).
|
||||
This driver is for Technologic Systems' TSCAN-1 PC104 boards.
|
||||
http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
|
||||
The driver supports multiple boards and automatically configures them:
|
||||
PLD IO base addresses are read from jumpers JP1 and JP2,
|
||||
IRQ numbers are read from jumpers JP4 and JP5,
|
||||
SJA1000 IO base addresses are chosen heuristically (first that works).
|
||||
|
||||
endif
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/led.h>
|
||||
|
||||
#include "sja1000.h"
|
||||
|
||||
|
@ -368,6 +369,8 @@ static void sja1000_rx(struct net_device *dev)
|
|||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_RX);
|
||||
}
|
||||
|
||||
static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
|
||||
|
@ -521,6 +524,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
|
|||
can_get_echo_skb(dev, 0);
|
||||
}
|
||||
netif_wake_queue(dev);
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
}
|
||||
if (isrc & IRQ_RI) {
|
||||
/* receive interrupt */
|
||||
|
@ -575,6 +579,8 @@ static int sja1000_open(struct net_device *dev)
|
|||
/* init and start chi */
|
||||
sja1000_start(dev);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_OPEN);
|
||||
|
||||
netif_start_queue(dev);
|
||||
|
||||
return 0;
|
||||
|
@ -592,6 +598,8 @@ static int sja1000_close(struct net_device *dev)
|
|||
|
||||
close_candev(dev);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -639,6 +647,8 @@ static const struct net_device_ops sja1000_netdev_ops = {
|
|||
|
||||
int register_sja1000dev(struct net_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sja1000_probe_chip(dev))
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -648,7 +658,12 @@ int register_sja1000dev(struct net_device *dev)
|
|||
set_reset_mode(dev);
|
||||
chipset_init(dev);
|
||||
|
||||
return register_candev(dev);
|
||||
ret = register_candev(dev);
|
||||
|
||||
if (!ret)
|
||||
devm_can_led_init(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_sja1000dev);
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/skb.h>
|
||||
|
||||
static __initconst const char banner[] =
|
||||
KERN_INFO "slcan: serial line CAN interface driver\n";
|
||||
|
@ -184,7 +185,8 @@ static void slc_bump(struct slcan *sl)
|
|||
cf.data[i] |= tmp;
|
||||
}
|
||||
|
||||
skb = dev_alloc_skb(sizeof(struct can_frame));
|
||||
skb = dev_alloc_skb(sizeof(struct can_frame) +
|
||||
sizeof(struct can_skb_priv));
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
|
@ -192,6 +194,10 @@ static void slc_bump(struct slcan *sl)
|
|||
skb->protocol = htons(ETH_P_CAN);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reserve(skb, sizeof(struct can_skb_priv));
|
||||
((struct can_skb_priv *)(skb->head))->ifindex = sl->dev->ifindex;
|
||||
|
||||
memcpy(skb_put(skb, sizeof(struct can_frame)),
|
||||
&cf, sizeof(struct can_frame));
|
||||
netif_rx_ni(skb);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config CAN_SOFTING
|
||||
tristate "Softing Gmbh CAN generic support"
|
||||
depends on CAN_DEV && HAS_IOMEM
|
||||
depends on HAS_IOMEM
|
||||
---help---
|
||||
Support for CAN cards from Softing Gmbh & some cards
|
||||
from Vector Gmbh.
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/led.h>
|
||||
#include <linux/can/platform/ti_hecc.h>
|
||||
|
||||
#define DRV_NAME "ti_hecc"
|
||||
|
@ -593,6 +594,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
|
|||
spin_unlock_irqrestore(&priv->mbx_lock, flags);
|
||||
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
can_led_event(priv->ndev, CAN_LED_EVENT_RX);
|
||||
netif_receive_skb(skb);
|
||||
stats->rx_packets++;
|
||||
|
||||
|
@ -796,6 +798,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
|
|||
stats->tx_bytes += hecc_read_mbx(priv, mbxno,
|
||||
HECC_CANMCF) & 0xF;
|
||||
stats->tx_packets++;
|
||||
can_led_event(ndev, CAN_LED_EVENT_TX);
|
||||
can_get_echo_skb(ndev, mbxno);
|
||||
--priv->tx_tail;
|
||||
}
|
||||
|
@ -851,6 +854,8 @@ static int ti_hecc_open(struct net_device *ndev)
|
|||
return err;
|
||||
}
|
||||
|
||||
can_led_event(ndev, CAN_LED_EVENT_OPEN);
|
||||
|
||||
ti_hecc_start(ndev);
|
||||
napi_enable(&priv->napi);
|
||||
netif_start_queue(ndev);
|
||||
|
@ -869,6 +874,8 @@ static int ti_hecc_close(struct net_device *ndev)
|
|||
close_candev(ndev);
|
||||
ti_hecc_transceiver_switch(priv, 0);
|
||||
|
||||
can_led_event(ndev, CAN_LED_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -961,6 +968,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "register_candev() failed\n");
|
||||
goto probe_exit_clk;
|
||||
}
|
||||
|
||||
devm_can_led_init(ndev);
|
||||
|
||||
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
|
||||
priv->base, (u32) ndev->irq);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
menu "CAN USB interfaces"
|
||||
depends on USB && CAN_DEV
|
||||
depends on USB
|
||||
|
||||
config CAN_EMS_USB
|
||||
tristate "EMS CPC-USB/ARM7 CAN/USB interface"
|
||||
|
@ -48,4 +48,10 @@ config CAN_PEAK_USB
|
|||
This driver supports the PCAN-USB and PCAN-USB Pro adapters
|
||||
from PEAK-System Technik (http://www.peak-system.com).
|
||||
|
||||
config CAN_8DEV_USB
|
||||
tristate "8 devices USB2CAN interface"
|
||||
---help---
|
||||
This driver supports the USB2CAN interface
|
||||
from 8 devices (http://www.8devices.com).
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -6,5 +6,6 @@ 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/
|
||||
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
|
||||
|
||||
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,6 +16,7 @@
|
|||
#include <linux/can.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/led.h>
|
||||
|
||||
/*
|
||||
* CAN mode
|
||||
|
@ -52,6 +53,13 @@ struct can_priv {
|
|||
|
||||
unsigned int echo_skb_max;
|
||||
struct sk_buff **echo_skb;
|
||||
|
||||
#ifdef CONFIG_CAN_LEDS
|
||||
struct led_trigger *tx_led_trig;
|
||||
char tx_led_trig_name[CAN_LED_NAME_SZ];
|
||||
struct led_trigger *rx_led_trig;
|
||||
char rx_led_trig_name[CAN_LED_NAME_SZ];
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -98,6 +106,9 @@ u8 can_len2dlc(u8 len);
|
|||
struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
|
||||
void free_candev(struct net_device *dev);
|
||||
|
||||
/* a candev safe wrapper around netdev_priv */
|
||||
struct can_priv *safe_candev_priv(struct net_device *dev);
|
||||
|
||||
int open_candev(struct net_device *dev);
|
||||
void close_candev(struct net_device *dev);
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef CAN_LED_H
|
||||
#define CAN_LED_H
|
||||
|
||||
#include <linux/if.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
enum can_led_event {
|
||||
CAN_LED_EVENT_OPEN,
|
||||
CAN_LED_EVENT_STOP,
|
||||
CAN_LED_EVENT_TX,
|
||||
CAN_LED_EVENT_RX,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CAN_LEDS
|
||||
|
||||
/* keep space for interface name + "-tx"/"-rx" suffix and null terminator */
|
||||
#define CAN_LED_NAME_SZ (IFNAMSIZ + 4)
|
||||
|
||||
void can_led_event(struct net_device *netdev, enum can_led_event event);
|
||||
void devm_can_led_init(struct net_device *netdev);
|
||||
int __init can_led_notifier_init(void);
|
||||
void __exit can_led_notifier_exit(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline void can_led_event(struct net_device *netdev,
|
||||
enum can_led_event event)
|
||||
{
|
||||
}
|
||||
static inline void devm_can_led_init(struct net_device *netdev)
|
||||
{
|
||||
}
|
||||
static inline int can_led_notifier_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void can_led_notifier_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* linux/can/skb.h
|
||||
*
|
||||
* Definitions for the CAN network socket buffer
|
||||
*
|
||||
* Copyright (C) 2012 Oliver Hartkopp <socketcan@hartkopp.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CAN_SKB_H
|
||||
#define CAN_SKB_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/can.h>
|
||||
|
||||
/*
|
||||
* The struct can_skb_priv is used to transport additional information along
|
||||
* with the stored struct can(fd)_frame that can not be contained in existing
|
||||
* struct sk_buff elements.
|
||||
* N.B. that this information must not be modified in cloned CAN sk_buffs.
|
||||
* To modify the CAN frame content or the struct can_skb_priv content
|
||||
* skb_copy() needs to be used instead of skb_clone().
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct can_skb_priv - private additional data inside CAN sk_buffs
|
||||
* @ifindex: ifindex of the first interface the CAN frame appeared on
|
||||
* @cf: align to the following CAN frame at skb->data
|
||||
*/
|
||||
struct can_skb_priv {
|
||||
int ifindex;
|
||||
struct can_frame cf[0];
|
||||
};
|
||||
|
||||
#endif /* CAN_SKB_H */
|
|
@ -44,6 +44,7 @@ enum {
|
|||
CGW_SRC_IF, /* ifindex of source network interface */
|
||||
CGW_DST_IF, /* ifindex of destination network interface */
|
||||
CGW_FILTER, /* specify struct can_filter on source CAN device */
|
||||
CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
|
||||
__CGW_MAX
|
||||
};
|
||||
|
||||
|
@ -51,6 +52,7 @@ enum {
|
|||
|
||||
#define CGW_FLAGS_CAN_ECHO 0x01
|
||||
#define CGW_FLAGS_CAN_SRC_TSTAMP 0x02
|
||||
#define CGW_FLAGS_CAN_IIF_TX_OK 0x04
|
||||
|
||||
#define CGW_MOD_FUNCS 4 /* AND OR XOR SET */
|
||||
|
||||
|
|
|
@ -16,10 +16,11 @@ menuconfig CAN
|
|||
If you want CAN support you should say Y here and also to the
|
||||
specific driver for your controller(s) below.
|
||||
|
||||
if CAN
|
||||
|
||||
config CAN_RAW
|
||||
tristate "Raw CAN Protocol (raw access with CAN-ID filtering)"
|
||||
depends on CAN
|
||||
default N
|
||||
default y
|
||||
---help---
|
||||
The raw CAN protocol option offers access to the CAN bus via
|
||||
the BSD socket API. You probably want to use the raw socket in
|
||||
|
@ -29,8 +30,7 @@ config CAN_RAW
|
|||
|
||||
config CAN_BCM
|
||||
tristate "Broadcast Manager CAN Protocol (with content filtering)"
|
||||
depends on CAN
|
||||
default N
|
||||
default y
|
||||
---help---
|
||||
The Broadcast Manager offers content filtering, timeout monitoring,
|
||||
sending of RTR frames, and cyclic CAN messages without permanent user
|
||||
|
@ -42,8 +42,7 @@ config CAN_BCM
|
|||
|
||||
config CAN_GW
|
||||
tristate "CAN Gateway/Router (with netlink configuration)"
|
||||
depends on CAN
|
||||
default N
|
||||
default y
|
||||
---help---
|
||||
The CAN Gateway/Router is used to route (and modify) CAN frames.
|
||||
It is based on the PF_CAN core infrastructure for msg filtering and
|
||||
|
@ -53,3 +52,5 @@ config CAN_GW
|
|||
by the netlink configuration interface known e.g. from iptables.
|
||||
|
||||
source "drivers/net/can/Kconfig"
|
||||
|
||||
endif
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/core.h>
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/can/bcm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/sock.h>
|
||||
|
@ -256,10 +257,13 @@ static void bcm_can_tx(struct bcm_op *op)
|
|||
return;
|
||||
}
|
||||
|
||||
skb = alloc_skb(CFSIZ, gfp_any());
|
||||
skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), gfp_any());
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
skb_reserve(skb, sizeof(struct can_skb_priv));
|
||||
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
|
||||
|
||||
memcpy(skb_put(skb, CFSIZ), cf, CFSIZ);
|
||||
|
||||
/* send with loopback */
|
||||
|
@ -1199,11 +1203,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
|
|||
if (!ifindex)
|
||||
return -ENODEV;
|
||||
|
||||
skb = alloc_skb(CFSIZ, GFP_KERNEL);
|
||||
|
||||
skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_reserve(skb, sizeof(struct can_skb_priv));
|
||||
|
||||
err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, CFSIZ);
|
||||
if (err < 0) {
|
||||
kfree_skb(skb);
|
||||
|
@ -1216,6 +1221,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
|
||||
skb->dev = dev;
|
||||
skb->sk = sk;
|
||||
err = can_send(skb, 1); /* send with loopback */
|
||||
|
|
74
net/can/gw.c
74
net/can/gw.c
|
@ -42,6 +42,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
@ -52,19 +53,31 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/core.h>
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/can/gw.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#define CAN_GW_VERSION "20101209"
|
||||
static __initconst const char banner[] =
|
||||
KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
|
||||
#define CAN_GW_VERSION "20130117"
|
||||
#define CAN_GW_NAME "can-gw"
|
||||
|
||||
MODULE_DESCRIPTION("PF_CAN netlink gateway");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
|
||||
MODULE_ALIAS("can-gw");
|
||||
MODULE_ALIAS(CAN_GW_NAME);
|
||||
|
||||
#define CGW_MIN_HOPS 1
|
||||
#define CGW_MAX_HOPS 6
|
||||
#define CGW_DEFAULT_HOPS 1
|
||||
|
||||
static unsigned int max_hops __read_mostly = CGW_DEFAULT_HOPS;
|
||||
module_param(max_hops, uint, S_IRUGO);
|
||||
MODULE_PARM_DESC(max_hops,
|
||||
"maximum " CAN_GW_NAME " routing hops for CAN frames "
|
||||
"(valid values: " __stringify(CGW_MIN_HOPS) "-"
|
||||
__stringify(CGW_MAX_HOPS) " hops, "
|
||||
"default: " __stringify(CGW_DEFAULT_HOPS) ")");
|
||||
|
||||
static HLIST_HEAD(cgw_list);
|
||||
static struct notifier_block notifier;
|
||||
|
@ -118,6 +131,7 @@ struct cgw_job {
|
|||
struct rcu_head rcu;
|
||||
u32 handled_frames;
|
||||
u32 dropped_frames;
|
||||
u32 deleted_frames;
|
||||
struct cf_mod mod;
|
||||
union {
|
||||
/* CAN frame data source */
|
||||
|
@ -338,15 +352,40 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
|
|||
struct sk_buff *nskb;
|
||||
int modidx = 0;
|
||||
|
||||
/* do not handle already routed frames - see comment below */
|
||||
if (skb_mac_header_was_set(skb))
|
||||
/*
|
||||
* Do not handle CAN frames routed more than 'max_hops' times.
|
||||
* In general we should never catch this delimiter which is intended
|
||||
* to cover a misconfiguration protection (e.g. circular CAN routes).
|
||||
*
|
||||
* The Controller Area Network controllers only accept CAN frames with
|
||||
* correct CRCs - which are not visible in the controller registers.
|
||||
* According to skbuff.h documentation the csum_start element for IP
|
||||
* checksums is undefined/unsued when ip_summed == CHECKSUM_UNNECESSARY.
|
||||
* Only CAN skbs can be processed here which already have this property.
|
||||
*/
|
||||
|
||||
#define cgw_hops(skb) ((skb)->csum_start)
|
||||
|
||||
BUG_ON(skb->ip_summed != CHECKSUM_UNNECESSARY);
|
||||
|
||||
if (cgw_hops(skb) >= max_hops) {
|
||||
/* indicate deleted frames due to misconfiguration */
|
||||
gwj->deleted_frames++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(gwj->dst.dev->flags & IFF_UP)) {
|
||||
gwj->dropped_frames++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* is sending the skb back to the incoming interface not allowed? */
|
||||
if (!(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK) &&
|
||||
skb_headroom(skb) == sizeof(struct can_skb_priv) &&
|
||||
(((struct can_skb_priv *)(skb->head))->ifindex ==
|
||||
gwj->dst.dev->ifindex))
|
||||
return;
|
||||
|
||||
/*
|
||||
* clone the given skb, which has not been done in can_rcv()
|
||||
*
|
||||
|
@ -363,15 +402,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark routed frames by setting some mac header length which is
|
||||
* not relevant for the CAN frames located in the skb->data section.
|
||||
*
|
||||
* As dev->header_ops is not set in CAN netdevices no one is ever
|
||||
* accessing the various header offsets in the CAN skbuffs anyway.
|
||||
* E.g. using the packet socket to read CAN frames is still working.
|
||||
*/
|
||||
skb_set_mac_header(nskb, 8);
|
||||
/* put the incremented hop counter in the cloned skb */
|
||||
cgw_hops(nskb) = cgw_hops(skb) + 1;
|
||||
nskb->dev = gwj->dst.dev;
|
||||
|
||||
/* pointer to modifiable CAN frame */
|
||||
|
@ -472,6 +504,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
|
|||
goto cancel;
|
||||
}
|
||||
|
||||
if (gwj->deleted_frames) {
|
||||
if (nla_put_u32(skb, CGW_DELETED, gwj->deleted_frames) < 0)
|
||||
goto cancel;
|
||||
}
|
||||
|
||||
/* check non default settings of attributes */
|
||||
|
||||
if (gwj->mod.modtype.and) {
|
||||
|
@ -771,6 +808,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
|
||||
gwj->handled_frames = 0;
|
||||
gwj->dropped_frames = 0;
|
||||
gwj->deleted_frames = 0;
|
||||
gwj->flags = r->flags;
|
||||
gwj->gwtype = r->gwtype;
|
||||
|
||||
|
@ -895,7 +933,11 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
|||
|
||||
static __init int cgw_module_init(void)
|
||||
{
|
||||
printk(banner);
|
||||
/* sanitize given module parameter */
|
||||
max_hops = clamp_t(unsigned int, max_hops, CGW_MIN_HOPS, CGW_MAX_HOPS);
|
||||
|
||||
pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n",
|
||||
max_hops);
|
||||
|
||||
cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
|
||||
0, 0, NULL);
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/core.h>
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
@ -699,11 +700,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
|
|||
if (!dev)
|
||||
return -ENXIO;
|
||||
|
||||
skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
|
||||
&err);
|
||||
skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv),
|
||||
msg->msg_flags & MSG_DONTWAIT, &err);
|
||||
if (!skb)
|
||||
goto put_dev;
|
||||
|
||||
skb_reserve(skb, sizeof(struct can_skb_priv));
|
||||
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
|
||||
|
||||
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
|
||||
if (err < 0)
|
||||
goto free_skb;
|
||||
|
|
Loading…
Reference in New Issue