mirror of
https://github.com/torvalds/linux.git
synced 2024-12-30 06:41:43 +00:00
Merge branch 'master' of git://gitorious.org/linux-can/linux-can-next
Marc Kleine-Budde says: ==================== here is our second pull request for net-next. In this series Federico Vaga adds a pci driver for c_can/d_can hardware using the existing generic c_can driver. The remaining 6 patches are by Oliver Hartkopp. He adds CANFD support to the CAN stack while keeping binary compatibility for existing applications. CANFD is an extension to the existing CAN standard, it allows longer CAN frames and/or higher data rates. There's no real hardware available yet, but this series adds CANFD support to the vcan driver. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
3879d4e397
@ -22,7 +22,8 @@ This file contains
|
||||
4.1.2 RAW socket option CAN_RAW_ERR_FILTER
|
||||
4.1.3 RAW socket option CAN_RAW_LOOPBACK
|
||||
4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS
|
||||
4.1.5 RAW socket returned message flags
|
||||
4.1.5 RAW socket option CAN_RAW_FD_FRAMES
|
||||
4.1.6 RAW socket returned message flags
|
||||
4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
|
||||
4.3 connected transport protocols (SOCK_SEQPACKET)
|
||||
4.4 unconnected transport protocols (SOCK_DGRAM)
|
||||
@ -41,7 +42,8 @@ This file contains
|
||||
6.5.1 Netlink interface to set/get devices properties
|
||||
6.5.2 Setting the CAN bit-timing
|
||||
6.5.3 Starting and stopping the CAN network device
|
||||
6.6 supported CAN hardware
|
||||
6.6 CAN FD (flexible data rate) driver support
|
||||
6.7 supported CAN hardware
|
||||
|
||||
7 Socket CAN resources
|
||||
|
||||
@ -273,7 +275,7 @@ solution for a couple of reasons:
|
||||
|
||||
struct can_frame {
|
||||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
__u8 can_dlc; /* data length code: 0 .. 8 */
|
||||
__u8 can_dlc; /* frame payload length in byte (0 .. 8) */
|
||||
__u8 data[8] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
@ -375,6 +377,51 @@ solution for a couple of reasons:
|
||||
nbytes = sendto(s, &frame, sizeof(struct can_frame),
|
||||
0, (struct sockaddr*)&addr, sizeof(addr));
|
||||
|
||||
Remark about CAN FD (flexible data rate) support:
|
||||
|
||||
Generally the handling of CAN FD is very similar to the formerly described
|
||||
examples. The new CAN FD capable CAN controllers support two different
|
||||
bitrates for the arbitration phase and the payload phase of the CAN FD frame
|
||||
and up to 64 bytes of payload. This extended payload length breaks all the
|
||||
kernel interfaces (ABI) which heavily rely on the CAN frame with fixed eight
|
||||
bytes of payload (struct can_frame) like the CAN_RAW socket. Therefore e.g.
|
||||
the CAN_RAW socket supports a new socket option CAN_RAW_FD_FRAMES that
|
||||
switches the socket into a mode that allows the handling of CAN FD frames
|
||||
and (legacy) CAN frames simultaneously (see section 4.1.5).
|
||||
|
||||
The struct canfd_frame is defined in include/linux/can.h:
|
||||
|
||||
struct canfd_frame {
|
||||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
__u8 len; /* frame payload length in byte (0 .. 64) */
|
||||
__u8 flags; /* additional flags for CAN FD */
|
||||
__u8 __res0; /* reserved / padding */
|
||||
__u8 __res1; /* reserved / padding */
|
||||
__u8 data[64] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
The struct canfd_frame and the existing struct can_frame have the can_id,
|
||||
the payload length and the payload data at the same offset inside their
|
||||
structures. This allows to handle the different structures very similar.
|
||||
When the content of a struct can_frame is copied into a struct canfd_frame
|
||||
all structure elements can be used as-is - only the data[] becomes extended.
|
||||
|
||||
When introducing the struct canfd_frame it turned out that the data length
|
||||
code (DLC) of the struct can_frame was used as a length information as the
|
||||
length and the DLC has a 1:1 mapping in the range of 0 .. 8. To preserve
|
||||
the easy handling of the length information the canfd_frame.len element
|
||||
contains a plain length value from 0 .. 64. So both canfd_frame.len and
|
||||
can_frame.can_dlc are equal and contain a length information and no DLC.
|
||||
For details about the distinction of CAN and CAN FD capable devices and
|
||||
the mapping to the bus-relevant data length code (DLC), see chapter 6.6.
|
||||
|
||||
The length of the two CAN(FD) frame structures define the maximum transfer
|
||||
unit (MTU) of the CAN(FD) network interface and skbuff data length. Two
|
||||
definitions are specified for CAN specific MTUs in include/linux/can.h :
|
||||
|
||||
#define CAN_MTU (sizeof(struct can_frame)) == 16 => 'legacy' CAN frame
|
||||
#define CANFD_MTU (sizeof(struct canfd_frame)) == 72 => CAN FD frame
|
||||
|
||||
4.1 RAW protocol sockets with can_filters (SOCK_RAW)
|
||||
|
||||
Using CAN_RAW sockets is extensively comparable to the commonly
|
||||
@ -472,7 +519,69 @@ solution for a couple of reasons:
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
|
||||
&recv_own_msgs, sizeof(recv_own_msgs));
|
||||
|
||||
4.1.5 RAW socket returned message flags
|
||||
4.1.5 RAW socket option CAN_RAW_FD_FRAMES
|
||||
|
||||
CAN FD support in CAN_RAW sockets can be enabled with a new socket option
|
||||
CAN_RAW_FD_FRAMES which is off by default. When the new socket option is
|
||||
not supported by the CAN_RAW socket (e.g. on older kernels), switching the
|
||||
CAN_RAW_FD_FRAMES option returns the error -ENOPROTOOPT.
|
||||
|
||||
Once CAN_RAW_FD_FRAMES is enabled the application can send both CAN frames
|
||||
and CAN FD frames. OTOH the application has to handle CAN and CAN FD frames
|
||||
when reading from the socket.
|
||||
|
||||
CAN_RAW_FD_FRAMES enabled: CAN_MTU and CANFD_MTU are allowed
|
||||
CAN_RAW_FD_FRAMES disabled: only CAN_MTU is allowed (default)
|
||||
|
||||
Example:
|
||||
[ remember: CANFD_MTU == sizeof(struct canfd_frame) ]
|
||||
|
||||
struct canfd_frame cfd;
|
||||
|
||||
nbytes = read(s, &cfd, CANFD_MTU);
|
||||
|
||||
if (nbytes == CANFD_MTU) {
|
||||
printf("got CAN FD frame with length %d\n", cfd.len);
|
||||
/* cfd.flags contains valid data */
|
||||
} else if (nbytes == CAN_MTU) {
|
||||
printf("got legacy CAN frame with length %d\n", cfd.len);
|
||||
/* cfd.flags is undefined */
|
||||
} else {
|
||||
fprintf(stderr, "read: invalid CAN(FD) frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* the content can be handled independently from the received MTU size */
|
||||
|
||||
printf("can_id: %X data length: %d data: ", cfd.can_id, cfd.len);
|
||||
for (i = 0; i < cfd.len; i++)
|
||||
printf("%02X ", cfd.data[i]);
|
||||
|
||||
When reading with size CANFD_MTU only returns CAN_MTU bytes that have
|
||||
been received from the socket a legacy CAN frame has been read into the
|
||||
provided CAN FD structure. Note that the canfd_frame.flags data field is
|
||||
not specified in the struct can_frame and therefore it is only valid in
|
||||
CANFD_MTU sized CAN FD frames.
|
||||
|
||||
As long as the payload length is <=8 the received CAN frames from CAN FD
|
||||
capable CAN devices can be received and read by legacy sockets too. When
|
||||
user-generated CAN FD frames have a payload length <=8 these can be send
|
||||
by legacy CAN network interfaces too. Sending CAN FD frames with payload
|
||||
length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
|
||||
|
||||
Implementation hint for new CAN applications:
|
||||
|
||||
To build a CAN FD aware application use struct canfd_frame as basic CAN
|
||||
data structure for CAN_RAW based applications. When the application is
|
||||
executed on an older Linux kernel and switching the CAN_RAW_FD_FRAMES
|
||||
socket option returns an error: No problem. You'll get legacy CAN frames
|
||||
or CAN FD frames and can process them the same way.
|
||||
|
||||
When sending to CAN devices make sure that the device is capable to handle
|
||||
CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU.
|
||||
The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall.
|
||||
|
||||
4.1.6 RAW socket returned message flags
|
||||
|
||||
When using recvmsg() call, the msg->msg_flags may contain following flags:
|
||||
|
||||
@ -573,10 +682,13 @@ solution for a couple of reasons:
|
||||
dev->type = ARPHRD_CAN; /* the netdevice hardware type */
|
||||
dev->flags = IFF_NOARP; /* CAN has no arp */
|
||||
|
||||
dev->mtu = sizeof(struct can_frame);
|
||||
dev->mtu = CAN_MTU; /* sizeof(struct can_frame) -> legacy CAN interface */
|
||||
|
||||
The struct can_frame is the payload of each socket buffer in the
|
||||
protocol family PF_CAN.
|
||||
or alternative, when the controller supports CAN with flexible data rate:
|
||||
dev->mtu = CANFD_MTU; /* sizeof(struct canfd_frame) -> CAN FD interface */
|
||||
|
||||
The struct can_frame or struct canfd_frame is the payload of each socket
|
||||
buffer (skbuff) in the protocol family PF_CAN.
|
||||
|
||||
6.2 local loopback of sent frames
|
||||
|
||||
@ -792,7 +904,33 @@ solution for a couple of reasons:
|
||||
Note that a restart will also create a CAN error message frame (see
|
||||
also chapter 3.4).
|
||||
|
||||
6.6 Supported CAN hardware
|
||||
6.6 CAN FD (flexible data rate) driver support
|
||||
|
||||
CAN FD capable CAN controllers support two different bitrates for the
|
||||
arbitration phase and the payload phase of the CAN FD frame. Therefore a
|
||||
second bittiming has to be specified in order to enable the CAN FD bitrate.
|
||||
|
||||
Additionally CAN FD capable CAN controllers support up to 64 bytes of
|
||||
payload. The representation of this length in can_frame.can_dlc and
|
||||
canfd_frame.len for userspace applications and inside the Linux network
|
||||
layer is a plain value from 0 .. 64 instead of the CAN 'data length code'.
|
||||
The data length code was a 1:1 mapping to the payload length in the legacy
|
||||
CAN frames anyway. The payload length to the bus-relevant DLC mapping is
|
||||
only performed inside the CAN drivers, preferably with the helper
|
||||
functions can_dlc2len() and can_len2dlc().
|
||||
|
||||
The CAN netdevice driver capabilities can be distinguished by the network
|
||||
devices maximum transfer unit (MTU):
|
||||
|
||||
MTU = 16 (CAN_MTU) => sizeof(struct can_frame) => 'legacy' CAN device
|
||||
MTU = 72 (CANFD_MTU) => sizeof(struct canfd_frame) => CAN FD capable device
|
||||
|
||||
The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall.
|
||||
N.B. CAN FD capable devices can also handle and send legacy CAN frames.
|
||||
|
||||
FIXME: Add details about the CAN FD controller configuration when available.
|
||||
|
||||
6.7 Supported CAN hardware
|
||||
|
||||
Please check the "Kconfig" file in "drivers/net/can" to get an actual
|
||||
list of the support CAN hardware. On the Socket CAN project website
|
||||
|
@ -13,4 +13,11 @@ config CAN_C_CAN_PLATFORM
|
||||
boards from ST Microelectronics (http://www.st.com) like the
|
||||
SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
|
||||
boards like am335x, dm814x, dm813x and dm811x.
|
||||
|
||||
config CAN_C_CAN_PCI
|
||||
tristate "Generic PCI Bus based C_CAN/D_CAN driver"
|
||||
depends on PCI
|
||||
---help---
|
||||
This driver adds support for the C_CAN/D_CAN chips connected
|
||||
to the PCI bus.
|
||||
endif
|
||||
|
@ -4,5 +4,6 @@
|
||||
|
||||
obj-$(CONFIG_CAN_C_CAN) += c_can.o
|
||||
obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
|
||||
obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
|
||||
|
||||
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
|
||||
|
236
drivers/net/can/c_can/c_can_pci.c
Normal file
236
drivers/net/can/c_can/c_can_pci.c
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* PCI bus driver for Bosch C_CAN/D_CAN controller
|
||||
*
|
||||
* Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
|
||||
*
|
||||
* Borrowed from c_can_platform.c
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
#include "c_can.h"
|
||||
|
||||
enum c_can_pci_reg_align {
|
||||
C_CAN_REG_ALIGN_16,
|
||||
C_CAN_REG_ALIGN_32,
|
||||
};
|
||||
|
||||
struct c_can_pci_data {
|
||||
/* Specify if is C_CAN or D_CAN */
|
||||
enum c_can_dev_id type;
|
||||
/* Set the register alignment in the memory */
|
||||
enum c_can_pci_reg_align reg_align;
|
||||
/* Set the frequency if clk is not usable */
|
||||
unsigned int freq;
|
||||
};
|
||||
|
||||
/*
|
||||
* 16-bit c_can registers can be arranged differently in the memory
|
||||
* architecture of different implementations. For example: 16-bit
|
||||
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
|
||||
* Handle the same by providing a common read/write interface.
|
||||
*/
|
||||
static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
|
||||
enum reg index)
|
||||
{
|
||||
return readw(priv->base + priv->regs[index]);
|
||||
}
|
||||
|
||||
static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
|
||||
enum reg index, u16 val)
|
||||
{
|
||||
writew(val, priv->base + priv->regs[index]);
|
||||
}
|
||||
|
||||
static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
|
||||
enum reg index)
|
||||
{
|
||||
return readw(priv->base + 2 * priv->regs[index]);
|
||||
}
|
||||
|
||||
static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
|
||||
enum reg index, u16 val)
|
||||
{
|
||||
writew(val, priv->base + 2 * priv->regs[index]);
|
||||
}
|
||||
|
||||
static int __devinit c_can_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
|
||||
struct c_can_priv *priv;
|
||||
struct net_device *dev;
|
||||
void __iomem *addr;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "pci_enable_device FAILED\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = pci_request_regions(pdev, KBUILD_MODNAME);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "pci_request_regions FAILED\n");
|
||||
goto out_disable_device;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
pci_enable_msi(pdev);
|
||||
|
||||
addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
|
||||
if (!addr) {
|
||||
dev_err(&pdev->dev,
|
||||
"device has no PCI memory resources, "
|
||||
"failing adapter\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_release_regions;
|
||||
}
|
||||
|
||||
/* allocate the c_can device */
|
||||
dev = alloc_c_can_dev();
|
||||
if (!dev) {
|
||||
ret = -ENOMEM;
|
||||
goto out_iounmap;
|
||||
}
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
pci_set_drvdata(pdev, dev);
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
dev->irq = pdev->irq;
|
||||
priv->base = addr;
|
||||
|
||||
if (!c_can_pci_data->freq) {
|
||||
/* get the appropriate clk */
|
||||
clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "no clock defined\n");
|
||||
ret = -ENODEV;
|
||||
goto out_free_c_can;
|
||||
}
|
||||
priv->can.clock.freq = clk_get_rate(clk);
|
||||
priv->priv = clk;
|
||||
} else {
|
||||
priv->can.clock.freq = c_can_pci_data->freq;
|
||||
priv->priv = NULL;
|
||||
}
|
||||
|
||||
/* Configure CAN type */
|
||||
switch (c_can_pci_data->type) {
|
||||
case C_CAN_DEVTYPE:
|
||||
priv->regs = reg_map_c_can;
|
||||
break;
|
||||
case D_CAN_DEVTYPE:
|
||||
priv->regs = reg_map_d_can;
|
||||
priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out_free_clock;
|
||||
}
|
||||
|
||||
/* Configure access to registers */
|
||||
switch (c_can_pci_data->reg_align) {
|
||||
case C_CAN_REG_ALIGN_32:
|
||||
priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
|
||||
priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
|
||||
break;
|
||||
case C_CAN_REG_ALIGN_16:
|
||||
priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
|
||||
priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out_free_clock;
|
||||
}
|
||||
|
||||
ret = register_c_can_dev(dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
goto out_free_clock;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
|
||||
KBUILD_MODNAME, priv->regs, dev->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_clock:
|
||||
if (priv->priv)
|
||||
clk_put(priv->priv);
|
||||
out_free_c_can:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
free_c_can_dev(dev);
|
||||
out_iounmap:
|
||||
pci_iounmap(pdev, addr);
|
||||
out_release_regions:
|
||||
pci_disable_msi(pdev);
|
||||
pci_clear_master(pdev);
|
||||
pci_release_regions(pdev);
|
||||
out_disable_device:
|
||||
pci_disable_device(pdev);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit c_can_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct c_can_priv *priv = netdev_priv(dev);
|
||||
|
||||
unregister_c_can_dev(dev);
|
||||
|
||||
if (priv->priv)
|
||||
clk_put(priv->priv);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
free_c_can_dev(dev);
|
||||
|
||||
pci_iounmap(pdev, priv->base);
|
||||
pci_disable_msi(pdev);
|
||||
pci_clear_master(pdev);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static struct c_can_pci_data c_can_sta2x11= {
|
||||
.type = C_CAN_DEVTYPE,
|
||||
.reg_align = C_CAN_REG_ALIGN_32,
|
||||
.freq = 52000000, /* 52 Mhz */
|
||||
};
|
||||
|
||||
#define C_CAN_ID(_vend, _dev, _driverdata) { \
|
||||
PCI_DEVICE(_vend, _dev), \
|
||||
.driver_data = (unsigned long)&_driverdata, \
|
||||
}
|
||||
static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
|
||||
C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
|
||||
c_can_sta2x11),
|
||||
{},
|
||||
};
|
||||
static struct pci_driver c_can_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = c_can_pci_tbl,
|
||||
.probe = c_can_pci_probe,
|
||||
.remove = __devexit_p(c_can_pci_remove),
|
||||
};
|
||||
|
||||
module_pci_driver(c_can_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
|
||||
MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);
|
@ -33,6 +33,39 @@ MODULE_DESCRIPTION(MOD_DESC);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
|
||||
|
||||
/* CAN DLC to real data length conversion helpers */
|
||||
|
||||
static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64};
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
u8 can_dlc2len(u8 can_dlc)
|
||||
{
|
||||
return dlc2len[can_dlc & 0x0F];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_dlc2len);
|
||||
|
||||
static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
9, 9, 9, 9, /* 9 - 12 */
|
||||
10, 10, 10, 10, /* 13 - 16 */
|
||||
11, 11, 11, 11, /* 17 - 20 */
|
||||
12, 12, 12, 12, /* 21 - 24 */
|
||||
13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
u8 can_len2dlc(u8 len)
|
||||
{
|
||||
if (unlikely(len > 64))
|
||||
return 0xF;
|
||||
|
||||
return len2dlc[len];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_len2dlc);
|
||||
|
||||
#ifdef CONFIG_CAN_CALC_BITTIMING
|
||||
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
||||
|
||||
@ -454,7 +487,7 @@ EXPORT_SYMBOL_GPL(can_bus_off);
|
||||
static void can_setup(struct net_device *dev)
|
||||
{
|
||||
dev->type = ARPHRD_CAN;
|
||||
dev->mtu = sizeof(struct can_frame);
|
||||
dev->mtu = CAN_MTU;
|
||||
dev->hard_header_len = 0;
|
||||
dev->addr_len = 0;
|
||||
dev->tx_queue_len = 10;
|
||||
|
@ -70,13 +70,12 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
|
||||
|
||||
static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cfd->len;
|
||||
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->dev = dev;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
@ -86,7 +85,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
|
||||
|
||||
static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
int loop;
|
||||
|
||||
@ -94,7 +93,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += cf->can_dlc;
|
||||
stats->tx_bytes += cfd->len;
|
||||
|
||||
/* set flag whether this packet has to be looped back */
|
||||
loop = skb->pkt_type == PACKET_LOOPBACK;
|
||||
@ -108,7 +107,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
* CAN core already did the echo for us
|
||||
*/
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cfd->len;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
@ -133,14 +132,28 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static int vcan_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 vcan_netdev_ops = {
|
||||
.ndo_start_xmit = vcan_tx,
|
||||
.ndo_change_mtu = vcan_change_mtu,
|
||||
};
|
||||
|
||||
static void vcan_setup(struct net_device *dev)
|
||||
{
|
||||
dev->type = ARPHRD_CAN;
|
||||
dev->mtu = sizeof(struct can_frame);
|
||||
dev->mtu = CAN_MTU;
|
||||
dev->hard_header_len = 0;
|
||||
dev->addr_len = 0;
|
||||
dev->tx_queue_len = 0;
|
||||
|
@ -46,18 +46,67 @@ typedef __u32 canid_t;
|
||||
*/
|
||||
typedef __u32 can_err_mask_t;
|
||||
|
||||
/* CAN payload length and DLC definitions according to ISO 11898-1 */
|
||||
#define CAN_MAX_DLC 8
|
||||
#define CAN_MAX_DLEN 8
|
||||
|
||||
/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
|
||||
#define CANFD_MAX_DLC 15
|
||||
#define CANFD_MAX_DLEN 64
|
||||
|
||||
/**
|
||||
* struct can_frame - basic CAN frame structure
|
||||
* @can_id: the CAN ID of the frame and CAN_*_FLAG flags, see above.
|
||||
* @can_dlc: the data length field of the CAN frame
|
||||
* @data: the CAN frame payload.
|
||||
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
|
||||
* @can_dlc: frame payload length in byte (0 .. 8) aka data length code
|
||||
* N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
|
||||
* mapping of the 'data length code' to the real payload length
|
||||
* @data: CAN frame payload (up to 8 byte)
|
||||
*/
|
||||
struct can_frame {
|
||||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
__u8 can_dlc; /* data length code: 0 .. 8 */
|
||||
__u8 data[8] __attribute__((aligned(8)));
|
||||
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
|
||||
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
/*
|
||||
* defined bits for canfd_frame.flags
|
||||
*
|
||||
* As the default for CAN FD should be to support the high data rate in the
|
||||
* payload section of the frame (HDR) and to support up to 64 byte in the
|
||||
* data section (EDL) the bits are only set in the non-default case.
|
||||
* Btw. as long as there's no real implementation for CAN FD network driver
|
||||
* these bits are only preliminary.
|
||||
*
|
||||
* RX: NOHDR/NOEDL - info about received CAN FD frame
|
||||
* ESI - bit from originating CAN controller
|
||||
* TX: NOHDR/NOEDL - control per-frame settings if supported by CAN controller
|
||||
* ESI - bit is set by local CAN controller
|
||||
*/
|
||||
#define CANFD_NOHDR 0x01 /* frame without high data rate */
|
||||
#define CANFD_NOEDL 0x02 /* frame without extended data length */
|
||||
#define CANFD_ESI 0x04 /* error state indicator */
|
||||
|
||||
/**
|
||||
* struct canfd_frame - CAN flexible data rate frame structure
|
||||
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
|
||||
* @len: frame payload length in byte (0 .. CANFD_MAX_DLEN)
|
||||
* @flags: additional flags for CAN FD
|
||||
* @__res0: reserved / padding
|
||||
* @__res1: reserved / padding
|
||||
* @data: CAN FD frame payload (up to CANFD_MAX_DLEN byte)
|
||||
*/
|
||||
struct canfd_frame {
|
||||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
__u8 len; /* frame payload length in byte */
|
||||
__u8 flags; /* additional flags for CAN FD */
|
||||
__u8 __res0; /* reserved / padding */
|
||||
__u8 __res1; /* reserved / padding */
|
||||
__u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
#define CAN_MTU (sizeof(struct can_frame))
|
||||
#define CANFD_MTU (sizeof(struct canfd_frame))
|
||||
|
||||
/* particular protocols of the protocol family PF_CAN */
|
||||
#define CAN_RAW 1 /* RAW sockets */
|
||||
#define CAN_BCM 2 /* Broadcast Manager */
|
||||
|
@ -17,10 +17,10 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#define CAN_VERSION "20090105"
|
||||
#define CAN_VERSION "20120528"
|
||||
|
||||
/* increment this number each time you change some user-space interface */
|
||||
#define CAN_ABI_VERSION "8"
|
||||
#define CAN_ABI_VERSION "9"
|
||||
|
||||
#define CAN_VERSION_STRING "rev " CAN_VERSION " abi " CAN_ABI_VERSION
|
||||
|
||||
|
@ -61,23 +61,40 @@ struct can_priv {
|
||||
* To be used in the CAN netdriver receive path to ensure conformance with
|
||||
* ISO 11898-1 Chapter 8.4.2.3 (DLC field)
|
||||
*/
|
||||
#define get_can_dlc(i) (min_t(__u8, (i), 8))
|
||||
#define get_can_dlc(i) (min_t(__u8, (i), CAN_MAX_DLC))
|
||||
#define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC))
|
||||
|
||||
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
|
||||
static inline int can_dropped_invalid_skb(struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (unlikely(skb->len != sizeof(*cf) || cf->can_dlc > 8)) {
|
||||
kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
return 1;
|
||||
}
|
||||
if (skb->protocol == htons(ETH_P_CAN)) {
|
||||
if (unlikely(skb->len != CAN_MTU ||
|
||||
cfd->len > CAN_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else if (skb->protocol == htons(ETH_P_CANFD)) {
|
||||
if (unlikely(skb->len != CANFD_MTU ||
|
||||
cfd->len > CANFD_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else
|
||||
goto inval_skb;
|
||||
|
||||
return 0;
|
||||
|
||||
inval_skb:
|
||||
kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
u8 can_dlc2len(u8 can_dlc);
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
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);
|
||||
|
||||
|
@ -23,7 +23,8 @@ enum {
|
||||
CAN_RAW_FILTER = 1, /* set 0 .. n can_filter(s) */
|
||||
CAN_RAW_ERR_FILTER, /* set filter for error frames */
|
||||
CAN_RAW_LOOPBACK, /* local loopback (default:on) */
|
||||
CAN_RAW_RECV_OWN_MSGS /* receive my own msgs (default:off) */
|
||||
CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */
|
||||
CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -105,7 +105,8 @@
|
||||
#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
|
||||
#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
|
||||
#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
|
||||
#define ETH_P_CAN 0x000C /* Controller Area Network */
|
||||
#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */
|
||||
#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/
|
||||
#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
|
||||
#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
|
||||
#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
|
||||
|
116
net/can/af_can.c
116
net/can/af_can.c
@ -41,6 +41,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/slab.h>
|
||||
@ -220,30 +221,46 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
|
||||
* -ENOBUFS on full driver queue (see net_xmit_errno())
|
||||
* -ENOMEM when local loopback failed at calling skb_clone()
|
||||
* -EPERM when trying to send on a non-CAN interface
|
||||
* -EMSGSIZE CAN frame size is bigger than CAN interface MTU
|
||||
* -EINVAL when the skb->data does not contain a valid CAN frame
|
||||
*/
|
||||
int can_send(struct sk_buff *skb, int loop)
|
||||
{
|
||||
struct sk_buff *newskb = NULL;
|
||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
int err;
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
if (skb->len == CAN_MTU) {
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
if (unlikely(cfd->len > CAN_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else if (skb->len == CANFD_MTU) {
|
||||
skb->protocol = htons(ETH_P_CANFD);
|
||||
if (unlikely(cfd->len > CANFD_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else
|
||||
goto inval_skb;
|
||||
|
||||
/*
|
||||
* Make sure the CAN frame can pass the selected CAN netdevice.
|
||||
* As structs can_frame and canfd_frame are similar, we can provide
|
||||
* CAN FD frames to legacy CAN drivers as long as the length is <= 8
|
||||
*/
|
||||
if (unlikely(skb->len > skb->dev->mtu && cfd->len > CAN_MAX_DLEN)) {
|
||||
err = -EMSGSIZE;
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
if (skb->dev->type != ARPHRD_CAN) {
|
||||
kfree_skb(skb);
|
||||
return -EPERM;
|
||||
if (unlikely(skb->dev->type != ARPHRD_CAN)) {
|
||||
err = -EPERM;
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
if (!(skb->dev->flags & IFF_UP)) {
|
||||
kfree_skb(skb);
|
||||
return -ENETDOWN;
|
||||
if (unlikely(!(skb->dev->flags & IFF_UP))) {
|
||||
err = -ENETDOWN;
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
@ -300,6 +317,10 @@ int can_send(struct sk_buff *skb, int loop)
|
||||
can_stats.tx_frames_delta++;
|
||||
|
||||
return 0;
|
||||
|
||||
inval_skb:
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(can_send);
|
||||
|
||||
@ -632,24 +653,11 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
|
||||
return matches;
|
||||
}
|
||||
|
||||
static int can_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
static void can_receive(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dev_rcv_lists *d;
|
||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
int matches;
|
||||
|
||||
if (!net_eq(dev_net(dev), &init_net))
|
||||
goto drop;
|
||||
|
||||
if (WARN_ONCE(dev->type != ARPHRD_CAN ||
|
||||
skb->len != sizeof(struct can_frame) ||
|
||||
cf->can_dlc > 8,
|
||||
"PF_CAN: dropped non conform skbuf: "
|
||||
"dev type %d, len %d, can_dlc %d\n",
|
||||
dev->type, skb->len, cf->can_dlc))
|
||||
goto drop;
|
||||
|
||||
/* update statistics */
|
||||
can_stats.rx_frames++;
|
||||
can_stats.rx_frames_delta++;
|
||||
@ -673,7 +681,49 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
can_stats.matches++;
|
||||
can_stats.matches_delta++;
|
||||
}
|
||||
}
|
||||
|
||||
static int can_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (unlikely(!net_eq(dev_net(dev), &init_net)))
|
||||
goto drop;
|
||||
|
||||
if (WARN_ONCE(dev->type != ARPHRD_CAN ||
|
||||
skb->len != CAN_MTU ||
|
||||
cfd->len > CAN_MAX_DLEN,
|
||||
"PF_CAN: dropped non conform CAN skbuf: "
|
||||
"dev type %d, len %d, datalen %d\n",
|
||||
dev->type, skb->len, cfd->len))
|
||||
goto drop;
|
||||
|
||||
can_receive(skb, dev);
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (unlikely(!net_eq(dev_net(dev), &init_net)))
|
||||
goto drop;
|
||||
|
||||
if (WARN_ONCE(dev->type != ARPHRD_CAN ||
|
||||
skb->len != CANFD_MTU ||
|
||||
cfd->len > CANFD_MAX_DLEN,
|
||||
"PF_CAN: dropped non conform CAN FD skbuf: "
|
||||
"dev type %d, len %d, datalen %d\n",
|
||||
dev->type, skb->len, cfd->len))
|
||||
goto drop;
|
||||
|
||||
can_receive(skb, dev);
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
drop:
|
||||
@ -807,10 +857,14 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
|
||||
|
||||
static struct packet_type can_packet __read_mostly = {
|
||||
.type = cpu_to_be16(ETH_P_CAN),
|
||||
.dev = NULL,
|
||||
.func = can_rcv,
|
||||
};
|
||||
|
||||
static struct packet_type canfd_packet __read_mostly = {
|
||||
.type = cpu_to_be16(ETH_P_CANFD),
|
||||
.func = canfd_rcv,
|
||||
};
|
||||
|
||||
static const struct net_proto_family can_family_ops = {
|
||||
.family = PF_CAN,
|
||||
.create = can_create,
|
||||
@ -824,6 +878,12 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
|
||||
|
||||
static __init int can_init(void)
|
||||
{
|
||||
/* check for correct padding to be able to use the structs similarly */
|
||||
BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
|
||||
offsetof(struct canfd_frame, len) ||
|
||||
offsetof(struct can_frame, data) !=
|
||||
offsetof(struct canfd_frame, data));
|
||||
|
||||
printk(banner);
|
||||
|
||||
memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
|
||||
@ -846,6 +906,7 @@ static __init int can_init(void)
|
||||
sock_register(&can_family_ops);
|
||||
register_netdevice_notifier(&can_netdev_notifier);
|
||||
dev_add_pack(&can_packet);
|
||||
dev_add_pack(&canfd_packet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -860,6 +921,7 @@ static __exit void can_exit(void)
|
||||
can_remove_proc();
|
||||
|
||||
/* protocol unregister */
|
||||
dev_remove_pack(&canfd_packet);
|
||||
dev_remove_pack(&can_packet);
|
||||
unregister_netdevice_notifier(&can_netdev_notifier);
|
||||
sock_unregister(PF_CAN);
|
||||
|
@ -82,6 +82,7 @@ struct raw_sock {
|
||||
struct notifier_block notifier;
|
||||
int loopback;
|
||||
int recv_own_msgs;
|
||||
int fd_frames;
|
||||
int count; /* number of active filters */
|
||||
struct can_filter dfilter; /* default/single filter */
|
||||
struct can_filter *filter; /* pointer to filter(s) */
|
||||
@ -119,6 +120,14 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
|
||||
if (!ro->recv_own_msgs && oskb->sk == sk)
|
||||
return;
|
||||
|
||||
/* do not pass frames with DLC > 8 to a legacy socket */
|
||||
if (!ro->fd_frames) {
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)oskb->data;
|
||||
|
||||
if (unlikely(cfd->len > CAN_MAX_DLEN))
|
||||
return;
|
||||
}
|
||||
|
||||
/* clone the given skb to be able to enqueue it into the rcv queue */
|
||||
skb = skb_clone(oskb, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
@ -291,6 +300,7 @@ static int raw_init(struct sock *sk)
|
||||
/* set default loopback behaviour */
|
||||
ro->loopback = 1;
|
||||
ro->recv_own_msgs = 0;
|
||||
ro->fd_frames = 0;
|
||||
|
||||
/* set notifier */
|
||||
ro->notifier.notifier_call = raw_notifier;
|
||||
@ -569,6 +579,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
break;
|
||||
|
||||
case CAN_RAW_FD_FRAMES:
|
||||
if (optlen != sizeof(ro->fd_frames))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&ro->fd_frames, optval, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
@ -627,6 +646,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
|
||||
val = &ro->recv_own_msgs;
|
||||
break;
|
||||
|
||||
case CAN_RAW_FD_FRAMES:
|
||||
if (len > sizeof(int))
|
||||
len = sizeof(int);
|
||||
val = &ro->fd_frames;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
@ -662,8 +687,13 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||
} else
|
||||
ifindex = ro->ifindex;
|
||||
|
||||
if (size != sizeof(struct can_frame))
|
||||
return -EINVAL;
|
||||
if (ro->fd_frames) {
|
||||
if (unlikely(size != CANFD_MTU && size != CAN_MTU))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (unlikely(size != CAN_MTU))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = dev_get_by_index(&init_net, ifindex);
|
||||
if (!dev)
|
||||
@ -705,7 +735,9 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||
struct msghdr *msg, size_t size, int flags)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct raw_sock *ro = raw_sk(sk);
|
||||
struct sk_buff *skb;
|
||||
int rxmtu;
|
||||
int err = 0;
|
||||
int noblock;
|
||||
|
||||
@ -716,10 +748,20 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||
if (!skb)
|
||||
return err;
|
||||
|
||||
if (size < skb->len)
|
||||
/*
|
||||
* when serving a legacy socket the DLC <= 8 is already checked inside
|
||||
* raw_rcv(). Now check if we need to pass a canfd_frame to a legacy
|
||||
* socket and cut the possible CANFD_MTU/CAN_MTU length to CAN_MTU
|
||||
*/
|
||||
if (!ro->fd_frames)
|
||||
rxmtu = CAN_MTU;
|
||||
else
|
||||
rxmtu = skb->len;
|
||||
|
||||
if (size < rxmtu)
|
||||
msg->msg_flags |= MSG_TRUNC;
|
||||
else
|
||||
size = skb->len;
|
||||
size = rxmtu;
|
||||
|
||||
err = memcpy_toiovec(msg->msg_iov, skb->data, size);
|
||||
if (err < 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user