Commit 61550022 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 0e36cbb3 e6afa00a
menu "CAN Device Drivers" menu "CAN Device Drivers"
depends on CAN
config CAN_VCAN config CAN_VCAN
tristate "Virtual Local CAN Interface (vcan)" tristate "Virtual Local CAN Interface (vcan)"
depends on CAN
---help--- ---help---
Similar to the network loopback devices, vcan offers a Similar to the network loopback devices, vcan offers a
virtual local CAN interface. virtual local CAN interface.
...@@ -13,7 +11,6 @@ config CAN_VCAN ...@@ -13,7 +11,6 @@ config CAN_VCAN
config CAN_SLCAN config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)" tristate "Serial / USB serial CAN Adaptors (slcan)"
depends on CAN
---help--- ---help---
CAN driver for several 'low cost' CAN interfaces that are attached CAN driver for several 'low cost' CAN interfaces that are attached
via serial lines or via USB-to-serial adapters using the LAWICEL via serial lines or via USB-to-serial adapters using the LAWICEL
...@@ -33,16 +30,16 @@ config CAN_SLCAN ...@@ -33,16 +30,16 @@ config CAN_SLCAN
config CAN_DEV config CAN_DEV
tristate "Platform CAN drivers with Netlink support" tristate "Platform CAN drivers with Netlink support"
depends on CAN
default y default y
---help--- ---help---
Enables the common framework for platform CAN drivers with Netlink Enables the common framework for platform CAN drivers with Netlink
support. This is the standard library for CAN drivers. support. This is the standard library for CAN drivers.
If unsure, say Y. If unsure, say Y.
if CAN_DEV
config CAN_CALC_BITTIMING config CAN_CALC_BITTIMING
bool "CAN bit-timing calculation" bool "CAN bit-timing calculation"
depends on CAN_DEV
default y default y
---help--- ---help---
If enabled, CAN bit-timing parameters will be calculated for the If enabled, CAN bit-timing parameters will be calculated for the
...@@ -54,15 +51,26 @@ config CAN_CALC_BITTIMING ...@@ -54,15 +51,26 @@ config CAN_CALC_BITTIMING
arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
If unsure, say Y. 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 config CAN_AT91
tristate "Atmel AT91 onchip CAN controller" tristate "Atmel AT91 onchip CAN controller"
depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5) depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
---help--- ---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors. and AT91SAM9X5 processors.
config CAN_TI_HECC config CAN_TI_HECC
depends on CAN_DEV && ARCH_OMAP3 depends on ARCH_OMAP3
tristate "TI High End CAN Controller" tristate "TI High End CAN Controller"
---help--- ---help---
Driver for TI HECC (High End CAN Controller) module found on many Driver for TI HECC (High End CAN Controller) module found on many
...@@ -70,12 +78,12 @@ config CAN_TI_HECC ...@@ -70,12 +78,12 @@ config CAN_TI_HECC
config CAN_MCP251X config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers" tristate "Microchip MCP251x SPI CAN controllers"
depends on CAN_DEV && SPI && HAS_DMA depends on SPI && HAS_DMA
---help--- ---help---
Driver for the Microchip MCP251x SPI CAN controllers. Driver for the Microchip MCP251x SPI CAN controllers.
config CAN_BFIN 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" tristate "Analog Devices Blackfin on-chip CAN"
---help--- ---help---
Driver for the Analog Devices Blackfin on-chip CAN controllers Driver for the Analog Devices Blackfin on-chip CAN controllers
...@@ -85,7 +93,7 @@ config CAN_BFIN ...@@ -85,7 +93,7 @@ config CAN_BFIN
config CAN_JANZ_ICAN3 config CAN_JANZ_ICAN3
tristate "Janz VMOD-ICAN3 Intelligent CAN controller" tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
depends on CAN_DEV && MFD_JANZ_CMODIO depends on MFD_JANZ_CMODIO
---help--- ---help---
Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
connects to a MODULbus carrier board. connects to a MODULbus carrier board.
...@@ -98,13 +106,13 @@ config HAVE_CAN_FLEXCAN ...@@ -98,13 +106,13 @@ config HAVE_CAN_FLEXCAN
config CAN_FLEXCAN config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips" tristate "Support for Freescale FLEXCAN based chips"
depends on CAN_DEV && HAVE_CAN_FLEXCAN depends on HAVE_CAN_FLEXCAN
---help--- ---help---
Say Y here if you want to support for Freescale FlexCAN. Say Y here if you want to support for Freescale FlexCAN.
config PCH_CAN config PCH_CAN
tristate "Intel EG20T PCH CAN controller" tristate "Intel EG20T PCH CAN controller"
depends on CAN_DEV && PCI depends on PCI
---help--- ---help---
This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
is an IOH for x86 embedded processor (Intel Atom E6xx series). is an IOH for x86 embedded processor (Intel Atom E6xx series).
...@@ -112,7 +120,7 @@ config PCH_CAN ...@@ -112,7 +120,7 @@ config PCH_CAN
config CAN_GRCAN config CAN_GRCAN
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices" tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
depends on CAN_DEV && OF depends on OF
---help--- ---help---
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN. Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
Note that the driver supports little endian, even though little Note that the driver supports little endian, even though little
...@@ -131,9 +139,10 @@ source "drivers/net/can/usb/Kconfig" ...@@ -131,9 +139,10 @@ source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig" source "drivers/net/can/softing/Kconfig"
endif
config CAN_DEBUG_DEVICES config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages" bool "CAN devices debugging messages"
depends on CAN
---help--- ---help---
Say Y here if you want the CAN device drivers to produce a bunch of 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 debug messages to the system log. Select this if you are having
......
...@@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o ...@@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o
obj-$(CONFIG_CAN_DEV) += can-dev.o obj-$(CONFIG_CAN_DEV) += can-dev.o
can-dev-y := dev.o can-dev-y := dev.o
can-dev-$(CONFIG_CAN_LEDS) += led.o
obj-y += usb/ obj-y += usb/
obj-y += softing/ obj-y += softing/
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
#define AT91_MB_MASK(i) ((1 << (i)) - 1) #define AT91_MB_MASK(i) ((1 << (i)) - 1)
...@@ -641,6 +642,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) ...@@ -641,6 +642,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->can_dlc; 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) ...@@ -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! */ /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
can_get_echo_skb(dev, mb - get_mb_tx_first(priv)); can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
dev->stats.tx_packets++; dev->stats.tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
} }
} }
...@@ -1128,6 +1132,8 @@ static int at91_open(struct net_device *dev) ...@@ -1128,6 +1132,8 @@ static int at91_open(struct net_device *dev)
goto out_close; goto out_close;
} }
can_led_event(dev, CAN_LED_EVENT_OPEN);
/* start chip and queuing */ /* start chip and queuing */
at91_chip_start(dev); at91_chip_start(dev);
napi_enable(&priv->napi); napi_enable(&priv->napi);
...@@ -1159,6 +1165,8 @@ static int at91_close(struct net_device *dev) ...@@ -1159,6 +1165,8 @@ static int at91_close(struct net_device *dev)
close_candev(dev); close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -1321,6 +1329,8 @@ static int at91_can_probe(struct platform_device *pdev) ...@@ -1321,6 +1329,8 @@ static int at91_can_probe(struct platform_device *pdev)
goto exit_free; goto exit_free;
} }
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->reg_base, dev->irq); priv->reg_base, dev->irq);
......
menuconfig CAN_C_CAN menuconfig CAN_C_CAN
tristate "Bosch C_CAN/D_CAN devices" tristate "Bosch C_CAN/D_CAN devices"
depends on CAN_DEV && HAS_IOMEM depends on HAS_IOMEM
if CAN_C_CAN if CAN_C_CAN
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#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/led.h>
#include "c_can.h" #include "c_can.h"
...@@ -477,6 +478,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl) ...@@ -477,6 +478,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += frame->can_dlc; stats->rx_bytes += frame->can_dlc;
can_led_event(dev, CAN_LED_EVENT_RX);
return 0; return 0;
} }
...@@ -751,6 +754,7 @@ static void c_can_do_tx(struct net_device *dev) ...@@ -751,6 +754,7 @@ static void c_can_do_tx(struct net_device *dev)
C_CAN_IFACE(MSGCTRL_REG, 0)) C_CAN_IFACE(MSGCTRL_REG, 0))
& IF_MCONT_DLC_MASK; & IF_MCONT_DLC_MASK;
stats->tx_packets++; stats->tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
c_can_inval_msg_object(dev, 0, msg_obj_no); c_can_inval_msg_object(dev, 0, msg_obj_no);
} else { } else {
break; break;
...@@ -1115,6 +1119,8 @@ static int c_can_open(struct net_device *dev) ...@@ -1115,6 +1119,8 @@ static int c_can_open(struct net_device *dev)
napi_enable(&priv->napi); napi_enable(&priv->napi);
can_led_event(dev, CAN_LED_EVENT_OPEN);
/* start the c_can controller */ /* start the c_can controller */
c_can_start(dev); c_can_start(dev);
...@@ -1143,6 +1149,8 @@ static int c_can_close(struct net_device *dev) ...@@ -1143,6 +1149,8 @@ static int c_can_close(struct net_device *dev)
c_can_reset_ram(priv, false); c_can_reset_ram(priv, false);
c_can_pm_runtime_put_sync(priv); c_can_pm_runtime_put_sync(priv);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -1268,6 +1276,8 @@ int register_c_can_dev(struct net_device *dev) ...@@ -1268,6 +1276,8 @@ int register_c_can_dev(struct net_device *dev)
err = register_candev(dev); err = register_candev(dev);
if (err) if (err)
c_can_pm_runtime_disable(priv); c_can_pm_runtime_disable(priv);
else
devm_can_led_init(dev);
return err; return err;
} }
......
menuconfig CAN_CC770 menuconfig CAN_CC770
tristate "Bosch CC770 and Intel AN82527 devices" tristate "Bosch CC770 and Intel AN82527 devices"
depends on CAN_DEV && HAS_IOMEM depends on HAS_IOMEM
if CAN_CC770 if CAN_CC770
......
...@@ -24,7 +24,9 @@ ...@@ -24,7 +24,9 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/skb.h>
#include <linux/can/netlink.h> #include <linux/can/netlink.h>
#include <linux/can/led.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#define MOD_DESC "CAN device driver interface" #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) ...@@ -501,13 +503,18 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
{ {
struct sk_buff *skb; 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)) if (unlikely(!skb))
return NULL; return NULL;
skb->protocol = htons(ETH_P_CAN); skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY; 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)); *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
memset(*cf, 0, sizeof(struct can_frame)); memset(*cf, 0, sizeof(struct can_frame));
...@@ -794,10 +801,25 @@ void unregister_candev(struct net_device *dev) ...@@ -794,10 +801,25 @@ void unregister_candev(struct net_device *dev)
} }
EXPORT_SYMBOL_GPL(unregister_candev); 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) static __init int can_dev_init(void)
{ {
int err; int err;
can_led_notifier_init();
err = rtnl_link_register(&can_link_ops); err = rtnl_link_register(&can_link_ops);
if (!err) if (!err)
printk(KERN_INFO MOD_DESC "\n"); printk(KERN_INFO MOD_DESC "\n");
...@@ -809,6 +831,8 @@ module_init(can_dev_init); ...@@ -809,6 +831,8 @@ module_init(can_dev_init);
static __exit void can_dev_exit(void) static __exit void can_dev_exit(void)
{ {
rtnl_link_unregister(&can_link_ops); rtnl_link_unregister(&can_link_ops);
can_led_notifier_exit();
} }
module_exit(can_dev_exit); module_exit(can_dev_exit);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#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/led.h>
#include <linux/can/platform/flexcan.h> #include <linux/can/platform/flexcan.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -564,6 +565,8 @@ static int flexcan_read_frame(struct net_device *dev) ...@@ -564,6 +565,8 @@ static int flexcan_read_frame(struct net_device *dev)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->can_dlc; stats->rx_bytes += cf->can_dlc;
can_led_event(dev, CAN_LED_EVENT_RX);
return 1; return 1;
} }
...@@ -652,6 +655,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) ...@@ -652,6 +655,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) { if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
stats->tx_bytes += can_get_echo_skb(dev, 0); stats->tx_bytes += can_get_echo_skb(dev, 0);
stats->tx_packets++; stats->tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1); flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
netif_wake_queue(dev); netif_wake_queue(dev);
} }
...@@ -865,6 +869,9 @@ static int flexcan_open(struct net_device *dev) ...@@ -865,6 +869,9 @@ static int flexcan_open(struct net_device *dev)
err = flexcan_chip_start(dev); err = flexcan_chip_start(dev);
if (err) if (err)
goto out_close; goto out_close;
can_led_event(dev, CAN_LED_EVENT_OPEN);
napi_enable(&priv->napi); napi_enable(&priv->napi);
netif_start_queue(dev); netif_start_queue(dev);
...@@ -893,6 +900,8 @@ static int flexcan_close(struct net_device *dev) ...@@ -893,6 +900,8 @@ static int flexcan_close(struct net_device *dev)
close_candev(dev); close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -1092,6 +1101,8 @@ static int flexcan_probe(struct platform_device *pdev) ...@@ -1092,6 +1101,8 @@ static int flexcan_probe(struct platform_device *pdev)
goto failed_register; goto failed_register;
} }
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->base, dev->irq); priv->base, dev->irq);
......
/*
* 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 @@ ...@@ -60,6 +60,7 @@
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/led.h>
#include <linux/can/platform/mcp251x.h> #include <linux/can/platform/mcp251x.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -494,6 +495,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx) ...@@ -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_packets++;
priv->net->stats.rx_bytes += frame->can_dlc; priv->net->stats.rx_bytes += frame->can_dlc;
can_led_event(priv->net, CAN_LED_EVENT_RX);
netif_rx_ni(skb); netif_rx_ni(skb);
} }
...@@ -707,6 +711,8 @@ static int mcp251x_stop(struct net_device *net) ...@@ -707,6 +711,8 @@ static int mcp251x_stop(struct net_device *net)
mutex_unlock(&priv->mcp_lock); mutex_unlock(&priv->mcp_lock);
can_led_event(net, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -905,6 +911,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) ...@@ -905,6 +911,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (intf & CANINTF_TX) { if (intf & CANINTF_TX) {
net->stats.tx_packets++; net->stats.tx_packets++;
net->stats.tx_bytes += priv->tx_len - 1; net->stats.tx_bytes += priv->tx_len - 1;
can_led_event(net, CAN_LED_EVENT_TX);
if (priv->tx_len) { if (priv->tx_len) {
can_get_echo_skb(net, 0); can_get_echo_skb(net, 0);
priv->tx_len = 0; priv->tx_len = 0;
...@@ -968,6 +975,9 @@ static int mcp251x_open(struct net_device *net) ...@@ -968,6 +975,9 @@ static int mcp251x_open(struct net_device *net)
mcp251x_open_clean(net); mcp251x_open_clean(net);
goto open_unlock; goto open_unlock;
} }
can_led_event(net, CAN_LED_EVENT_OPEN);
netif_wake_queue(net); netif_wake_queue(net);
open_unlock: open_unlock:
...@@ -1077,10 +1087,15 @@ static int mcp251x_can_probe(struct spi_device *spi) ...@@ -1077,10 +1087,15 @@ static int mcp251x_can_probe(struct spi_device *spi)
pdata->transceiver_enable(0); pdata->transceiver_enable(0);
ret = register_candev(net); ret = register_candev(net);
if (!ret) { if (ret)
goto error_probe;
devm_can_led_init(net);
dev_info(&spi->dev, "probed\n"); dev_info(&spi->dev, "probed\n");
return ret; return ret;
}
error_probe: error_probe:
if (!mcp251x_enable_dma) if (!mcp251x_enable_dma)
kfree(priv->spi_rx_buf); kfree(priv->spi_rx_buf);
......
config CAN_MSCAN config CAN_MSCAN
depends on CAN_DEV && (PPC || M68K) depends on PPC || M68K
tristate "Support for Freescale MSCAN based chips" tristate "Support for Freescale MSCAN based chips"
---help--- ---help---
The Motorola Scalable Controller Area Network (MSCAN) definition The Motorola Scalable Controller Area Network (MSCAN) definition
......
menuconfig CAN_SJA1000 menuconfig CAN_SJA1000
tristate "Philips/NXP SJA1000 devices" tristate "Philips/NXP SJA1000 devices"
depends on CAN_DEV && HAS_IOMEM depends on HAS_IOMEM
if CAN_SJA1000 if CAN_SJA1000
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
#include "sja1000.h" #include "sja1000.h"
...@@ -368,6 +369,8 @@ static void sja1000_rx(struct net_device *dev) ...@@ -368,6 +369,8 @@ static void sja1000_rx(struct net_device *dev)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->can_dlc; 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) 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) ...@@ -521,6 +524,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
can_get_echo_skb(dev, 0); can_get_echo_skb(dev, 0);
} }
netif_wake_queue(dev); netif_wake_queue(dev);
can_led_event(dev, CAN_LED_EVENT_TX);
} }
if (isrc & IRQ_RI) { if (isrc & IRQ_RI) {
/* receive interrupt */ /* receive interrupt */
...@@ -575,6 +579,8 @@ static int sja1000_open(struct net_device *dev) ...@@ -575,6 +579,8 @@ static int sja1000_open(struct net_device *dev)
/* init and start chi */ /* init and start chi */
sja1000_start(dev); sja1000_start(dev);
can_led_event(dev, CAN_LED_EVENT_OPEN);
netif_start_queue(dev); netif_start_queue(dev);
return 0; return 0;
...@@ -592,6 +598,8 @@ static int sja1000_close(struct net_device *dev) ...@@ -592,6 +598,8 @@ static int sja1000_close(struct net_device *dev)
close_candev(dev); close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -639,6 +647,8 @@ static const struct net_device_ops sja1000_netdev_ops = { ...@@ -639,6 +647,8 @@ static const struct net_device_ops sja1000_netdev_ops = {
int register_sja1000dev(struct net_device *dev) int register_sja1000dev(struct net_device *dev)
{ {
int ret;
if (!sja1000_probe_chip(dev)) if (!sja1000_probe_chip(dev))
return -ENODEV; return -ENODEV;
...@@ -648,7 +658,12 @@ int register_sja1000dev(struct net_device *dev) ...@@ -648,7 +658,12 @@ int register_sja1000dev(struct net_device *dev)
set_reset_mode(dev); set_reset_mode(dev);
chipset_init(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); EXPORT_SYMBOL_GPL(register_sja1000dev);
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/skb.h>
static __initconst const char banner[] = static __initconst const char banner[] =
KERN_INFO "slcan: serial line CAN interface driver\n"; KERN_INFO "slcan: serial line CAN interface driver\n";
...@@ -184,7 +185,8 @@ static void slc_bump(struct slcan *sl) ...@@ -184,7 +185,8 @@ static void slc_bump(struct slcan *sl)
cf.data[i] |= tmp; 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) if (!skb)
return; return;
...@@ -192,6 +194,10 @@ static void slc_bump(struct slcan *sl) ...@@ -192,6 +194,10 @@ static void slc_bump(struct slcan *sl)
skb->protocol = htons(ETH_P_CAN); skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY; 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)), memcpy(skb_put(skb, sizeof(struct can_frame)),
&cf, sizeof(struct can_frame)); &cf, sizeof(struct can_frame));
netif_rx_ni(skb); netif_rx_ni(skb);
......
config CAN_SOFTING config CAN_SOFTING
tristate "Softing Gmbh CAN generic support" tristate "Softing Gmbh CAN generic support"
depends on CAN_DEV && HAS_IOMEM depends on HAS_IOMEM
---help--- ---help---
Support for CAN cards from Softing Gmbh & some cards Support for CAN cards from Softing Gmbh & some cards
from Vector Gmbh. from Vector Gmbh.
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/can/platform/ti_hecc.h> #include <linux/can/platform/ti_hecc.h>
#define DRV_NAME "ti_hecc" #define DRV_NAME "ti_hecc"
...@@ -593,6 +594,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno) ...@@ -593,6 +594,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
spin_unlock_irqrestore(&priv->mbx_lock, flags); spin_unlock_irqrestore(&priv->mbx_lock, flags);
stats->rx_bytes += cf->can_dlc; stats->rx_bytes += cf->can_dlc;
can_led_event(priv->ndev, CAN_LED_EVENT_RX);
netif_receive_skb(skb); netif_receive_skb(skb);
stats->rx_packets++; stats->rx_packets++;
...@@ -796,6 +798,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id) ...@@ -796,6 +798,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
stats->tx_bytes += hecc_read_mbx(priv, mbxno, stats->tx_bytes += hecc_read_mbx(priv, mbxno,
HECC_CANMCF) & 0xF; HECC_CANMCF) & 0xF;
stats->tx_packets++; stats->tx_packets++;
can_led_event(ndev, CAN_LED_EVENT_TX);
can_get_echo_skb(ndev, mbxno); can_get_echo_skb(ndev, mbxno);
--priv->tx_tail; --priv->tx_tail;
} }
...@@ -851,6 +854,8 @@ static int ti_hecc_open(struct net_device *ndev) ...@@ -851,6 +854,8 @@ static int ti_hecc_open(struct net_device *ndev)
return err; return err;
} }
can_led_event(ndev, CAN_LED_EVENT_OPEN);
ti_hecc_start(ndev); ti_hecc_start(ndev);
napi_enable(&priv->napi); napi_enable(&priv->napi);
netif_start_queue(ndev); netif_start_queue(ndev);
...@@ -869,6 +874,8 @@ static int ti_hecc_close(struct net_device *ndev) ...@@ -869,6 +874,8 @@ static int ti_hecc_close(struct net_device *ndev)
close_candev(ndev); close_candev(ndev);
ti_hecc_transceiver_switch(priv, 0); ti_hecc_transceiver_switch(priv, 0);
can_led_event(ndev, CAN_LED_EVENT_STOP);
return 0; return 0;
} }
...@@ -961,6 +968,9 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -961,6 +968,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "register_candev() failed\n"); dev_err(&pdev->dev, "register_candev() failed\n");
goto probe_exit_clk; goto probe_exit_clk;
} }
devm_can_led_init(ndev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n", dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
priv->base, (u32) ndev->irq); priv->base, (u32) ndev->irq);
......
menu "CAN USB interfaces" menu "CAN USB interfaces"
depends on USB && CAN_DEV depends on USB
config CAN_EMS_USB config CAN_EMS_USB
tristate "EMS CPC-USB/ARM7 CAN/USB interface" tristate "EMS CPC-USB/ARM7 CAN/USB interface"
...@@ -48,4 +48,10 @@ config CAN_PEAK_USB ...@@ -48,4 +48,10 @@ config CAN_PEAK_USB
This driver supports the PCAN-USB and PCAN-USB Pro adapters This driver supports the PCAN-USB and PCAN-USB Pro adapters
from PEAK-System Technik (http://www.peak-system.com). 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 endmenu
...@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o ...@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.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
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
This diff is collapsed.
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/netlink.h> #include <linux/can/netlink.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/can/led.h>
/* /*
* CAN mode * CAN mode
...@@ -52,6 +53,13 @@ struct can_priv { ...@@ -52,6 +53,13 @@ struct can_priv {
unsigned int echo_skb_max; unsigned int echo_skb_max;
struct sk_buff **echo_skb; 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); ...@@ -98,6 +106,9 @@ u8 can_len2dlc(u8 len);
struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max); struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
void free_candev(struct net_device *dev); 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); int open_candev(struct net_device *dev);
void close_candev(struct net_device *dev); void close_candev(struct net_device *dev);
......
/*
* 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
/*
* 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 { ...@@ -44,6 +44,7 @@ enum {
CGW_SRC_IF, /* ifindex of source network interface */ CGW_SRC_IF, /* ifindex of source network interface */
CGW_DST_IF, /* ifindex of destination network interface */ CGW_DST_IF, /* ifindex of destination network interface */
CGW_FILTER, /* specify struct can_filter on source CAN device */ CGW_FILTER, /* specify struct can_filter on source CAN device */
CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
__CGW_MAX __CGW_MAX
}; };
...@@ -51,6 +52,7 @@ enum { ...@@ -51,6 +52,7 @@ enum {
#define CGW_FLAGS_CAN_ECHO 0x01 #define CGW_FLAGS_CAN_ECHO 0x01
#define CGW_FLAGS_CAN_SRC_TSTAMP 0x02 #define CGW_FLAGS_CAN_SRC_TSTAMP 0x02
#define CGW_FLAGS_CAN_IIF_TX_OK 0x04
#define CGW_MOD_FUNCS 4 /* AND OR XOR SET */ #define CGW_MOD_FUNCS 4 /* AND OR XOR SET */
......
...@@ -16,10 +16,11 @@ menuconfig CAN ...@@ -16,10 +16,11 @@ menuconfig CAN
If you want CAN support you should say Y here and also to the If you want CAN support you should say Y here and also to the
specific driver for your controller(s) below. specific driver for your controller(s) below.
if CAN
config CAN_RAW config CAN_RAW
tristate "Raw CAN Protocol (raw access with CAN-ID filtering)" tristate "Raw CAN Protocol (raw access with CAN-ID filtering)"
depends on CAN default y
default N
---help--- ---help---
The raw CAN protocol option offers access to the CAN bus via 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 the BSD socket API. You probably want to use the raw socket in
...@@ -29,8 +30,7 @@ config CAN_RAW ...@@ -29,8 +30,7 @@ config CAN_RAW
config CAN_BCM config CAN_BCM
tristate "Broadcast Manager CAN Protocol (with content filtering)" tristate "Broadcast Manager CAN Protocol (with content filtering)"
depends on CAN default y
default N
---help--- ---help---
The Broadcast Manager offers content filtering, timeout monitoring, The Broadcast Manager offers content filtering, timeout monitoring,
sending of RTR frames, and cyclic CAN messages without permanent user sending of RTR frames, and cyclic CAN messages without permanent user
...@@ -42,8 +42,7 @@ config CAN_BCM ...@@ -42,8 +42,7 @@ config CAN_BCM
config CAN_GW config CAN_GW
tristate "CAN Gateway/Router (with netlink configuration)" tristate "CAN Gateway/Router (with netlink configuration)"
depends on CAN default y
default N
---help--- ---help---
The CAN Gateway/Router is used to route (and modify) CAN frames. 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 It is based on the PF_CAN core infrastructure for msg filtering and
...@@ -53,3 +52,5 @@ config CAN_GW ...@@ -53,3 +52,5 @@ config CAN_GW
by the netlink configuration interface known e.g. from iptables. by the netlink configuration interface known e.g. from iptables.
source "drivers/net/can/Kconfig" source "drivers/net/can/Kconfig"
endif
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/bcm.h> #include <linux/can/bcm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -256,10 +257,13 @@ static void bcm_can_tx(struct bcm_op *op) ...@@ -256,10 +257,13 @@ static void bcm_can_tx(struct bcm_op *op)
return; return;
} }
skb = alloc_skb(CFSIZ, gfp_any()); skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), gfp_any());
if (!skb) if (!skb)
goto out; 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); memcpy(skb_put(skb, CFSIZ), cf, CFSIZ);
/* send with loopback */ /* send with loopback */
...@@ -1199,11 +1203,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) ...@@ -1199,11 +1203,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
if (!ifindex) if (!ifindex)
return -ENODEV; return -ENODEV;
skb = alloc_skb(CFSIZ, GFP_KERNEL); skb = alloc_skb(CFSIZ + sizeof(struct can_skb_priv), GFP_KERNEL);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
skb_reserve(skb, sizeof(struct can_skb_priv));
err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, CFSIZ); err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, CFSIZ);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
...@@ -1216,6 +1221,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) ...@@ -1216,6 +1221,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
return -ENODEV; return -ENODEV;
} }
((struct can_skb_priv *)(skb->head))->ifindex = dev->ifindex;
skb->dev = dev; skb->dev = dev;
skb->sk = sk; skb->sk = sk;
err = can_send(skb, 1); /* send with loopback */ err = can_send(skb, 1); /* send with loopback */
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
...@@ -52,19 +53,31 @@ ...@@ -52,19 +53,31 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/gw.h> #include <linux/can/gw.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/sock.h> #include <net/sock.h>
#define CAN_GW_VERSION "20101209" #define CAN_GW_VERSION "20130117"
static __initconst const char banner[] = #define CAN_GW_NAME "can-gw"
KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
MODULE_DESCRIPTION("PF_CAN netlink gateway"); MODULE_DESCRIPTION("PF_CAN netlink gateway");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>"); 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 HLIST_HEAD(cgw_list);
static struct notifier_block notifier; static struct notifier_block notifier;
...@@ -118,6 +131,7 @@ struct cgw_job { ...@@ -118,6 +131,7 @@ struct cgw_job {
struct rcu_head rcu; struct rcu_head rcu;
u32 handled_frames; u32 handled_frames;
u32 dropped_frames; u32 dropped_frames;
u32 deleted_frames;
struct cf_mod mod; struct cf_mod mod;
union { union {
/* CAN frame data source */ /* CAN frame data source */
...@@ -338,15 +352,40 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) ...@@ -338,15 +352,40 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
struct sk_buff *nskb; struct sk_buff *nskb;
int modidx = 0; 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; return;
}
if (!(gwj->dst.dev->flags & IFF_UP)) { if (!(gwj->dst.dev->flags & IFF_UP)) {
gwj->dropped_frames++; gwj->dropped_frames++;
return; 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() * 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) ...@@ -363,15 +402,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
return; return;
} }
/* /* put the incremented hop counter in the cloned skb */
* Mark routed frames by setting some mac header length which is cgw_hops(nskb) = cgw_hops(skb) + 1;
* 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);
nskb->dev = gwj->dst.dev; nskb->dev = gwj->dst.dev;
/* pointer to modifiable CAN frame */ /* pointer to modifiable CAN frame */
...@@ -472,6 +504,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type, ...@@ -472,6 +504,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
goto cancel; 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 */ /* check non default settings of attributes */
if (gwj->mod.modtype.and) { if (gwj->mod.modtype.and) {
...@@ -771,6 +808,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -771,6 +808,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
gwj->handled_frames = 0; gwj->handled_frames = 0;
gwj->dropped_frames = 0; gwj->dropped_frames = 0;
gwj->deleted_frames = 0;
gwj->flags = r->flags; gwj->flags = r->flags;
gwj->gwtype = r->gwtype; gwj->gwtype = r->gwtype;
...@@ -895,7 +933,11 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ...@@ -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) 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), cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
0, 0, NULL); 0, 0, NULL);
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/raw.h> #include <linux/can/raw.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
...@@ -699,11 +700,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -699,11 +700,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
if (!dev) if (!dev)
return -ENXIO; return -ENXIO;
skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv),
&err); msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb) if (!skb)
goto put_dev; 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); err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err < 0) if (err < 0)
goto free_skb; goto free_skb;
......
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