linux-can-next-for-5.4-20190814

-----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEmvEkXzgOfc881GuFWsYho5HknSAFAl1TpDwTHG1rbEBwZW5n
 dXRyb25peC5kZQAKCRBaxiGjkeSdIMwYB/49sQtE+obVwAOGcXogemkN5+Gj/KTo
 KzF0CLYRjVOz2FViGVJL9HQ5QZwy1IxTycIUV2kKnrlI6s0Z17z3G0lV2+J4scuy
 O+wVn36QzQHdP3Uj8kGmNQ1v6BliePM8bvm4sHtXzb1diW+qNg/0LmNN4brjPWka
 kfvFjS2IdXa7BblT2aiAZj2V+iSQEpy5NieVwcBti0E2AFb+W3qEa8Lg4QORy3Qi
 MAHg0QSUHZp0+joXRQiott4WttfuQ17OQFuxzsQ7bQCQhBQWYUmg14Hm/LP4V3g2
 9algzS6g3Qapdo7KEJrCSViblzHVD+yL3BemfahNUyK4F8zGkPq48Kp5
 =MqG7
 -----END PGP SIGNATURE-----

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

Marc Kleine-Budde says:

====================
pull-request: can-next 2019-08-14

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

The first two patches are for the kvaser_pciefd driver: Christer Beskow
removes unnecessary code in the kvaser_pciefd_pwm_stop() function,
YueHaibing removes the unused including of <linux/version.h>.

In the next patch YueHaibing also removes the unused including of
<linux/version.h> in the f81601 driver.

In the ti_hecc driver the next 6 patches are by me and fix checkpatch
warnings. YueHaibing's patch removes an unused variable in the
ti_hecc_mailbox_read() function.

The next 6 patches all target the xilinx_can driver. Anssi Hannula's
patch fixes a chip start failure with an invalid bus. The patch by
Venkatesh Yadav Abbarapu skips an error message in case of a deferred
probe. The 3 patches by Appana Durga Kedareswara rao fix the RX and TX
path for CAN-FD frames. Srinivas Neeli's patch fixes the bit timing
calculations for CAN-FD.

The next 12 patches are by me and several checkpatch warnings in the
af_can, raw and bcm components.

Thomas Gleixner provides a patch for the bcm, which switches the timer
to HRTIMER_MODE_SOFT and removes the hrtimer_tasklet.

Then 6 more patches by me for the gw component, which fix checkpatch
warnings, followed by 2 patches by Oliver Hartkopp to add CAN-FD
support.

The vcan driver gets 3 patches by me, fixing checkpatch warnings.

And finally a patch by Andre Hartmann to fix typos in CAN's netlink
header.
====================
This commit is contained in:
David S. Miller 2019-08-15 12:43:22 -07:00
commit 8714652fcd
12 changed files with 582 additions and 536 deletions

View file

@ -7,7 +7,6 @@
*/
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/pci.h>
@ -643,7 +642,7 @@ static int kvaser_pciefd_bus_on(struct kvaser_pciefd_can *can)
static void kvaser_pciefd_pwm_stop(struct kvaser_pciefd_can *can)
{
int top, trigger;
u8 top;
u32 pwm_ctrl;
unsigned long irq;
@ -651,12 +650,8 @@ static void kvaser_pciefd_pwm_stop(struct kvaser_pciefd_can *can)
pwm_ctrl = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_PWM_REG);
top = (pwm_ctrl >> KVASER_PCIEFD_KCAN_PWM_TOP_SHIFT) & 0xff;
trigger = (100 * top + 50) / 100;
if (trigger < 0)
trigger = 0;
pwm_ctrl = trigger & 0xff;
pwm_ctrl |= (top & 0xff) << KVASER_PCIEFD_KCAN_PWM_TOP_SHIFT;
/* Set duty cycle to zero */
pwm_ctrl |= top;
iowrite32(pwm_ctrl, can->reg_base + KVASER_PCIEFD_KCAN_PWM_REG);
spin_unlock_irqrestore(&can->lock, irq);
}

View file

@ -14,7 +14,6 @@
#include <linux/pci.h>
#include <linux/can/dev.h>
#include <linux/io.h>
#include <linux/version.h>
#include "sja1000.h"

View file

@ -46,8 +46,7 @@ MODULE_VERSION(HECC_MODULE_VERSION);
#define HECC_MAX_MAILBOXES 32 /* hardware mailboxes - do not change */
#define MAX_TX_PRIO 0x3F /* hardware value - do not change */
/*
* Important Note: TX mailbox configuration
/* Important Note: TX mailbox configuration
* TX mailboxes should be restricted to the number of SKB buffers to avoid
* maintaining SKB buffers separately. TX mailboxes should be a power of 2
* for the mailbox logic to work. Top mailbox numbers are reserved for RX
@ -223,7 +222,7 @@ static inline u32 hecc_read_stamp(struct ti_hecc_priv *priv, u32 mbxno)
}
static inline void hecc_write_mbx(struct ti_hecc_priv *priv, u32 mbxno,
u32 reg, u32 val)
u32 reg, u32 val)
{
__raw_writel(val, priv->mbx + mbxno * 0x10 + reg);
}
@ -244,13 +243,13 @@ static inline u32 hecc_read(struct ti_hecc_priv *priv, int reg)
}
static inline void hecc_set_bit(struct ti_hecc_priv *priv, int reg,
u32 bit_mask)
u32 bit_mask)
{
hecc_write(priv, reg, hecc_read(priv, reg) | bit_mask);
}
static inline void hecc_clear_bit(struct ti_hecc_priv *priv, int reg,
u32 bit_mask)
u32 bit_mask)
{
hecc_write(priv, reg, hecc_read(priv, reg) & ~bit_mask);
}
@ -272,8 +271,8 @@ static int ti_hecc_set_btc(struct ti_hecc_priv *priv)
if (bit_timing->brp > 4)
can_btc |= HECC_CANBTC_SAM;
else
netdev_warn(priv->ndev, "WARN: Triple"
"sampling not set due to h/w limitations");
netdev_warn(priv->ndev,
"WARN: Triple sampling not set due to h/w limitations");
}
can_btc |= ((bit_timing->sjw - 1) & 0x3) << 8;
can_btc |= ((bit_timing->brp - 1) & 0xFF) << 16;
@ -309,8 +308,7 @@ static void ti_hecc_reset(struct net_device *ndev)
/* Set change control request and wait till enabled */
hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_CCR);
/*
* INFO: It has been observed that at times CCE bit may not be
/* INFO: It has been observed that at times CCE bit may not be
* set and hw seems to be ok even if this bit is not set so
* timing out with a timing of 1ms to respect the specs
*/
@ -320,8 +318,7 @@ static void ti_hecc_reset(struct net_device *ndev)
udelay(10);
}
/*
* Note: On HECC, BTC can be programmed only in initialization mode, so
/* Note: On HECC, BTC can be programmed only in initialization mode, so
* it is expected that the can bittiming parameters are set via ip
* utility before the device is opened
*/
@ -330,13 +327,11 @@ static void ti_hecc_reset(struct net_device *ndev)
/* Clear CCR (and CANMC register) and wait for CCE = 0 enable */
hecc_write(priv, HECC_CANMC, 0);
/*
* INFO: CAN net stack handles bus off and hence disabling auto-bus-on
/* INFO: CAN net stack handles bus off and hence disabling auto-bus-on
* hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_ABO);
*/
/*
* INFO: It has been observed that at times CCE bit may not be
/* INFO: It has been observed that at times CCE bit may not be
* set and hw seems to be ok even if this bit is not set so
*/
cnt = HECC_CCE_WAIT_COUNT;
@ -369,7 +364,8 @@ static void ti_hecc_start(struct net_device *ndev)
/* put HECC in initialization mode and set btc */
ti_hecc_reset(ndev);
priv->tx_head = priv->tx_tail = HECC_TX_MASK;
priv->tx_head = HECC_TX_MASK;
priv->tx_tail = HECC_TX_MASK;
/* Enable local and global acceptance mask registers */
hecc_write(priv, HECC_CANGAM, HECC_SET_REG);
@ -395,7 +391,7 @@ static void ti_hecc_start(struct net_device *ndev)
} else {
hecc_write(priv, HECC_CANMIL, 0);
hecc_write(priv, HECC_CANGIM,
HECC_CANGIM_DEF_MASK | HECC_CANGIM_I0EN);
HECC_CANGIM_DEF_MASK | HECC_CANGIM_I0EN);
}
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
@ -429,7 +425,7 @@ static int ti_hecc_do_set_mode(struct net_device *ndev, enum can_mode mode)
}
static int ti_hecc_get_berr_counter(const struct net_device *ndev,
struct can_berr_counter *bec)
struct can_berr_counter *bec)
{
struct ti_hecc_priv *priv = netdev_priv(ndev);
@ -439,8 +435,7 @@ static int ti_hecc_get_berr_counter(const struct net_device *ndev,
return 0;
}
/*
* ti_hecc_xmit: HECC Transmit
/* ti_hecc_xmit: HECC Transmit
*
* The transmit mailboxes start from 0 to HECC_MAX_TX_MBOX. In HECC the
* priority of the mailbox for tranmission is dependent upon priority setting
@ -478,8 +473,8 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&priv->mbx_lock, flags);
netif_stop_queue(ndev);
netdev_err(priv->ndev,
"BUG: TX mbx not ready tx_head=%08X, tx_tail=%08X\n",
priv->tx_head, priv->tx_tail);
"BUG: TX mbx not ready tx_head=%08X, tx_tail=%08X\n",
priv->tx_head, priv->tx_tail);
return NETDEV_TX_BUSY;
}
spin_unlock_irqrestore(&priv->mbx_lock, flags);
@ -496,10 +491,10 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
data = (cf->can_id & CAN_SFF_MASK) << 18;
hecc_write_mbx(priv, mbxno, HECC_CANMID, data);
hecc_write_mbx(priv, mbxno, HECC_CANMDL,
be32_to_cpu(*(__be32 *)(cf->data)));
be32_to_cpu(*(__be32 *)(cf->data)));
if (cf->can_dlc > 4)
hecc_write_mbx(priv, mbxno, HECC_CANMDH,
be32_to_cpu(*(__be32 *)(cf->data + 4)));
be32_to_cpu(*(__be32 *)(cf->data + 4)));
else
*(u32 *)(cf->data + 4) = 0;
can_put_echo_skb(skb, ndev, mbxno);
@ -507,7 +502,7 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_lock_irqsave(&priv->mbx_lock, flags);
--priv->tx_head;
if ((hecc_read(priv, HECC_CANME) & BIT(get_tx_head_mb(priv))) ||
(priv->tx_head & HECC_TX_MASK) == HECC_TX_MASK) {
(priv->tx_head & HECC_TX_MASK) == HECC_TX_MASK) {
netif_stop_queue(ndev);
}
hecc_set_bit(priv, HECC_CANME, mbx_mask);
@ -520,7 +515,8 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_OK;
}
static inline struct ti_hecc_priv *rx_offload_to_priv(struct can_rx_offload *offload)
static inline
struct ti_hecc_priv *rx_offload_to_priv(struct can_rx_offload *offload)
{
return container_of(offload, struct ti_hecc_priv, offload);
}
@ -530,18 +526,19 @@ static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload,
u32 *timestamp, unsigned int mbxno)
{
struct ti_hecc_priv *priv = rx_offload_to_priv(offload);
u32 data, mbx_mask;
u32 data;
mbx_mask = BIT(mbxno);
data = hecc_read_mbx(priv, mbxno, HECC_CANMID);
if (data & HECC_CANMID_IDE)
cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
cf->can_id = (data >> 18) & CAN_SFF_MASK;
data = hecc_read_mbx(priv, mbxno, HECC_CANMCF);
if (data & HECC_CANMCF_RTR)
cf->can_id |= CAN_RTR_FLAG;
cf->can_dlc = get_can_dlc(data & 0xF);
data = hecc_read_mbx(priv, mbxno, HECC_CANMDL);
*(__be32 *)(cf->data) = cpu_to_be32(data);
if (cf->can_dlc > 4) {
@ -555,7 +552,7 @@ static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload,
}
static int ti_hecc_error(struct net_device *ndev, int int_status,
int err_status)
int err_status)
{
struct ti_hecc_priv *priv = netdev_priv(ndev);
struct can_frame *cf;
@ -567,7 +564,8 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
if (!skb) {
if (printk_ratelimit())
netdev_err(priv->ndev,
"ti_hecc_error: alloc_can_err_skb() failed\n");
"%s: alloc_can_err_skb() failed\n",
__func__);
return -ENOMEM;
}
@ -601,8 +599,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR);
}
/*
* Need to check busoff condition in error status register too to
/* Need to check busoff condition in error status register too to
* ensure warning interrupts don't hog the system
*/
if ((int_status & HECC_CANGIF_BOIF) || (err_status & HECC_CANES_BO)) {
@ -656,15 +653,16 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
unsigned long flags, rx_pending;
int_status = hecc_read(priv,
(priv->use_hecc1int) ? HECC_CANGIF1 : HECC_CANGIF0);
priv->use_hecc1int ?
HECC_CANGIF1 : HECC_CANGIF0);
if (!int_status)
return IRQ_NONE;
err_status = hecc_read(priv, HECC_CANES);
if (err_status & (HECC_BUS_ERROR | HECC_CANES_BO |
HECC_CANES_EP | HECC_CANES_EW))
ti_hecc_error(ndev, int_status, err_status);
HECC_CANES_EP | HECC_CANES_EW))
ti_hecc_error(ndev, int_status, err_status);
if (int_status & HECC_CANGIF_GMIF) {
while (priv->tx_tail - priv->tx_head > 0) {
@ -678,18 +676,19 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
hecc_clear_bit(priv, HECC_CANME, mbx_mask);
spin_unlock_irqrestore(&priv->mbx_lock, flags);
stamp = hecc_read_stamp(priv, mbxno);
stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload,
mbxno, stamp);
stats->tx_bytes +=
can_rx_offload_get_echo_skb(&priv->offload,
mbxno, stamp);
stats->tx_packets++;
can_led_event(ndev, CAN_LED_EVENT_TX);
--priv->tx_tail;
}
/* restart queue if wrap-up or if queue stalled on last pkt */
if (((priv->tx_head == priv->tx_tail) &&
((priv->tx_head & HECC_TX_MASK) != HECC_TX_MASK)) ||
(((priv->tx_tail & HECC_TX_MASK) == HECC_TX_MASK) &&
((priv->tx_head & HECC_TX_MASK) == HECC_TX_MASK)))
if ((priv->tx_head == priv->tx_tail &&
((priv->tx_head & HECC_TX_MASK) != HECC_TX_MASK)) ||
(((priv->tx_tail & HECC_TX_MASK) == HECC_TX_MASK) &&
((priv->tx_head & HECC_TX_MASK) == HECC_TX_MASK)))
netif_wake_queue(ndev);
/* offload RX mailboxes and let NAPI deliver them */
@ -718,7 +717,7 @@ static int ti_hecc_open(struct net_device *ndev)
int err;
err = request_irq(ndev->irq, ti_hecc_interrupt, IRQF_SHARED,
ndev->name, ndev);
ndev->name, ndev);
if (err) {
netdev_err(ndev, "error requesting interrupt\n");
return err;
@ -894,7 +893,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
devm_can_led_init(ndev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
priv->base, (u32) ndev->irq);
priv->base, (u32)ndev->irq);
return 0;

View file

@ -1,5 +1,4 @@
/*
* vcan.c - Virtual CAN interface
/* vcan.c - Virtual CAN interface
*
* Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved.
@ -39,6 +38,8 @@
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
@ -57,9 +58,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
MODULE_ALIAS_RTNL_LINK(DRV_NAME);
/*
* CAN test feature:
/* CAN test feature:
* Enable the echo on driver level for testing the CAN core echo modes.
* See Documentation/networking/can.rst for details.
*/
@ -68,7 +67,6 @@ static bool echo; /* echo testing. Default: 0 (Off) */
module_param(echo, bool, 0444);
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 canfd_frame *cfd = (struct canfd_frame *)skb->data;
@ -101,10 +99,8 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
if (!echo) {
/* no echo handling available inside this driver */
if (loop) {
/*
* only count the packets here, because the
/* only count the packets here, because the
* CAN core already did the echo for us
*/
stats->rx_packets++;
@ -117,7 +113,6 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
/* perform standard echo handling for CAN network interfaces */
if (loop) {
skb = can_create_echo_skb(skb);
if (!skb)
return NETDEV_TX_OK;
@ -173,10 +168,10 @@ static struct rtnl_link_ops vcan_link_ops __read_mostly = {
static __init int vcan_init_module(void)
{
pr_info("vcan: Virtual CAN interface driver\n");
pr_info("Virtual CAN interface driver\n");
if (echo)
printk(KERN_INFO "vcan: enabled echo on driver level.\n");
pr_info("enabled echo on driver level.\n");
return rtnl_link_register(&vcan_link_ops);
}

View file

@ -66,8 +66,7 @@ enum xcan_reg {
#define XCAN_FRAME_DLC_OFFSET(frame_base) ((frame_base) + 0x04)
#define XCAN_FRAME_DW1_OFFSET(frame_base) ((frame_base) + 0x08)
#define XCAN_FRAME_DW2_OFFSET(frame_base) ((frame_base) + 0x0C)
#define XCANFD_FRAME_DW_OFFSET(frame_base, n) (((frame_base) + 0x08) + \
((n) * XCAN_CANFD_FRAME_SIZE))
#define XCANFD_FRAME_DW_OFFSET(frame_base) ((frame_base) + 0x08)
#define XCAN_CANFD_FRAME_SIZE 0x48
#define XCAN_TXMSG_FRAME_OFFSET(n) (XCAN_TXMSG_BASE_OFFSET + \
@ -124,8 +123,10 @@ enum xcan_reg {
#define XCAN_IDR_RTR_MASK 0x00000001 /* Remote TX request */
#define XCAN_DLCR_DLC_MASK 0xF0000000 /* Data length code */
#define XCAN_FSR_FL_MASK 0x00003F00 /* RX Fill Level */
#define XCAN_2_FSR_FL_MASK 0x00007F00 /* RX Fill Level */
#define XCAN_FSR_IRI_MASK 0x00000080 /* RX Increment Read Index */
#define XCAN_FSR_RI_MASK 0x0000001F /* RX Read Index */
#define XCAN_2_FSR_RI_MASK 0x0000003F /* RX Read Index */
#define XCAN_DLCR_EDL_MASK 0x08000000 /* EDL Mask in DLC */
#define XCAN_DLCR_BRS_MASK 0x04000000 /* BRS Mask in DLC */
@ -424,7 +425,7 @@ static int xcan_set_bittiming(struct net_device *ndev)
btr0 = dbt->brp - 1;
/* Setting Time Segment 1 in BTR Register */
btr1 = dbt->prop_seg + bt->phase_seg1 - 1;
btr1 = dbt->prop_seg + dbt->phase_seg1 - 1;
/* Setting Time Segment 2 in BTR Register */
btr1 |= (dbt->phase_seg2 - 1) << priv->devtype.btr_ts2_shift;
@ -456,9 +457,8 @@ static int xcan_set_bittiming(struct net_device *ndev)
static int xcan_chip_start(struct net_device *ndev)
{
struct xcan_priv *priv = netdev_priv(ndev);
u32 reg_msr, reg_sr_mask;
u32 reg_msr;
int err;
unsigned long timeout;
u32 ier;
/* Check if it is in reset mode */
@ -484,10 +484,8 @@ static int xcan_chip_start(struct net_device *ndev)
/* Check whether it is loopback mode or normal mode */
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
reg_msr = XCAN_MSR_LBACK_MASK;
reg_sr_mask = XCAN_SR_LBACK_MASK;
} else {
reg_msr = 0x0;
reg_sr_mask = XCAN_SR_NORMAL_MASK;
}
/* enable the first extended filter, if any, as cores with extended
@ -499,14 +497,6 @@ static int xcan_chip_start(struct net_device *ndev)
priv->write_reg(priv, XCAN_MSR_OFFSET, reg_msr);
priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK);
timeout = jiffies + XCAN_TIMEOUT;
while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & reg_sr_mask)) {
if (time_after(jiffies, timeout)) {
netdev_warn(ndev,
"timed out for correct mode\n");
return -ETIMEDOUT;
}
}
netdev_dbg(ndev, "status:#x%08x\n",
priv->read_reg(priv, XCAN_SR_OFFSET));
@ -600,7 +590,7 @@ static void xcan_write_frame(struct xcan_priv *priv, struct sk_buff *skb,
if (priv->devtype.cantype == XAXI_CANFD ||
priv->devtype.cantype == XAXI_CANFD_2_0) {
for (i = 0; i < cf->len; i += 4) {
ramoff = XCANFD_FRAME_DW_OFFSET(frame_offset, dwindex) +
ramoff = XCANFD_FRAME_DW_OFFSET(frame_offset) +
(dwindex * XCANFD_DW_BYTES);
priv->write_reg(priv, ramoff,
be32_to_cpup((__be32 *)(cf->data + i)));
@ -816,94 +806,69 @@ static int xcanfd_rx(struct net_device *ndev, int frame_base)
struct net_device_stats *stats = &ndev->stats;
struct canfd_frame *cf;
struct sk_buff *skb;
u32 id_xcan, dlc, data[2] = {0, 0}, dwindex = 0, i, fsr, readindex;
u32 id_xcan, dlc, data[2] = {0, 0}, dwindex = 0, i, dw_offset;
fsr = priv->read_reg(priv, XCAN_FSR_OFFSET);
if (fsr & XCAN_FSR_FL_MASK) {
readindex = fsr & XCAN_FSR_RI_MASK;
id_xcan = priv->read_reg(priv,
XCAN_FRAME_ID_OFFSET(frame_base));
dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base));
if (dlc & XCAN_DLCR_EDL_MASK)
skb = alloc_canfd_skb(ndev, &cf);
else
skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
id_xcan = priv->read_reg(priv, XCAN_FRAME_ID_OFFSET(frame_base));
dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base));
if (dlc & XCAN_DLCR_EDL_MASK)
skb = alloc_canfd_skb(ndev, &cf);
else
skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
if (unlikely(!skb)) {
stats->rx_dropped++;
return 0;
}
/* Change Xilinx CANFD data length format to socketCAN data
* format
*/
if (dlc & XCAN_DLCR_EDL_MASK)
cf->len = can_dlc2len((dlc & XCAN_DLCR_DLC_MASK) >>
XCAN_DLCR_DLC_SHIFT);
else
cf->len = get_can_dlc((dlc & XCAN_DLCR_DLC_MASK) >>
XCAN_DLCR_DLC_SHIFT);
/* Change Xilinx CAN ID format to socketCAN ID format */
if (id_xcan & XCAN_IDR_IDE_MASK) {
/* The received frame is an Extended format frame */
cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3;
cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >>
XCAN_IDR_ID2_SHIFT;
cf->can_id |= CAN_EFF_FLAG;
if (id_xcan & XCAN_IDR_RTR_MASK)
cf->can_id |= CAN_RTR_FLAG;
} else {
/* The received frame is a standard format frame */
cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >>
XCAN_IDR_ID1_SHIFT;
if (!(dlc & XCAN_DLCR_EDL_MASK) && (id_xcan &
XCAN_IDR_SRR_MASK))
cf->can_id |= CAN_RTR_FLAG;
}
/* Check the frame received is FD or not*/
if (dlc & XCAN_DLCR_EDL_MASK) {
for (i = 0; i < cf->len; i += 4) {
if (priv->devtype.flags & XCAN_FLAG_CANFD_2)
data[0] = priv->read_reg(priv,
(XCAN_RXMSG_2_FRAME_OFFSET(readindex) +
(dwindex * XCANFD_DW_BYTES)));
else
data[0] = priv->read_reg(priv,
(XCAN_RXMSG_FRAME_OFFSET(readindex) +
(dwindex * XCANFD_DW_BYTES)));
*(__be32 *)(cf->data + i) =
cpu_to_be32(data[0]);
dwindex++;
}
} else {
for (i = 0; i < cf->len; i += 4) {
if (priv->devtype.flags & XCAN_FLAG_CANFD_2)
data[0] = priv->read_reg(priv,
XCAN_RXMSG_2_FRAME_OFFSET(readindex) + i);
else
data[0] = priv->read_reg(priv,
XCAN_RXMSG_FRAME_OFFSET(readindex) + i);
*(__be32 *)(cf->data + i) =
cpu_to_be32(data[0]);
}
}
/* Update FSR Register so that next packet will save to
* buffer
*/
fsr = priv->read_reg(priv, XCAN_FSR_OFFSET);
fsr |= XCAN_FSR_IRI_MASK;
priv->write_reg(priv, XCAN_FSR_OFFSET, fsr);
fsr = priv->read_reg(priv, XCAN_FSR_OFFSET);
stats->rx_bytes += cf->len;
stats->rx_packets++;
netif_receive_skb(skb);
return 1;
if (unlikely(!skb)) {
stats->rx_dropped++;
return 0;
}
/* If FSR Register is not updated with fill level */
return 0;
/* Change Xilinx CANFD data length format to socketCAN data
* format
*/
if (dlc & XCAN_DLCR_EDL_MASK)
cf->len = can_dlc2len((dlc & XCAN_DLCR_DLC_MASK) >>
XCAN_DLCR_DLC_SHIFT);
else
cf->len = get_can_dlc((dlc & XCAN_DLCR_DLC_MASK) >>
XCAN_DLCR_DLC_SHIFT);
/* Change Xilinx CAN ID format to socketCAN ID format */
if (id_xcan & XCAN_IDR_IDE_MASK) {
/* The received frame is an Extended format frame */
cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3;
cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >>
XCAN_IDR_ID2_SHIFT;
cf->can_id |= CAN_EFF_FLAG;
if (id_xcan & XCAN_IDR_RTR_MASK)
cf->can_id |= CAN_RTR_FLAG;
} else {
/* The received frame is a standard format frame */
cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >>
XCAN_IDR_ID1_SHIFT;
if (!(dlc & XCAN_DLCR_EDL_MASK) && (id_xcan &
XCAN_IDR_SRR_MASK))
cf->can_id |= CAN_RTR_FLAG;
}
/* Check the frame received is FD or not*/
if (dlc & XCAN_DLCR_EDL_MASK) {
for (i = 0; i < cf->len; i += 4) {
dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base) +
(dwindex * XCANFD_DW_BYTES);
data[0] = priv->read_reg(priv, dw_offset);
*(__be32 *)(cf->data + i) = cpu_to_be32(data[0]);
dwindex++;
}
} else {
for (i = 0; i < cf->len; i += 4) {
dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base);
data[0] = priv->read_reg(priv, dw_offset + i);
*(__be32 *)(cf->data + i) = cpu_to_be32(data[0]);
}
}
stats->rx_bytes += cf->len;
stats->rx_packets++;
netif_receive_skb(skb);
return 1;
}
/**
@ -1164,7 +1129,7 @@ static int xcan_rx_fifo_get_next_frame(struct xcan_priv *priv)
int offset;
if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI) {
u32 fsr;
u32 fsr, mask;
/* clear RXOK before the is-empty check so that any newly
* received frame will reassert it without a race
@ -1174,12 +1139,17 @@ static int xcan_rx_fifo_get_next_frame(struct xcan_priv *priv)
fsr = priv->read_reg(priv, XCAN_FSR_OFFSET);
/* check if RX FIFO is empty */
if (!(fsr & XCAN_FSR_FL_MASK))
if (priv->devtype.flags & XCAN_FLAG_CANFD_2)
mask = XCAN_2_FSR_FL_MASK;
else
mask = XCAN_FSR_FL_MASK;
if (!(fsr & mask))
return -ENOENT;
if (priv->devtype.flags & XCAN_FLAG_CANFD_2)
offset =
XCAN_RXMSG_2_FRAME_OFFSET(fsr & XCAN_FSR_RI_MASK);
XCAN_RXMSG_2_FRAME_OFFSET(fsr & XCAN_2_FSR_RI_MASK);
else
offset =
XCAN_RXMSG_FRAME_OFFSET(fsr & XCAN_FSR_RI_MASK);
@ -1791,7 +1761,8 @@ static int xcan_probe(struct platform_device *pdev)
/* Getting the CAN can_clk info */
priv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
if (IS_ERR(priv->can_clk)) {
dev_err(&pdev->dev, "Device clock not found.\n");
if (PTR_ERR(priv->can_clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Device clock not found.\n");
ret = PTR_ERR(priv->can_clk);
goto err_free;
}

View file

@ -80,6 +80,10 @@ enum {
CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
CGW_LIM_HOPS, /* limit the number of hops of this specific rule */
CGW_MOD_UID, /* user defined identifier for modification updates */
CGW_FDMOD_AND, /* CAN FD frame modification binary AND */
CGW_FDMOD_OR, /* CAN FD frame modification binary OR */
CGW_FDMOD_XOR, /* CAN FD frame modification binary XOR */
CGW_FDMOD_SET, /* CAN FD frame modification set alternate values */
__CGW_MAX
};
@ -88,15 +92,18 @@ enum {
#define CGW_FLAGS_CAN_ECHO 0x01
#define CGW_FLAGS_CAN_SRC_TSTAMP 0x02
#define CGW_FLAGS_CAN_IIF_TX_OK 0x04
#define CGW_FLAGS_CAN_FD 0x08
#define CGW_MOD_FUNCS 4 /* AND OR XOR SET */
/* CAN frame elements that are affected by curr. 3 CAN frame modifications */
#define CGW_MOD_ID 0x01
#define CGW_MOD_DLC 0x02
#define CGW_MOD_DLC 0x02 /* contains the data length in bytes */
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD length representation */
#define CGW_MOD_DATA 0x04
#define CGW_MOD_FLAGS 0x08 /* CAN FD flags */
#define CGW_FRAME_MODS 3 /* ID DLC DATA */
#define CGW_FRAME_MODS 4 /* ID DLC/LEN DATA FLAGS */
#define MAX_MODFUNCTIONS (CGW_MOD_FUNCS * CGW_FRAME_MODS)
@ -105,7 +112,13 @@ struct cgw_frame_mod {
__u8 modtype;
} __attribute__((packed));
struct cgw_fdframe_mod {
struct canfd_frame cf;
__u8 modtype;
} __attribute__((packed));
#define CGW_MODATTR_LEN sizeof(struct cgw_frame_mod)
#define CGW_FDMODATTR_LEN sizeof(struct cgw_fdframe_mod)
struct cgw_csum_xor {
__s8 from_idx;

View file

@ -40,15 +40,15 @@ struct can_bittiming {
};
/*
* CAN harware-dependent bit-timing constant
* CAN hardware-dependent bit-timing constant
*
* Used for calculating and checking bit-timing parameters
*/
struct can_bittiming_const {
char name[16]; /* Name of the CAN controller hardware */
__u32 tseg1_min; /* Time segement 1 = prop_seg + phase_seg1 */
__u32 tseg1_min; /* Time segment 1 = prop_seg + phase_seg1 */
__u32 tseg1_max;
__u32 tseg2_min; /* Time segement 2 = phase_seg2 */
__u32 tseg2_min; /* Time segment 2 = phase_seg2 */
__u32 tseg2_max;
__u32 sjw_max; /* Synchronisation jump width */
__u32 brp_min; /* Bit-rate prescaler */

View file

@ -1,6 +1,5 @@
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
* af_can.c - Protocol family CAN core module
/* af_can.c - Protocol family CAN core module
* (used by different CAN protocol modules)
*
* Copyright (c) 2002-2017 Volkswagen Group Electronic Research
@ -84,9 +83,7 @@ static DEFINE_MUTEX(proto_tab_lock);
static atomic_t skbcounter = ATOMIC_INIT(0);
/*
* af_can socket functions
*/
/* af_can socket functions */
static void can_sock_destruct(struct sock *sk)
{
@ -132,14 +129,13 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
err = request_module("can-proto-%d", protocol);
/*
* In case of error we only print a message but don't
/* In case of error we only print a message but don't
* return the error code immediately. Below we will
* return -EPROTONOSUPPORT
*/
if (err)
printk_ratelimited(KERN_ERR "can: request_module "
"(can-proto-%d) failed.\n", protocol);
pr_err_ratelimited("can: request_module (can-proto-%d) failed.\n",
protocol);
cp = can_get_proto(protocol);
}
@ -180,9 +176,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
return err;
}
/*
* af_can tx path
*/
/* af_can tx path */
/**
* can_send - transmit a CAN frame (optional with local loopback)
@ -215,11 +209,11 @@ int can_send(struct sk_buff *skb, int loop)
skb->protocol = htons(ETH_P_CANFD);
if (unlikely(cfd->len > CANFD_MAX_DLEN))
goto inval_skb;
} else
} else {
goto inval_skb;
}
/*
* Make sure the CAN frame can pass the selected CAN netdevice.
/* 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
*/
@ -250,8 +244,7 @@ int can_send(struct sk_buff *skb, int loop)
/* indication for the CAN driver: do loopback */
skb->pkt_type = PACKET_LOOPBACK;
/*
* The reference to the originating sock may be required
/* The reference to the originating sock may be required
* by the receiving socket to check whether the frame is
* its own. Example: can_raw sockopt CAN_RAW_RECV_OWN_MSGS
* Therefore we have to ensure that skb->sk remains the
@ -260,8 +253,7 @@ int can_send(struct sk_buff *skb, int loop)
*/
if (!(skb->dev->flags & IFF_ECHO)) {
/*
* If the interface is not capable to do loopback
/* If the interface is not capable to do loopback
* itself, we do it here.
*/
newskb = skb_clone(skb, GFP_ATOMIC);
@ -304,12 +296,10 @@ int can_send(struct sk_buff *skb, int loop)
}
EXPORT_SYMBOL(can_send);
/*
* af_can rx path
*/
/* af_can rx path */
static struct can_dev_rcv_lists *find_dev_rcv_lists(struct net *net,
struct net_device *dev)
struct net_device *dev)
{
if (!dev)
return net->can.can_rx_alldev_list;
@ -401,7 +391,6 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
/* extra filterlists for the subscription of a single non-RTR can_id */
if (((*mask & CAN_EFF_RTR_FLAGS) == CAN_EFF_RTR_FLAGS) &&
!(*can_id & CAN_RTR_FLAG)) {
if (*can_id & CAN_EFF_FLAG) {
if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS))
return &d->rx_eff[effhash(*can_id)];
@ -498,9 +487,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
}
EXPORT_SYMBOL(can_rx_register);
/*
* can_rx_delete_receiver - rcu callback for single receiver entry removal
*/
/* can_rx_delete_receiver - rcu callback for single receiver entry removal */
static void can_rx_delete_receiver(struct rcu_head *rp)
{
struct receiver *r = container_of(rp, struct receiver, rcu);
@ -541,16 +528,14 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
d = find_dev_rcv_lists(net, dev);
if (!d) {
pr_err("BUG: receive list not found for "
"dev %s, id %03X, mask %03X\n",
pr_err("BUG: receive list not found for dev %s, id %03X, mask %03X\n",
DNAME(dev), can_id, mask);
goto out;
}
rl = find_rcv_list(&can_id, &mask, d);
/*
* Search the receiver list for the item to delete. This should
/* Search the receiver list for the item to delete. This should
* exist, since no receiver may be unregistered that hasn't
* been registered before.
*/
@ -561,14 +546,13 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
break;
}
/*
* Check for bugs in CAN protocol implementations using af_can.c:
/* Check for bugs in CAN protocol implementations using af_can.c:
* 'r' will be NULL if no matching list item was found for removal.
*/
if (!r) {
WARN(1, "BUG: receive list entry not found for dev %s, "
"id %03X, mask %03X\n", DNAME(dev), can_id, mask);
WARN(1, "BUG: receive list entry not found for dev %s, id %03X, mask %03X\n",
DNAME(dev), can_id, mask);
goto out;
}
@ -721,7 +705,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
}
static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
struct packet_type *pt, struct net_device *orig_dev)
{
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
@ -737,9 +721,7 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
return NET_RX_SUCCESS;
}
/*
* af_can protocol functions
*/
/* af_can protocol functions */
/**
* can_proto_register - register CAN transport protocol
@ -770,8 +752,9 @@ int can_proto_register(const struct can_proto *cp)
if (rcu_access_pointer(proto_tab[proto])) {
pr_err("can: protocol %d already registered\n", proto);
err = -EBUSY;
} else
} else {
RCU_INIT_POINTER(proto_tab[proto], cp);
}
mutex_unlock(&proto_tab_lock);
@ -801,9 +784,7 @@ void can_proto_unregister(const struct can_proto *cp)
}
EXPORT_SYMBOL(can_proto_unregister);
/*
* af_can notifier to create/remove CAN netdevice specific structs
*/
/* af_can notifier to create/remove CAN netdevice specific structs */
static int can_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
{
@ -814,7 +795,6 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
return NOTIFY_DONE;
switch (msg) {
case NETDEV_REGISTER:
/* create new dev_rcv_lists for this device */
@ -831,15 +811,16 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
d = dev->ml_priv;
if (d) {
if (d->entries)
if (d->entries) {
d->remove_on_zero_entries = 1;
else {
} else {
kfree(d);
dev->ml_priv = NULL;
}
} else
pr_err("can: notifier: receive list not found for dev "
"%s\n", dev->name);
} else {
pr_err("can: notifier: receive list not found for dev %s\n",
dev->name);
}
spin_unlock(&dev_net(dev)->can.can_rcvlists_lock);
@ -853,13 +834,13 @@ static int can_pernet_init(struct net *net)
{
spin_lock_init(&net->can.can_rcvlists_lock);
net->can.can_rx_alldev_list =
kzalloc(sizeof(struct can_dev_rcv_lists), GFP_KERNEL);
kzalloc(sizeof(*net->can.can_rx_alldev_list), GFP_KERNEL);
if (!net->can.can_rx_alldev_list)
goto out;
net->can.can_stats = kzalloc(sizeof(struct s_stats), GFP_KERNEL);
net->can.can_stats = kzalloc(sizeof(*net->can.can_stats), GFP_KERNEL);
if (!net->can.can_stats)
goto out_free_alldev_list;
net->can.can_pstats = kzalloc(sizeof(struct s_pstats), GFP_KERNEL);
net->can.can_pstats = kzalloc(sizeof(*net->can.can_pstats), GFP_KERNEL);
if (!net->can.can_pstats)
goto out_free_can_stats;
@ -913,9 +894,7 @@ static void can_pernet_exit(struct net *net)
kfree(net->can.can_pstats);
}
/*
* af_can module init/exit functions
*/
/* af_can module init/exit functions */
static struct packet_type can_packet __read_mostly = {
.type = cpu_to_be16(ETH_P_CAN),

View file

@ -1,6 +1,5 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
/* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -54,7 +53,7 @@ struct receiver {
canid_t can_id;
canid_t mask;
unsigned long matches;
void (*func)(struct sk_buff *, void *);
void (*func)(struct sk_buff *skb, void *data);
void *data;
char *ident;
struct sock *sk;

View file

@ -106,7 +106,6 @@ struct bcm_op {
unsigned long frames_abs, frames_filtered;
struct bcm_timeval ival1, ival2;
struct hrtimer timer, thrtimer;
struct tasklet_struct tsklet, thrtsklet;
ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
int rx_ifindex;
int cfsiz;
@ -371,25 +370,34 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
}
}
static void bcm_tx_start_timer(struct bcm_op *op)
static bool bcm_tx_set_expiry(struct bcm_op *op, struct hrtimer *hrt)
{
ktime_t ival;
if (op->kt_ival1 && op->count)
hrtimer_start(&op->timer,
ktime_add(ktime_get(), op->kt_ival1),
HRTIMER_MODE_ABS);
ival = op->kt_ival1;
else if (op->kt_ival2)
hrtimer_start(&op->timer,
ktime_add(ktime_get(), op->kt_ival2),
HRTIMER_MODE_ABS);
ival = op->kt_ival2;
else
return false;
hrtimer_set_expires(hrt, ktime_add(ktime_get(), ival));
return true;
}
static void bcm_tx_timeout_tsklet(unsigned long data)
static void bcm_tx_start_timer(struct bcm_op *op)
{
struct bcm_op *op = (struct bcm_op *)data;
if (bcm_tx_set_expiry(op, &op->timer))
hrtimer_start_expires(&op->timer, HRTIMER_MODE_ABS_SOFT);
}
/* bcm_tx_timeout_handler - performs cyclic CAN frame transmissions */
static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
{
struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
struct bcm_msg_head msg_head;
if (op->kt_ival1 && (op->count > 0)) {
op->count--;
if (!op->count && (op->flags & TX_COUNTEVT)) {
@ -406,22 +414,12 @@ static void bcm_tx_timeout_tsklet(unsigned long data)
}
bcm_can_tx(op);
} else if (op->kt_ival2)
} else if (op->kt_ival2) {
bcm_can_tx(op);
}
bcm_tx_start_timer(op);
}
/*
* bcm_tx_timeout_handler - performs cyclic CAN frame transmissions
*/
static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
{
struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
tasklet_schedule(&op->tsklet);
return HRTIMER_NORESTART;
return bcm_tx_set_expiry(op, &op->timer) ?
HRTIMER_RESTART : HRTIMER_NORESTART;
}
/*
@ -487,7 +485,7 @@ static void bcm_rx_update_and_send(struct bcm_op *op,
/* do not send the saved data - only start throttle timer */
hrtimer_start(&op->thrtimer,
ktime_add(op->kt_lastmsg, op->kt_ival2),
HRTIMER_MODE_ABS);
HRTIMER_MODE_ABS_SOFT);
return;
}
@ -546,14 +544,21 @@ static void bcm_rx_starttimer(struct bcm_op *op)
return;
if (op->kt_ival1)
hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL);
hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL_SOFT);
}
static void bcm_rx_timeout_tsklet(unsigned long data)
/* bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out */
static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
{
struct bcm_op *op = (struct bcm_op *)data;
struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
struct bcm_msg_head msg_head;
/* if user wants to be informed, when cyclic CAN-Messages come back */
if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
/* clear received CAN frames to indicate 'nothing received' */
memset(op->last_frames, 0, op->nframes * op->cfsiz);
}
/* create notification to user */
msg_head.opcode = RX_TIMEOUT;
msg_head.flags = op->flags;
@ -564,25 +569,6 @@ static void bcm_rx_timeout_tsklet(unsigned long data)
msg_head.nframes = 0;
bcm_send_to_user(op, &msg_head, NULL, 0);
}
/*
* bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out
*/
static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
{
struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
/* schedule before NET_RX_SOFTIRQ */
tasklet_hi_schedule(&op->tsklet);
/* no restart of the timer is done here! */
/* if user wants to be informed, when cyclic CAN-Messages come back */
if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
/* clear received CAN frames to indicate 'nothing received' */
memset(op->last_frames, 0, op->nframes * op->cfsiz);
}
return HRTIMER_NORESTART;
}
@ -590,14 +576,12 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
/*
* bcm_rx_do_flush - helper for bcm_rx_thr_flush
*/
static inline int bcm_rx_do_flush(struct bcm_op *op, int update,
unsigned int index)
static inline int bcm_rx_do_flush(struct bcm_op *op, unsigned int index)
{
struct canfd_frame *lcf = op->last_frames + op->cfsiz * index;
if ((op->last_frames) && (lcf->flags & RX_THR)) {
if (update)
bcm_rx_changed(op, lcf);
bcm_rx_changed(op, lcf);
return 1;
}
return 0;
@ -605,11 +589,8 @@ static inline int bcm_rx_do_flush(struct bcm_op *op, int update,
/*
* bcm_rx_thr_flush - Check for throttled data and send it to the userspace
*
* update == 0 : just check if throttled data is available (any irq context)
* update == 1 : check and send throttled data to userspace (soft_irq context)
*/
static int bcm_rx_thr_flush(struct bcm_op *op, int update)
static int bcm_rx_thr_flush(struct bcm_op *op)
{
int updated = 0;
@ -618,24 +599,16 @@ static int bcm_rx_thr_flush(struct bcm_op *op, int update)
/* for MUX filter we start at index 1 */
for (i = 1; i < op->nframes; i++)
updated += bcm_rx_do_flush(op, update, i);
updated += bcm_rx_do_flush(op, i);
} else {
/* for RX_FILTER_ID and simple filter */
updated += bcm_rx_do_flush(op, update, 0);
updated += bcm_rx_do_flush(op, 0);
}
return updated;
}
static void bcm_rx_thr_tsklet(unsigned long data)
{
struct bcm_op *op = (struct bcm_op *)data;
/* push the changed data to the userspace */
bcm_rx_thr_flush(op, 1);
}
/*
* bcm_rx_thr_handler - the time for blocked content updates is over now:
* Check for throttled data and send it to the userspace
@ -644,9 +617,7 @@ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
{
struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
tasklet_schedule(&op->thrtsklet);
if (bcm_rx_thr_flush(op, 0)) {
if (bcm_rx_thr_flush(op)) {
hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2);
return HRTIMER_RESTART;
} else {
@ -742,23 +713,8 @@ static struct bcm_op *bcm_find_op(struct list_head *ops,
static void bcm_remove_op(struct bcm_op *op)
{
if (op->tsklet.func) {
while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) ||
test_bit(TASKLET_STATE_RUN, &op->tsklet.state) ||
hrtimer_active(&op->timer)) {
hrtimer_cancel(&op->timer);
tasklet_kill(&op->tsklet);
}
}
if (op->thrtsklet.func) {
while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) ||
test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) ||
hrtimer_active(&op->thrtimer)) {
hrtimer_cancel(&op->thrtimer);
tasklet_kill(&op->thrtsklet);
}
}
hrtimer_cancel(&op->timer);
hrtimer_cancel(&op->thrtimer);
if ((op->frames) && (op->frames != &op->sframe))
kfree(op->frames);
@ -991,15 +947,13 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
op->ifindex = ifindex;
/* initialize uninitialized (kzalloc) structure */
hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_init(&op->timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_SOFT);
op->timer.function = bcm_tx_timeout_handler;
/* initialize tasklet for tx countevent notification */
tasklet_init(&op->tsklet, bcm_tx_timeout_tsklet,
(unsigned long) op);
/* currently unused in tx_ops */
hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_SOFT);
/* add this bcm_op to the list of the tx_ops */
list_add(&op->list, &bo->tx_ops);
@ -1168,20 +1122,14 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
op->rx_ifindex = ifindex;
/* initialize uninitialized (kzalloc) structure */
hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_init(&op->timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_SOFT);
op->timer.function = bcm_rx_timeout_handler;
/* initialize tasklet for rx timeout notification */
tasklet_init(&op->tsklet, bcm_rx_timeout_tsklet,
(unsigned long) op);
hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_SOFT);
op->thrtimer.function = bcm_rx_thr_handler;
/* initialize tasklet for rx throttle handling */
tasklet_init(&op->thrtsklet, bcm_rx_thr_tsklet,
(unsigned long) op);
/* add this bcm_op to the list of the rx_ops */
list_add(&op->list, &bo->rx_ops);
@ -1227,12 +1175,12 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
*/
op->kt_lastmsg = 0;
hrtimer_cancel(&op->thrtimer);
bcm_rx_thr_flush(op, 1);
bcm_rx_thr_flush(op);
}
if ((op->flags & STARTTIMER) && op->kt_ival1)
hrtimer_start(&op->timer, op->kt_ival1,
HRTIMER_MODE_REL);
HRTIMER_MODE_REL_SOFT);
}
/* now we can register for can_ids, if we added a new bcm_op */
@ -1680,8 +1628,8 @@ static int bcm_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
return size;
}
int bcm_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd,
unsigned long arg)
static int bcm_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
/* no ioctls for socket layer -> hand it down to NIC layer */
return -ENOIOCTLCMD;

View file

@ -1,8 +1,7 @@
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
/*
* gw.c - CAN frame Gateway/Router/Bridge with netlink interface
/* gw.c - CAN frame Gateway/Router/Bridge with netlink interface
*
* Copyright (c) 2017 Volkswagen Group Electronic Research
* Copyright (c) 2019 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -60,7 +59,7 @@
#include <net/net_namespace.h>
#include <net/sock.h>
#define CAN_GW_VERSION "20170425"
#define CAN_GW_VERSION "20190810"
#define CAN_GW_NAME "can-gw"
MODULE_DESCRIPTION("PF_CAN netlink gateway");
@ -86,10 +85,10 @@ static struct kmem_cache *cgw_cache __read_mostly;
/* structure that contains the (on-the-fly) CAN frame modifications */
struct cf_mod {
struct {
struct can_frame and;
struct can_frame or;
struct can_frame xor;
struct can_frame set;
struct canfd_frame and;
struct canfd_frame or;
struct canfd_frame xor;
struct canfd_frame set;
} modframe;
struct {
u8 and;
@ -97,7 +96,7 @@ struct cf_mod {
u8 xor;
u8 set;
} modtype;
void (*modfunc[MAX_MODFUNCTIONS])(struct can_frame *cf,
void (*modfunc[MAX_MODFUNCTIONS])(struct canfd_frame *cf,
struct cf_mod *mod);
/* CAN frame checksum calculation after CAN frame modifications */
@ -106,15 +105,15 @@ struct cf_mod {
struct cgw_csum_crc8 crc8;
} csum;
struct {
void (*xor)(struct can_frame *cf, struct cgw_csum_xor *xor);
void (*crc8)(struct can_frame *cf, struct cgw_csum_crc8 *crc8);
void (*xor)(struct canfd_frame *cf,
struct cgw_csum_xor *xor);
void (*crc8)(struct canfd_frame *cf,
struct cgw_csum_crc8 *crc8);
} csumfunc;
u32 uid;
};
/*
* So far we just support CAN -> CAN routing and frame modifications.
/* So far we just support CAN -> CAN routing and frame modifications.
*
* The internal can_can_gw structure contains data and attributes for
* a CAN -> CAN gateway job.
@ -152,39 +151,88 @@ struct cgw_job {
/* modification functions that are invoked in the hot path in can_can_gw_rcv */
#define MODFUNC(func, op) static void func(struct can_frame *cf, \
#define MODFUNC(func, op) static void func(struct canfd_frame *cf, \
struct cf_mod *mod) { op ; }
MODFUNC(mod_and_id, cf->can_id &= mod->modframe.and.can_id)
MODFUNC(mod_and_dlc, cf->can_dlc &= mod->modframe.and.can_dlc)
MODFUNC(mod_and_len, cf->len &= mod->modframe.and.len)
MODFUNC(mod_and_flags, cf->flags &= mod->modframe.and.flags)
MODFUNC(mod_and_data, *(u64 *)cf->data &= *(u64 *)mod->modframe.and.data)
MODFUNC(mod_or_id, cf->can_id |= mod->modframe.or.can_id)
MODFUNC(mod_or_dlc, cf->can_dlc |= mod->modframe.or.can_dlc)
MODFUNC(mod_or_len, cf->len |= mod->modframe.or.len)
MODFUNC(mod_or_flags, cf->flags |= mod->modframe.or.flags)
MODFUNC(mod_or_data, *(u64 *)cf->data |= *(u64 *)mod->modframe.or.data)
MODFUNC(mod_xor_id, cf->can_id ^= mod->modframe.xor.can_id)
MODFUNC(mod_xor_dlc, cf->can_dlc ^= mod->modframe.xor.can_dlc)
MODFUNC(mod_xor_len, cf->len ^= mod->modframe.xor.len)
MODFUNC(mod_xor_flags, cf->flags ^= mod->modframe.xor.flags)
MODFUNC(mod_xor_data, *(u64 *)cf->data ^= *(u64 *)mod->modframe.xor.data)
MODFUNC(mod_set_id, cf->can_id = mod->modframe.set.can_id)
MODFUNC(mod_set_dlc, cf->can_dlc = mod->modframe.set.can_dlc)
MODFUNC(mod_set_len, cf->len = mod->modframe.set.len)
MODFUNC(mod_set_flags, cf->flags = mod->modframe.set.flags)
MODFUNC(mod_set_data, *(u64 *)cf->data = *(u64 *)mod->modframe.set.data)
static inline void canframecpy(struct can_frame *dst, struct can_frame *src)
static void mod_and_fddata(struct canfd_frame *cf, struct cf_mod *mod)
{
/*
* Copy the struct members separately to ensure that no uninitialized
int i;
for (i = 0; i < CANFD_MAX_DLEN; i += 8)
*(u64 *)(cf->data + i) &= *(u64 *)(mod->modframe.and.data + i);
}
static void mod_or_fddata(struct canfd_frame *cf, struct cf_mod *mod)
{
int i;
for (i = 0; i < CANFD_MAX_DLEN; i += 8)
*(u64 *)(cf->data + i) |= *(u64 *)(mod->modframe.or.data + i);
}
static void mod_xor_fddata(struct canfd_frame *cf, struct cf_mod *mod)
{
int i;
for (i = 0; i < CANFD_MAX_DLEN; i += 8)
*(u64 *)(cf->data + i) ^= *(u64 *)(mod->modframe.xor.data + i);
}
static void mod_set_fddata(struct canfd_frame *cf, struct cf_mod *mod)
{
memcpy(cf->data, mod->modframe.set.data, CANFD_MAX_DLEN);
}
static void canframecpy(struct canfd_frame *dst, struct can_frame *src)
{
/* Copy the struct members separately to ensure that no uninitialized
* data are copied in the 3 bytes hole of the struct. This is needed
* to make easy compares of the data in the struct cf_mod.
*/
dst->can_id = src->can_id;
dst->can_dlc = src->can_dlc;
dst->len = src->can_dlc;
*(u64 *)dst->data = *(u64 *)src->data;
}
static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re)
static void canfdframecpy(struct canfd_frame *dst, struct canfd_frame *src)
{
/*
* absolute dlc values 0 .. 7 => 0 .. 7, e.g. data [0]
/* Copy the struct members separately to ensure that no uninitialized
* data are copied in the 2 bytes hole of the struct. This is needed
* to make easy compares of the data in the struct cf_mod.
*/
dst->can_id = src->can_id;
dst->flags = src->flags;
dst->len = src->len;
memcpy(dst->data, src->data, CANFD_MAX_DLEN);
}
static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re, struct rtcanmsg *r)
{
s8 dlen = CAN_MAX_DLEN;
if (r->flags & CGW_FLAGS_CAN_FD)
dlen = CANFD_MAX_DLEN;
/* absolute dlc values 0 .. 7 => 0 .. 7, e.g. data [0]
* relative to received dlc -1 .. -8 :
* e.g. for received dlc = 8
* -1 => index = 7 (data[7])
@ -192,27 +240,27 @@ static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re)
* -8 => index = 0 (data[0])
*/
if (fr > -9 && fr < 8 &&
to > -9 && to < 8 &&
re > -9 && re < 8)
if (fr >= -dlen && fr < dlen &&
to >= -dlen && to < dlen &&
re >= -dlen && re < dlen)
return 0;
else
return -EINVAL;
}
static inline int calc_idx(int idx, int rx_dlc)
static inline int calc_idx(int idx, int rx_len)
{
if (idx < 0)
return rx_dlc + idx;
return rx_len + idx;
else
return idx;
}
static void cgw_csum_xor_rel(struct can_frame *cf, struct cgw_csum_xor *xor)
static void cgw_csum_xor_rel(struct canfd_frame *cf, struct cgw_csum_xor *xor)
{
int from = calc_idx(xor->from_idx, cf->can_dlc);
int to = calc_idx(xor->to_idx, cf->can_dlc);
int res = calc_idx(xor->result_idx, cf->can_dlc);
int from = calc_idx(xor->from_idx, cf->len);
int to = calc_idx(xor->to_idx, cf->len);
int res = calc_idx(xor->result_idx, cf->len);
u8 val = xor->init_xor_val;
int i;
@ -230,7 +278,7 @@ static void cgw_csum_xor_rel(struct can_frame *cf, struct cgw_csum_xor *xor)
cf->data[res] = val;
}
static void cgw_csum_xor_pos(struct can_frame *cf, struct cgw_csum_xor *xor)
static void cgw_csum_xor_pos(struct canfd_frame *cf, struct cgw_csum_xor *xor)
{
u8 val = xor->init_xor_val;
int i;
@ -241,7 +289,7 @@ static void cgw_csum_xor_pos(struct can_frame *cf, struct cgw_csum_xor *xor)
cf->data[xor->result_idx] = val;
}
static void cgw_csum_xor_neg(struct can_frame *cf, struct cgw_csum_xor *xor)
static void cgw_csum_xor_neg(struct canfd_frame *cf, struct cgw_csum_xor *xor)
{
u8 val = xor->init_xor_val;
int i;
@ -252,11 +300,12 @@ static void cgw_csum_xor_neg(struct can_frame *cf, struct cgw_csum_xor *xor)
cf->data[xor->result_idx] = val;
}
static void cgw_csum_crc8_rel(struct can_frame *cf, struct cgw_csum_crc8 *crc8)
static void cgw_csum_crc8_rel(struct canfd_frame *cf,
struct cgw_csum_crc8 *crc8)
{
int from = calc_idx(crc8->from_idx, cf->can_dlc);
int to = calc_idx(crc8->to_idx, cf->can_dlc);
int res = calc_idx(crc8->result_idx, cf->can_dlc);
int from = calc_idx(crc8->from_idx, cf->len);
int to = calc_idx(crc8->to_idx, cf->len);
int res = calc_idx(crc8->result_idx, cf->len);
u8 crc = crc8->init_crc_val;
int i;
@ -265,96 +314,102 @@ static void cgw_csum_crc8_rel(struct can_frame *cf, struct cgw_csum_crc8 *crc8)
if (from <= to) {
for (i = crc8->from_idx; i <= crc8->to_idx; i++)
crc = crc8->crctab[crc^cf->data[i]];
crc = crc8->crctab[crc ^ cf->data[i]];
} else {
for (i = crc8->from_idx; i >= crc8->to_idx; i--)
crc = crc8->crctab[crc^cf->data[i]];
crc = crc8->crctab[crc ^ cf->data[i]];
}
switch (crc8->profile) {
case CGW_CRC8PRF_1U8:
crc = crc8->crctab[crc^crc8->profile_data[0]];
crc = crc8->crctab[crc ^ crc8->profile_data[0]];
break;
case CGW_CRC8PRF_16U8:
crc = crc8->crctab[crc^crc8->profile_data[cf->data[1] & 0xF]];
crc = crc8->crctab[crc ^ crc8->profile_data[cf->data[1] & 0xF]];
break;
case CGW_CRC8PRF_SFFID_XOR:
crc = crc8->crctab[crc^(cf->can_id & 0xFF)^
crc = crc8->crctab[crc ^ (cf->can_id & 0xFF) ^
(cf->can_id >> 8 & 0xFF)];
break;
}
cf->data[crc8->result_idx] = crc^crc8->final_xor_val;
cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val;
}
static void cgw_csum_crc8_pos(struct can_frame *cf, struct cgw_csum_crc8 *crc8)
static void cgw_csum_crc8_pos(struct canfd_frame *cf,
struct cgw_csum_crc8 *crc8)
{
u8 crc = crc8->init_crc_val;
int i;
for (i = crc8->from_idx; i <= crc8->to_idx; i++)
crc = crc8->crctab[crc^cf->data[i]];
crc = crc8->crctab[crc ^ cf->data[i]];
switch (crc8->profile) {
case CGW_CRC8PRF_1U8:
crc = crc8->crctab[crc^crc8->profile_data[0]];
crc = crc8->crctab[crc ^ crc8->profile_data[0]];
break;
case CGW_CRC8PRF_16U8:
crc = crc8->crctab[crc^crc8->profile_data[cf->data[1] & 0xF]];
crc = crc8->crctab[crc ^ crc8->profile_data[cf->data[1] & 0xF]];
break;
case CGW_CRC8PRF_SFFID_XOR:
crc = crc8->crctab[crc^(cf->can_id & 0xFF)^
crc = crc8->crctab[crc ^ (cf->can_id & 0xFF) ^
(cf->can_id >> 8 & 0xFF)];
break;
}
cf->data[crc8->result_idx] = crc^crc8->final_xor_val;
cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val;
}
static void cgw_csum_crc8_neg(struct can_frame *cf, struct cgw_csum_crc8 *crc8)
static void cgw_csum_crc8_neg(struct canfd_frame *cf,
struct cgw_csum_crc8 *crc8)
{
u8 crc = crc8->init_crc_val;
int i;
for (i = crc8->from_idx; i >= crc8->to_idx; i--)
crc = crc8->crctab[crc^cf->data[i]];
crc = crc8->crctab[crc ^ cf->data[i]];
switch (crc8->profile) {
case CGW_CRC8PRF_1U8:
crc = crc8->crctab[crc^crc8->profile_data[0]];
crc = crc8->crctab[crc ^ crc8->profile_data[0]];
break;
case CGW_CRC8PRF_16U8:
crc = crc8->crctab[crc^crc8->profile_data[cf->data[1] & 0xF]];
crc = crc8->crctab[crc ^ crc8->profile_data[cf->data[1] & 0xF]];
break;
case CGW_CRC8PRF_SFFID_XOR:
crc = crc8->crctab[crc^(cf->can_id & 0xFF)^
crc = crc8->crctab[crc ^ (cf->can_id & 0xFF) ^
(cf->can_id >> 8 & 0xFF)];
break;
}
cf->data[crc8->result_idx] = crc^crc8->final_xor_val;
cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val;
}
/* the receive & process & send function */
static void can_can_gw_rcv(struct sk_buff *skb, void *data)
{
struct cgw_job *gwj = (struct cgw_job *)data;
struct can_frame *cf;
struct canfd_frame *cf;
struct sk_buff *nskb;
int modidx = 0;
/*
* Do not handle CAN frames routed more than 'max_hops' times.
/* process strictly Classic CAN or CAN FD frames */
if (gwj->flags & CGW_FLAGS_CAN_FD) {
if (skb->len != CANFD_MTU)
return;
} else {
if (skb->len != CAN_MTU)
return;
}
/* 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).
*
@ -385,8 +440,7 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
can_skb_prv(skb)->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()
*
* When there is at least one modification function activated,
* we need to copy the skb as we want to modify skb->data.
@ -411,7 +465,7 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
nskb->dev = gwj->dst.dev;
/* pointer to modifiable CAN frame */
cf = (struct can_frame *)nskb->data;
cf = (struct canfd_frame *)nskb->data;
/* perform preprocessed modification functions if there are any */
while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx])
@ -420,26 +474,22 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
/* Has the CAN frame been modified? */
if (modidx) {
/* get available space for the processed CAN frame type */
int max_len = nskb->len - offsetof(struct can_frame, data);
int max_len = nskb->len - offsetof(struct canfd_frame, data);
/* dlc may have changed, make sure it fits to the CAN frame */
if (cf->can_dlc > max_len)
goto out_delete;
/* check for checksum updates in classic CAN length only */
if (gwj->mod.csumfunc.crc8) {
if (cf->can_dlc > 8)
goto out_delete;
if (cf->len > max_len) {
/* delete frame due to misconfiguration */
gwj->deleted_frames++;
kfree_skb(nskb);
return;
}
/* check for checksum updates */
if (gwj->mod.csumfunc.crc8)
(*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8);
}
if (gwj->mod.csumfunc.xor) {
if (cf->can_dlc > 8)
goto out_delete;
if (gwj->mod.csumfunc.xor)
(*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor);
}
}
/* clear the skb timestamp if not configured the other way */
@ -451,14 +501,6 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
gwj->dropped_frames++;
else
gwj->handled_frames++;
return;
out_delete:
/* delete frame due to misconfiguration */
gwj->deleted_frames++;
kfree_skb(nskb);
return;
}
static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
@ -484,14 +526,12 @@ static int cgw_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
if (msg == NETDEV_UNREGISTER) {
struct cgw_job *gwj = NULL;
struct hlist_node *nx;
ASSERT_RTNL();
hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
if (gwj->src.dev == dev || gwj->dst.dev == dev) {
hlist_del(&gwj->list);
cgw_unregister_filter(net, gwj);
@ -506,7 +546,6 @@ static int cgw_notifier(struct notifier_block *nb,
static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
u32 pid, u32 seq, int flags)
{
struct cgw_frame_mod mb;
struct rtcanmsg *rtcan;
struct nlmsghdr *nlh;
@ -543,32 +582,66 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
goto cancel;
}
if (gwj->mod.modtype.and) {
memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.and;
if (nla_put(skb, CGW_MOD_AND, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->flags & CGW_FLAGS_CAN_FD) {
struct cgw_fdframe_mod mb;
if (gwj->mod.modtype.or) {
memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.or;
if (nla_put(skb, CGW_MOD_OR, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->mod.modtype.and) {
memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.and;
if (nla_put(skb, CGW_FDMOD_AND, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->mod.modtype.xor) {
memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.xor;
if (nla_put(skb, CGW_MOD_XOR, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->mod.modtype.or) {
memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.or;
if (nla_put(skb, CGW_FDMOD_OR, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->mod.modtype.set) {
memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.set;
if (nla_put(skb, CGW_MOD_SET, sizeof(mb), &mb) < 0)
goto cancel;
if (gwj->mod.modtype.xor) {
memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.xor;
if (nla_put(skb, CGW_FDMOD_XOR, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->mod.modtype.set) {
memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.set;
if (nla_put(skb, CGW_FDMOD_SET, sizeof(mb), &mb) < 0)
goto cancel;
}
} else {
struct cgw_frame_mod mb;
if (gwj->mod.modtype.and) {
memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.and;
if (nla_put(skb, CGW_MOD_AND, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->mod.modtype.or) {
memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.or;
if (nla_put(skb, CGW_MOD_OR, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->mod.modtype.xor) {
memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.xor;
if (nla_put(skb, CGW_MOD_XOR, sizeof(mb), &mb) < 0)
goto cancel;
}
if (gwj->mod.modtype.set) {
memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf));
mb.modtype = gwj->mod.modtype.set;
if (nla_put(skb, CGW_MOD_SET, sizeof(mb), &mb) < 0)
goto cancel;
}
}
if (gwj->mod.uid) {
@ -589,7 +662,6 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
}
if (gwj->gwtype == CGW_TYPE_CAN_CAN) {
if (gwj->ccgw.filter.can_id || gwj->ccgw.filter.can_mask) {
if (nla_put(skb, CGW_FILTER, sizeof(struct can_filter),
&gwj->ccgw.filter) < 0)
@ -624,8 +696,9 @@ static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb)
if (idx < s_idx)
goto cont;
if (cgw_put_job(skb, gwj, RTM_NEWROUTE, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI) < 0)
if (cgw_put_job(skb, gwj, RTM_NEWROUTE,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI) < 0)
break;
cont:
idx++;
@ -637,7 +710,7 @@ static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
static const struct nla_policy cgw_policy[CGW_MAX+1] = {
static const struct nla_policy cgw_policy[CGW_MAX + 1] = {
[CGW_MOD_AND] = { .len = sizeof(struct cgw_frame_mod) },
[CGW_MOD_OR] = { .len = sizeof(struct cgw_frame_mod) },
[CGW_MOD_XOR] = { .len = sizeof(struct cgw_frame_mod) },
@ -649,14 +722,18 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = {
[CGW_FILTER] = { .len = sizeof(struct can_filter) },
[CGW_LIM_HOPS] = { .type = NLA_U8 },
[CGW_MOD_UID] = { .type = NLA_U32 },
[CGW_FDMOD_AND] = { .len = sizeof(struct cgw_fdframe_mod) },
[CGW_FDMOD_OR] = { .len = sizeof(struct cgw_fdframe_mod) },
[CGW_FDMOD_XOR] = { .len = sizeof(struct cgw_fdframe_mod) },
[CGW_FDMOD_SET] = { .len = sizeof(struct cgw_fdframe_mod) },
};
/* check for common and gwtype specific attributes */
static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
u8 gwtype, void *gwtypeattr, u8 *limhops)
{
struct nlattr *tb[CGW_MAX+1];
struct cgw_frame_mod mb;
struct nlattr *tb[CGW_MAX + 1];
struct rtcanmsg *r = nlmsg_data(nlh);
int modidx = 0;
int err = 0;
@ -676,87 +753,166 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
}
/* check for AND/OR/XOR/SET modifications */
if (r->flags & CGW_FLAGS_CAN_FD) {
struct cgw_fdframe_mod mb;
if (tb[CGW_MOD_AND]) {
nla_memcpy(&mb, tb[CGW_MOD_AND], CGW_MODATTR_LEN);
if (tb[CGW_FDMOD_AND]) {
nla_memcpy(&mb, tb[CGW_FDMOD_AND], CGW_FDMODATTR_LEN);
canframecpy(&mod->modframe.and, &mb.cf);
mod->modtype.and = mb.modtype;
canfdframecpy(&mod->modframe.and, &mb.cf);
mod->modtype.and = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_and_id;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_and_id;
if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_and_dlc;
if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_and_len;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_and_data;
}
if (mb.modtype & CGW_MOD_FLAGS)
mod->modfunc[modidx++] = mod_and_flags;
if (tb[CGW_MOD_OR]) {
nla_memcpy(&mb, tb[CGW_MOD_OR], CGW_MODATTR_LEN);
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_and_fddata;
}
canframecpy(&mod->modframe.or, &mb.cf);
mod->modtype.or = mb.modtype;
if (tb[CGW_FDMOD_OR]) {
nla_memcpy(&mb, tb[CGW_FDMOD_OR], CGW_FDMODATTR_LEN);
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_or_id;
canfdframecpy(&mod->modframe.or, &mb.cf);
mod->modtype.or = mb.modtype;
if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_or_dlc;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_or_id;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_or_data;
}
if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_or_len;
if (tb[CGW_MOD_XOR]) {
nla_memcpy(&mb, tb[CGW_MOD_XOR], CGW_MODATTR_LEN);
if (mb.modtype & CGW_MOD_FLAGS)
mod->modfunc[modidx++] = mod_or_flags;
canframecpy(&mod->modframe.xor, &mb.cf);
mod->modtype.xor = mb.modtype;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_or_fddata;
}
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_xor_id;
if (tb[CGW_FDMOD_XOR]) {
nla_memcpy(&mb, tb[CGW_FDMOD_XOR], CGW_FDMODATTR_LEN);
if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_xor_dlc;
canfdframecpy(&mod->modframe.xor, &mb.cf);
mod->modtype.xor = mb.modtype;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_xor_data;
}
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_xor_id;
if (tb[CGW_MOD_SET]) {
nla_memcpy(&mb, tb[CGW_MOD_SET], CGW_MODATTR_LEN);
if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_xor_len;
canframecpy(&mod->modframe.set, &mb.cf);
mod->modtype.set = mb.modtype;
if (mb.modtype & CGW_MOD_FLAGS)
mod->modfunc[modidx++] = mod_xor_flags;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_set_id;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_xor_fddata;
}
if (mb.modtype & CGW_MOD_DLC)
mod->modfunc[modidx++] = mod_set_dlc;
if (tb[CGW_FDMOD_SET]) {
nla_memcpy(&mb, tb[CGW_FDMOD_SET], CGW_FDMODATTR_LEN);
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_set_data;
canfdframecpy(&mod->modframe.set, &mb.cf);
mod->modtype.set = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_set_id;
if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_set_len;
if (mb.modtype & CGW_MOD_FLAGS)
mod->modfunc[modidx++] = mod_set_flags;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_set_fddata;
}
} else {
struct cgw_frame_mod mb;
if (tb[CGW_MOD_AND]) {
nla_memcpy(&mb, tb[CGW_MOD_AND], CGW_MODATTR_LEN);
canframecpy(&mod->modframe.and, &mb.cf);
mod->modtype.and = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_and_id;
if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_and_len;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_and_data;
}
if (tb[CGW_MOD_OR]) {
nla_memcpy(&mb, tb[CGW_MOD_OR], CGW_MODATTR_LEN);
canframecpy(&mod->modframe.or, &mb.cf);
mod->modtype.or = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_or_id;
if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_or_len;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_or_data;
}
if (tb[CGW_MOD_XOR]) {
nla_memcpy(&mb, tb[CGW_MOD_XOR], CGW_MODATTR_LEN);
canframecpy(&mod->modframe.xor, &mb.cf);
mod->modtype.xor = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_xor_id;
if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_xor_len;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_xor_data;
}
if (tb[CGW_MOD_SET]) {
nla_memcpy(&mb, tb[CGW_MOD_SET], CGW_MODATTR_LEN);
canframecpy(&mod->modframe.set, &mb.cf);
mod->modtype.set = mb.modtype;
if (mb.modtype & CGW_MOD_ID)
mod->modfunc[modidx++] = mod_set_id;
if (mb.modtype & CGW_MOD_LEN)
mod->modfunc[modidx++] = mod_set_len;
if (mb.modtype & CGW_MOD_DATA)
mod->modfunc[modidx++] = mod_set_data;
}
}
/* check for checksum operations after CAN frame modifications */
if (modidx) {
if (tb[CGW_CS_CRC8]) {
struct cgw_csum_crc8 *c = nla_data(tb[CGW_CS_CRC8]);
err = cgw_chk_csum_parms(c->from_idx, c->to_idx,
c->result_idx);
c->result_idx, r);
if (err)
return err;
nla_memcpy(&mod->csum.crc8, tb[CGW_CS_CRC8],
CGW_CS_CRC8_LEN);
/*
* select dedicated processing function to reduce
/* select dedicated processing function to reduce
* runtime operations in receive hot path.
*/
if (c->from_idx < 0 || c->to_idx < 0 ||
@ -772,15 +928,14 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
struct cgw_csum_xor *c = nla_data(tb[CGW_CS_XOR]);
err = cgw_chk_csum_parms(c->from_idx, c->to_idx,
c->result_idx);
c->result_idx, r);
if (err)
return err;
nla_memcpy(&mod->csum.xor, tb[CGW_CS_XOR],
CGW_CS_XOR_LEN);
/*
* select dedicated processing function to reduce
/* select dedicated processing function to reduce
* runtime operations in receive hot path.
*/
if (c->from_idx < 0 || c->to_idx < 0 ||
@ -792,16 +947,14 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
mod->csumfunc.xor = cgw_csum_xor_neg;
}
if (tb[CGW_MOD_UID]) {
if (tb[CGW_MOD_UID])
nla_memcpy(&mod->uid, tb[CGW_MOD_UID], sizeof(u32));
}
}
if (gwtype == CGW_TYPE_CAN_CAN) {
/* check CGW_TYPE_CAN_CAN specific attributes */
struct can_can_gw *ccgw = (struct can_can_gw *)gwtypeattr;
memset(ccgw, 0, sizeof(*ccgw));
/* check for can_filter in attributes */
@ -862,12 +1015,10 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
return err;
if (mod.uid) {
ASSERT_RTNL();
/* check for updating an existing job with identical uid */
hlist_for_each_entry(gwj, &net->can.cgw_list, list) {
if (gwj->mod.uid != mod.uid)
continue;
@ -988,7 +1139,6 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
/* remove only the first matching entry */
hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
if (gwj->flags != r->flags)
continue;

View file

@ -1,6 +1,5 @@
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
/*
* raw.c - Raw sockets for protocol family CAN
/* raw.c - Raw sockets for protocol family CAN
*
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
@ -65,8 +64,7 @@ MODULE_ALIAS("can-proto-1");
#define MASK_ALL 0
/*
* A raw socket has a list of can_filters attached to it, each receiving
/* A raw socket has a list of can_filters attached to it, each receiving
* the CAN frames matching that filter. If the filter list is empty,
* no CAN frames will be received by the socket. The default after
* opening the socket, is to have one filter which receives all frames.
@ -97,8 +95,7 @@ struct raw_sock {
struct uniqframe __percpu *uniq;
};
/*
* Return pointer to store the extra msg flags for raw_recvmsg().
/* Return pointer to store the extra msg flags for raw_recvmsg().
* We use the space of one unsigned int beyond the 'struct sockaddr_can'
* in skb->cb.
*/
@ -157,8 +154,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
if (!skb)
return;
/*
* Put the datagram to the queue so that raw_recvmsg() can
/* Put the datagram to the queue so that raw_recvmsg() can
* get it from there. We need to pass the interface index to
* raw_recvmsg(). We pass a whole struct sockaddr_can in skb->cb
* containing the interface index.
@ -284,7 +280,6 @@ static int raw_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
switch (msg) {
case NETDEV_UNREGISTER:
lock_sock(sk);
/* remove current filters & unregister */
@ -370,8 +365,9 @@ static int raw_release(struct socket *sock)
raw_disable_allfilters(dev_net(dev), dev, sk);
dev_put(dev);
}
} else
} else {
raw_disable_allfilters(sock_net(sk), NULL, sk);
}
}
if (ro->count > 1)
@ -451,8 +447,9 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
dev, sk);
dev_put(dev);
}
} else
} else {
raw_disable_allfilters(sock_net(sk), NULL, sk);
}
}
ro->ifindex = ifindex;
ro->bound = 1;
@ -503,7 +500,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
return -EINVAL;
switch (optname) {
case CAN_RAW_FILTER:
if (optlen % sizeof(struct can_filter) != 0)
return -EINVAL;
@ -666,17 +662,18 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
return -EINVAL;
switch (optname) {
case CAN_RAW_FILTER:
lock_sock(sk);
if (ro->count > 0) {
int fsize = ro->count * sizeof(struct can_filter);
if (len > fsize)
len = fsize;
if (copy_to_user(optval, ro->filter, len))
err = -EFAULT;
} else
} else {
len = 0;
}
release_sock(sk);
if (!err)
@ -743,8 +740,9 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
return -EINVAL;
ifindex = addr->can_ifindex;
} else
} else {
ifindex = ro->ifindex;
}
dev = dev_get_by_index(sock_net(sk), ifindex);
if (!dev)
@ -837,8 +835,8 @@ static int raw_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
return size;
}
int raw_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd,
unsigned long arg)
static int raw_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
/* no ioctls for socket layer -> hand it down to NIC layer */
return -ENOIOCTLCMD;
@ -887,7 +885,7 @@ static __init int raw_module_init(void)
err = can_proto_register(&raw_can_proto);
if (err < 0)
printk(KERN_ERR "can: registration of raw protocol failed\n");
pr_err("can: registration of raw protocol failed\n");
return err;
}