Commit 18148f09 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-4.13-20170404' of...

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

Marc Kleine-Budde says:

====================
pull-request: can-next 2017-03-03

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

There are two patches by Yegor Yefremov which convert the ti_hecc
driver into a DT only driver, as there is no in-tree user of the old
platform driver interface anymore. The next patch by Mario Kicherer
adds network namespace support to the can subsystem. The last two
patches by Akshay Bhat add support for the holt_hi311x SPI CAN driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents af0e5461 57e83fb9
* Holt HI-311X stand-alone CAN controller device tree bindings
Required properties:
- compatible: Should be one of the following:
- "holt,hi3110" for HI-3110
- reg: SPI chip select.
- clocks: The clock feeding the CAN controller.
- interrupt-parent: The parent interrupt controller.
- interrupts: Should contain IRQ line for the CAN controller.
Optional properties:
- vdd-supply: Regulator that powers the CAN controller.
- xceiver-supply: Regulator that powers the CAN transceiver.
Example:
can0: can@1 {
compatible = "holt,hi3110";
reg = <1>;
clocks = <&clk32m>;
interrupt-parent = <&gpio4>;
interrupts = <13 IRQ_TYPE_EDGE_RISING>;
vdd-supply = <&reg5v0>;
xceiver-supply = <&reg5v0>;
};
Texas Instruments High End CAN Controller (HECC)
================================================
This file provides information, what the device node
for the hecc interface contains.
Required properties:
- compatible: "ti,am3517-hecc"
- reg: addresses and lengths of the register spaces for 'hecc', 'hecc-ram'
and 'mbx'
- reg-names :"hecc", "hecc-ram", "mbx"
- interrupts: interrupt mapping for the hecc interrupts sources
- clocks: clock phandles (see clock bindings for details)
Optional properties:
- ti,use-hecc1int: if provided configures HECC to produce all interrupts
on HECC1INT interrupt line. By default HECC0INT interrupt
line will be used.
- xceiver-supply: regulator that powers the CAN transceiver
Example:
For am3517evm board:
hecc: can@5c050000 {
compatible = "ti,am3517-hecc";
reg = <0x5c050000 0x80>,
<0x5c053000 0x180>,
<0x5c052000 0x200>;
reg-names = "hecc", "hecc-ram", "mbx";
interrupts = <24>;
clocks = <&hecc_ck>;
};
menu "CAN SPI interfaces"
depends on SPI
config CAN_HI311X
tristate "Holt HI311x SPI CAN controllers"
depends on CAN_DEV && SPI && HAS_DMA
---help---
Driver for the Holt HI311x SPI CAN controllers.
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
depends on HAS_DMA
......
......@@ -3,4 +3,5 @@
#
obj-$(CONFIG_CAN_HI311X) += hi311x.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
This diff is collapsed.
......@@ -17,25 +17,6 @@
*
*/
/*
* Your platform definitions should specify module ram offsets and interrupt
* number to use as follows:
*
* static struct ti_hecc_platform_data am3517_evm_hecc_pdata = {
* .scc_hecc_offset = 0,
* .scc_ram_offset = 0x3000,
* .hecc_ram_offset = 0x3000,
* .mbx_offset = 0x2000,
* .int_line = 0,
* .revision = 1,
* .transceiver_switch = hecc_phy_control,
* };
*
* Please see include/linux/can/platform/ti_hecc.h for description of
* above fields.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
......@@ -46,11 +27,13 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/can/platform/ti_hecc.h>
#define DRV_NAME "ti_hecc"
#define HECC_MODULE_VERSION "0.7"
......@@ -214,15 +197,14 @@ struct ti_hecc_priv {
struct net_device *ndev;
struct clk *clk;
void __iomem *base;
u32 scc_ram_offset;
u32 hecc_ram_offset;
u32 mbx_offset;
u32 int_line;
void __iomem *hecc_ram;
void __iomem *mbx;
bool use_hecc1int;
spinlock_t mbx_lock; /* CANME register needs protection */
u32 tx_head;
u32 tx_tail;
u32 rx_next;
void (*transceiver_switch)(int);
struct regulator *reg_xceiver;
};
static inline int get_tx_head_mb(struct ti_hecc_priv *priv)
......@@ -242,20 +224,18 @@ static inline int get_tx_head_prio(struct ti_hecc_priv *priv)
static inline void hecc_write_lam(struct ti_hecc_priv *priv, u32 mbxno, u32 val)
{
__raw_writel(val, priv->base + priv->hecc_ram_offset + mbxno * 4);
__raw_writel(val, priv->hecc_ram + mbxno * 4);
}
static inline void hecc_write_mbx(struct ti_hecc_priv *priv, u32 mbxno,
u32 reg, u32 val)
{
__raw_writel(val, priv->base + priv->mbx_offset + mbxno * 0x10 +
reg);
__raw_writel(val, priv->mbx + mbxno * 0x10 + reg);
}
static inline u32 hecc_read_mbx(struct ti_hecc_priv *priv, u32 mbxno, u32 reg)
{
return __raw_readl(priv->base + priv->mbx_offset + mbxno * 0x10 +
reg);
return __raw_readl(priv->mbx + mbxno * 0x10 + reg);
}
static inline void hecc_write(struct ti_hecc_priv *priv, u32 reg, u32 val)
......@@ -311,11 +291,16 @@ static int ti_hecc_set_btc(struct ti_hecc_priv *priv)
return 0;
}
static void ti_hecc_transceiver_switch(const struct ti_hecc_priv *priv,
int on)
static int ti_hecc_transceiver_switch(const struct ti_hecc_priv *priv,
int on)
{
if (priv->transceiver_switch)
priv->transceiver_switch(on);
if (!priv->reg_xceiver)
return 0;
if (on)
return regulator_enable(priv->reg_xceiver);
else
return regulator_disable(priv->reg_xceiver);
}
static void ti_hecc_reset(struct net_device *ndev)
......@@ -409,7 +394,7 @@ static void ti_hecc_start(struct net_device *ndev)
/* Prevent message over-write & Enable interrupts */
hecc_write(priv, HECC_CANOPC, HECC_SET_REG);
if (priv->int_line) {
if (priv->use_hecc1int) {
hecc_write(priv, HECC_CANMIL, HECC_SET_REG);
hecc_write(priv, HECC_CANGIM, HECC_CANGIM_DEF_MASK |
HECC_CANGIM_I1EN | HECC_CANGIM_SIL);
......@@ -760,7 +745,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
unsigned long ack, flags;
int_status = hecc_read(priv,
(priv->int_line) ? HECC_CANGIF1 : HECC_CANGIF0);
(priv->use_hecc1int) ? HECC_CANGIF1 : HECC_CANGIF0);
if (!int_status)
return IRQ_NONE;
......@@ -806,7 +791,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
}
/* clear all interrupt conditions - read back to avoid spurious ints */
if (priv->int_line) {
if (priv->use_hecc1int) {
hecc_write(priv, HECC_CANGIF1, HECC_SET_REG);
int_status = hecc_read(priv, HECC_CANGIF1);
} else {
......@@ -872,58 +857,87 @@ static const struct net_device_ops ti_hecc_netdev_ops = {
.ndo_change_mtu = can_change_mtu,
};
static const struct of_device_id ti_hecc_dt_ids[] = {
{
.compatible = "ti,am3517-hecc",
},
{ }
};
MODULE_DEVICE_TABLE(of, ti_hecc_dt_ids);
static int ti_hecc_probe(struct platform_device *pdev)
{
struct net_device *ndev = (struct net_device *)0;
struct ti_hecc_priv *priv;
struct ti_hecc_platform_data *pdata;
struct resource *mem, *irq;
void __iomem *addr;
struct device_node *np = pdev->dev.of_node;
struct resource *res, *irq;
struct regulator *reg_xceiver;
int err = -ENODEV;
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "No platform data\n");
goto probe_exit;
if (!IS_ENABLED(CONFIG_OF) || !np)
return -EINVAL;
reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
return -EPROBE_DEFER;
else if (IS_ERR(reg_xceiver))
reg_xceiver = NULL;
ndev = alloc_candev(sizeof(struct ti_hecc_priv), HECC_MAX_TX_MBOX);
if (!ndev) {
dev_err(&pdev->dev, "alloc_candev failed\n");
return -ENOMEM;
}
priv = netdev_priv(ndev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "No mem resources\n");
goto probe_exit;
/* handle hecc memory */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hecc");
if (!res) {
dev_err(&pdev->dev, "can't get IORESOURCE_MEM hecc\n");
return -EINVAL;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "No irq resource\n");
goto probe_exit;
priv->base = devm_ioremap_resource(&pdev->dev, res);
if (!priv->base) {
dev_err(&pdev->dev, "hecc ioremap failed\n");
return -ENOMEM;
}
if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
dev_err(&pdev->dev, "HECC region already claimed\n");
err = -EBUSY;
goto probe_exit;
/* handle hecc-ram memory */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hecc-ram");
if (!res) {
dev_err(&pdev->dev, "can't get IORESOURCE_MEM hecc-ram\n");
return -EINVAL;
}
addr = ioremap(mem->start, resource_size(mem));
if (!addr) {
dev_err(&pdev->dev, "ioremap failed\n");
err = -ENOMEM;
goto probe_exit_free_region;
priv->hecc_ram = devm_ioremap_resource(&pdev->dev, res);
if (!priv->hecc_ram) {
dev_err(&pdev->dev, "hecc-ram ioremap failed\n");
return -ENOMEM;
}
ndev = alloc_candev(sizeof(struct ti_hecc_priv), HECC_MAX_TX_MBOX);
if (!ndev) {
dev_err(&pdev->dev, "alloc_candev failed\n");
err = -ENOMEM;
goto probe_exit_iounmap;
/* handle mbx memory */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mbx");
if (!res) {
dev_err(&pdev->dev, "can't get IORESOURCE_MEM mbx\n");
return -EINVAL;
}
priv->mbx = devm_ioremap_resource(&pdev->dev, res);
if (!priv->mbx) {
dev_err(&pdev->dev, "mbx ioremap failed\n");
return -ENOMEM;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "No irq resource\n");
goto probe_exit;
}
priv = netdev_priv(ndev);
priv->ndev = ndev;
priv->base = addr;
priv->scc_ram_offset = pdata->scc_ram_offset;
priv->hecc_ram_offset = pdata->hecc_ram_offset;
priv->mbx_offset = pdata->mbx_offset;
priv->int_line = pdata->int_line;
priv->transceiver_switch = pdata->transceiver_switch;
priv->reg_xceiver = reg_xceiver;
priv->use_hecc1int = of_property_read_bool(np, "ti,use-hecc1int");
priv->can.bittiming_const = &ti_hecc_bittiming_const;
priv->can.do_set_mode = ti_hecc_do_set_mode;
......@@ -971,32 +985,23 @@ static int ti_hecc_probe(struct platform_device *pdev)
clk_put(priv->clk);
probe_exit_candev:
free_candev(ndev);
probe_exit_iounmap:
iounmap(addr);
probe_exit_free_region:
release_mem_region(mem->start, resource_size(mem));
probe_exit:
return err;
}
static int ti_hecc_remove(struct platform_device *pdev)
{
struct resource *res;
struct net_device *ndev = platform_get_drvdata(pdev);
struct ti_hecc_priv *priv = netdev_priv(ndev);
unregister_candev(ndev);
clk_disable_unprepare(priv->clk);
clk_put(priv->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iounmap(priv->base);
release_mem_region(res->start, resource_size(res));
free_candev(ndev);
return 0;
}
#ifdef CONFIG_PM
static int ti_hecc_suspend(struct platform_device *pdev, pm_message_t state)
{
......@@ -1045,6 +1050,7 @@ static int ti_hecc_resume(struct platform_device *pdev)
static struct platform_driver ti_hecc_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = ti_hecc_dt_ids,
},
.probe = ti_hecc_probe,
.remove = ti_hecc_remove,
......
......@@ -45,12 +45,13 @@ struct can_proto {
extern int can_proto_register(const struct can_proto *cp);
extern void can_proto_unregister(const struct can_proto *cp);
int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
int can_rx_register(struct net *net, struct net_device *dev,
canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *),
void *data, char *ident, struct sock *sk);
extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
canid_t mask,
extern void can_rx_unregister(struct net *net, struct net_device *dev,
canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *),
void *data);
......
#ifndef _CAN_PLATFORM_TI_HECC_H
#define _CAN_PLATFORM_TI_HECC_H
/*
* TI HECC (High End CAN Controller) driver platform header
*
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed as is WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/**
* struct hecc_platform_data - HECC Platform Data
*
* @scc_hecc_offset: mostly 0 - should really never change
* @scc_ram_offset: SCC RAM offset
* @hecc_ram_offset: HECC RAM offset
* @mbx_offset: Mailbox RAM offset
* @int_line: Interrupt line to use - 0 or 1
* @version: version for future use
* @transceiver_switch: platform specific callback fn for transceiver control
*
* Platform data structure to get all platform specific settings.
* this structure also accounts the fact that the IP may have different
* RAM and mailbox offsets for different SOC's
*/
struct ti_hecc_platform_data {
u32 scc_hecc_offset;
u32 scc_ram_offset;
u32 hecc_ram_offset;
u32 mbx_offset;
u32 int_line;
u32 version;
void (*transceiver_switch) (int);
};
#endif /* !_CAN_PLATFORM_TI_HECC_H */
......@@ -27,6 +27,7 @@
#include <net/netns/nftables.h>
#include <net/netns/xfrm.h>
#include <net/netns/mpls.h>
#include <net/netns/can.h>
#include <linux/ns_common.h>
#include <linux/idr.h>
#include <linux/skbuff.h>
......@@ -140,6 +141,9 @@ struct net {
#endif
#if IS_ENABLED(CONFIG_MPLS)
struct netns_mpls mpls;
#endif
#if IS_ENABLED(CONFIG_CAN)
struct netns_can can;
#endif
struct sock *diag_nlsk;
atomic_t fnhe_genid;
......
/*
* can in net namespaces
*/
#ifndef __NETNS_CAN_H__
#define __NETNS_CAN_H__
#include <linux/spinlock.h>
struct dev_rcv_lists;
struct netns_can {
#if IS_ENABLED(CONFIG_PROC_FS)
struct proc_dir_entry *proc_dir;
struct proc_dir_entry *pde_version;
struct proc_dir_entry *pde_stats;
struct proc_dir_entry *pde_reset_stats;
struct proc_dir_entry *pde_rcvlist_all;
struct proc_dir_entry *pde_rcvlist_fil;
struct proc_dir_entry *pde_rcvlist_inv;
struct proc_dir_entry *pde_rcvlist_sff;
struct proc_dir_entry *pde_rcvlist_eff;
struct proc_dir_entry *pde_rcvlist_err;
#endif
/* receive filters subscribed for 'all' CAN devices */
struct dev_rcv_lists *can_rx_alldev_list;
spinlock_t can_rcvlists_lock;
};
#endif /* __NETNS_CAN_H__ */
......@@ -75,9 +75,7 @@ static int stats_timer __read_mostly = 1;
module_param(stats_timer, int, S_IRUGO);
MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)");
/* receive filters subscribed for 'all' CAN devices */
struct dev_rcv_lists can_rx_alldev_list;
static DEFINE_SPINLOCK(can_rcvlists_lock);
static int can_net_id;
static struct kmem_cache *rcv_cache __read_mostly;
......@@ -145,9 +143,6 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
if (protocol < 0 || protocol >= CAN_NPROTO)
return -EINVAL;
if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
cp = can_get_proto(protocol);
#ifdef CONFIG_MODULES
......@@ -331,10 +326,11 @@ EXPORT_SYMBOL(can_send);
* af_can rx path
*/
static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
static struct dev_rcv_lists *find_dev_rcv_lists(struct net *net,
struct net_device *dev)
{
if (!dev)
return &can_rx_alldev_list;
return net->can.can_rx_alldev_list;
else
return (struct dev_rcv_lists *)dev->ml_priv;
}
......@@ -467,9 +463,9 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
* -ENOMEM on missing cache mem to create subscription entry
* -ENODEV unknown device
*/
int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *), void *data,
char *ident, struct sock *sk)
int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
canid_t mask, void (*func)(struct sk_buff *, void *),
void *data, char *ident, struct sock *sk)
{
struct receiver *r;
struct hlist_head *rl;
......@@ -481,13 +477,16 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
if (dev && dev->type != ARPHRD_CAN)
return -ENODEV;
if (dev && !net_eq(net, dev_net(dev)))
return -ENODEV;
r = kmem_cache_alloc(rcv_cache, GFP_KERNEL);
if (!r)
return -ENOMEM;
spin_lock(&can_rcvlists_lock);
spin_lock(&net->can.can_rcvlists_lock);
d = find_dev_rcv_lists(dev);
d = find_dev_rcv_lists(net, dev);
if (d) {
rl = find_rcv_list(&can_id, &mask, d);
......@@ -510,7 +509,7 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
err = -ENODEV;
}
spin_unlock(&can_rcvlists_lock);
spin_unlock(&net->can.can_rcvlists_lock);
return err;
}
......@@ -540,8 +539,9 @@ static void can_rx_delete_receiver(struct rcu_head *rp)
* Description:
* Removes subscription entry depending on given (subscription) values.
*/
void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *), void *data)
void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
canid_t mask, void (*func)(struct sk_buff *, void *),
void *data)
{
struct receiver *r = NULL;
struct hlist_head *rl;
......@@ -550,9 +550,12 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
if (dev && dev->type != ARPHRD_CAN)
return;
spin_lock(&can_rcvlists_lock);
if (dev && !net_eq(net, dev_net(dev)))
return;
d = find_dev_rcv_lists(dev);
spin_lock(&net->can.can_rcvlists_lock);
d = find_dev_rcv_lists(net, dev);
if (!d) {
pr_err("BUG: receive list not found for "
"dev %s, id %03X, mask %03X\n",
......@@ -598,7 +601,7 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
}
out:
spin_unlock(&can_rcvlists_lock);
spin_unlock(&net->can.can_rcvlists_lock);
/* schedule the receiver item for deletion */
if (r) {
......@@ -696,10 +699,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
rcu_read_lock();
/* deliver the packet to sockets listening on all devices */
matches = can_rcv_filter(&can_rx_alldev_list, skb);
matches = can_rcv_filter(dev_net(dev)->can.can_rx_alldev_list, skb);
/* find receive list for this device */
d = find_dev_rcv_lists(dev);
d = find_dev_rcv_lists(dev_net(dev), dev);
if (d)
matches += can_rcv_filter(d, skb);
......@@ -719,9 +722,6 @@ static int can_rcv(struct sk_buff *skb, struct net_device *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,
......@@ -743,9 +743,6 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *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,
......@@ -835,9 +832,6 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct dev_rcv_lists *d;
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
......@@ -855,7 +849,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
break;
case NETDEV_UNREGISTER:
spin_lock(&can_rcvlists_lock);
spin_lock(&dev_net(dev)->can.can_rcvlists_lock);
d = dev->ml_priv;
if (d) {
......@@ -869,7 +863,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
pr_err("can: notifier: receive list not found for dev "
"%s\n", dev->name);
spin_unlock(&can_rcvlists_lock);
spin_unlock(&dev_net(dev)->can.can_rcvlists_lock);
break;
}
......@@ -877,6 +871,40 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
return NOTIFY_DONE;
}
static int can_pernet_init(struct net *net)
{
net->can.can_rcvlists_lock =
__SPIN_LOCK_UNLOCKED(net->can.can_rcvlists_lock);
net->can.can_rx_alldev_list =
kzalloc(sizeof(struct dev_rcv_lists), GFP_KERNEL);
if (IS_ENABLED(CONFIG_PROC_FS))
can_init_proc(net);
return 0;
}
static void can_pernet_exit(struct net *net)
{
struct net_device *dev;
if (IS_ENABLED(CONFIG_PROC_FS))
can_remove_proc(net);
/* remove created dev_rcv_lists from still registered CAN devices */
rcu_read_lock();
for_each_netdev_rcu(net, dev) {
if (dev->type == ARPHRD_CAN && dev->ml_priv) {
struct dev_rcv_lists *d = dev->ml_priv;
BUG_ON(d->entries);
kfree(d);
dev->ml_priv = NULL;
}
}
rcu_read_unlock();
}
/*
* af_can module init/exit functions
*/
......@@ -902,6 +930,13 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
.notifier_call = can_notifier,
};
static struct pernet_operations can_pernet_ops __read_mostly = {
.init = can_pernet_init,
.exit = can_pernet_exit,
.id = &can_net_id,
.size = 0,
};
static __init int can_init(void)
{
/* check for correct padding to be able to use the structs similarly */
......@@ -912,8 +947,6 @@ static __init int can_init(void)
pr_info("can: controller area network core (" CAN_VERSION_STRING ")\n");
memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver),
0, 0, NULL);
if (!rcv_cache)
......@@ -925,9 +958,10 @@ static __init int can_init(void)
setup_timer(&can_stattimer, can_stat_update, 0);
mod_timer(&can_stattimer, round_jiffies(jiffies + HZ));
}
can_init_proc();
}
register_pernet_subsys(&can_pernet_ops);
/* protocol register */
sock_register(&can_family_ops);
register_netdevice_notifier(&can_netdev_notifier);
......@@ -939,13 +973,9 @@ static __init int can_init(void)
static __exit void can_exit(void)
{
struct net_device *dev;
if (IS_ENABLED(CONFIG_PROC_FS)) {
if (stats_timer)
del_timer_sync(&can_stattimer);
can_remove_proc();
}
/* protocol unregister */
......@@ -954,19 +984,7 @@ static __exit void can_exit(void)
unregister_netdevice_notifier(&can_netdev_notifier);
sock_unregister(PF_CAN);
/* remove created dev_rcv_lists from still registered CAN devices */
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
if (dev->type == ARPHRD_CAN && dev->ml_priv) {
struct dev_rcv_lists *d = dev->ml_priv;
BUG_ON(d->entries);
kfree(d);
dev->ml_priv = NULL;
}
}
rcu_read_unlock();
unregister_pernet_subsys(&can_pernet_ops);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
......
......@@ -114,8 +114,8 @@ struct s_pstats {
extern struct dev_rcv_lists can_rx_alldev_list;
/* function prototypes for the CAN networklayer procfs (proc.c) */
void can_init_proc(void);
void can_remove_proc(void);
void can_init_proc(struct net *net);
void can_remove_proc(struct net *net);
void can_stat_update(unsigned long data);
/* structures and variables from af_can.c needed in proc.c for reading */
......
......@@ -764,8 +764,8 @@ static void bcm_remove_op(struct bcm_op *op)
static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
{
if (op->rx_reg_dev == dev) {
can_rx_unregister(dev, op->can_id, REGMASK(op->can_id),
bcm_rx_handler, op);
can_rx_unregister(&init_net, dev, op->can_id,
REGMASK(op->can_id), bcm_rx_handler, op);
/* mark as removed subscription */
op->rx_reg_dev = NULL;
......@@ -808,7 +808,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
}
}
} else
can_rx_unregister(NULL, op->can_id,
can_rx_unregister(&init_net, NULL, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op);
......@@ -1222,7 +1222,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
dev = dev_get_by_index(&init_net, ifindex);
if (dev) {
err = can_rx_register(dev, op->can_id,
err = can_rx_register(&init_net, dev,
op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op,
"bcm", sk);
......@@ -1232,7 +1233,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
}
} else
err = can_rx_register(NULL, op->can_id,
err = can_rx_register(&init_net, NULL, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op, "bcm", sk);
if (err) {
......@@ -1528,7 +1529,7 @@ static int bcm_release(struct socket *sock)
}
}
} else
can_rx_unregister(NULL, op->can_id,
can_rx_unregister(&init_net, NULL, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op);
......
......@@ -440,14 +440,14 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
static inline int cgw_register_filter(struct cgw_job *gwj)
{
return can_rx_register(gwj->src.dev, gwj->ccgw.filter.can_id,
return can_rx_register(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id,
gwj->ccgw.filter.can_mask, can_can_gw_rcv,
gwj, "gw", NULL);
}
static inline void cgw_unregister_filter(struct cgw_job *gwj)
{
can_rx_unregister(gwj->src.dev, gwj->ccgw.filter.can_id,
can_rx_unregister(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id,
gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj);
}
......
......@@ -62,17 +62,6 @@
#define CAN_PROC_RCVLIST_EFF "rcvlist_eff"
#define CAN_PROC_RCVLIST_ERR "rcvlist_err"
static struct proc_dir_entry *can_dir;
static struct proc_dir_entry *pde_version;
static struct proc_dir_entry *pde_stats;
static struct proc_dir_entry *pde_reset_stats;
static struct proc_dir_entry *pde_rcvlist_all;
static struct proc_dir_entry *pde_rcvlist_fil;
static struct proc_dir_entry *pde_rcvlist_inv;
static struct proc_dir_entry *pde_rcvlist_sff;
static struct proc_dir_entry *pde_rcvlist_eff;
static struct proc_dir_entry *pde_rcvlist_err;
static int user_reset;
static const char rx_list_name[][8] = {
......@@ -351,20 +340,21 @@ static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx,
static int can_rcvlist_proc_show(struct seq_file *m, void *v)
{
/* double cast to prevent GCC warning */
int idx = (int)(long)m->private;
int idx = (int)(long)PDE_DATA(m->file->f_inode);
struct net_device *dev;
struct dev_rcv_lists *d;
struct net *net = m->private;
seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]);
rcu_read_lock();
/* receive list for 'all' CAN devices (dev == NULL) */
d = &can_rx_alldev_list;
d = net->can.can_rx_alldev_list;
can_rcvlist_proc_show_one(m, idx, NULL, d);
/* receive list for registered CAN devices */
for_each_netdev_rcu(&init_net, dev) {
for_each_netdev_rcu(net, dev) {
if (dev->type == ARPHRD_CAN && dev->ml_priv)
can_rcvlist_proc_show_one(m, idx, dev, dev->ml_priv);
}
......@@ -377,7 +367,7 @@ static int can_rcvlist_proc_show(struct seq_file *m, void *v)
static int can_rcvlist_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, can_rcvlist_proc_show, PDE_DATA(inode));
return single_open_net(inode, file, can_rcvlist_proc_show);
}
static const struct file_operations can_rcvlist_proc_fops = {
......@@ -417,6 +407,7 @@ static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
{
struct net_device *dev;
struct dev_rcv_lists *d;
struct net *net = m->private;
/* RX_SFF */
seq_puts(m, "\nreceive list 'rx_sff':\n");
......@@ -424,11 +415,11 @@ static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
rcu_read_lock();
/* sff receive list for 'all' CAN devices (dev == NULL) */
d = &can_rx_alldev_list;
d = net->can.can_rx_alldev_list;
can_rcvlist_proc_show_array(m, NULL, d->rx_sff, ARRAY_SIZE(d->rx_sff));
/* sff receive list for registered CAN devices */
for_each_netdev_rcu(&init_net, dev) {
for_each_netdev_rcu(net, dev) {
if (dev->type == ARPHRD_CAN && dev->ml_priv) {
d = dev->ml_priv;
can_rcvlist_proc_show_array(m, dev, d->rx_sff,
......@@ -444,7 +435,7 @@ static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
static int can_rcvlist_sff_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, can_rcvlist_sff_proc_show, NULL);
return single_open_net(inode, file, can_rcvlist_sff_proc_show);
}
static const struct file_operations can_rcvlist_sff_proc_fops = {
......@@ -460,6 +451,7 @@ static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
{
struct net_device *dev;
struct dev_rcv_lists *d;
struct net *net = m->private;
/* RX_EFF */
seq_puts(m, "\nreceive list 'rx_eff':\n");
......@@ -467,11 +459,11 @@ static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
rcu_read_lock();
/* eff receive list for 'all' CAN devices (dev == NULL) */
d = &can_rx_alldev_list;
d = net->can.can_rx_alldev_list;
can_rcvlist_proc_show_array(m, NULL, d->rx_eff, ARRAY_SIZE(d->rx_eff));
/* eff receive list for registered CAN devices */
for_each_netdev_rcu(&init_net, dev) {
for_each_netdev_rcu(net, dev) {
if (dev->type == ARPHRD_CAN && dev->ml_priv) {
d = dev->ml_priv;
can_rcvlist_proc_show_array(m, dev, d->rx_eff,
......@@ -487,7 +479,7 @@ static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
static int can_rcvlist_eff_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, can_rcvlist_eff_proc_show, NULL);
return single_open_net(inode, file, can_rcvlist_eff_proc_show);
}
static const struct file_operations can_rcvlist_eff_proc_fops = {
......@@ -498,82 +490,86 @@ static const struct file_operations can_rcvlist_eff_proc_fops = {
.release = single_release,
};
/*
* proc utility functions
*/
static void can_remove_proc_readentry(const char *name)
{
if (can_dir)
remove_proc_entry(name, can_dir);
}
/*
* can_init_proc - create main CAN proc directory and procfs entries
*/
void can_init_proc(void)
void can_init_proc(struct net *net)
{
/* create /proc/net/can directory */
can_dir = proc_mkdir("can", init_net.proc_net);
net->can.proc_dir = proc_net_mkdir(net, "can", net->proc_net);
if (!can_dir) {
pr_info("can: failed to create /proc/net/can.\n");
if (!net->can.proc_dir) {
printk(KERN_INFO "can: failed to create /proc/net/can . "
"CONFIG_PROC_FS missing?\n");
return;
}
/* own procfs entries from the AF_CAN core */
pde_version = proc_create(CAN_PROC_VERSION, 0644, can_dir,
&can_version_proc_fops);
pde_stats = proc_create(CAN_PROC_STATS, 0644, can_dir,
&can_stats_proc_fops);
pde_reset_stats = proc_create(CAN_PROC_RESET_STATS, 0644, can_dir,
&can_reset_stats_proc_fops);
pde_rcvlist_err = proc_create_data(CAN_PROC_RCVLIST_ERR, 0644, can_dir,
&can_rcvlist_proc_fops, (void *)RX_ERR);
pde_rcvlist_all = proc_create_data(CAN_PROC_RCVLIST_ALL, 0644, can_dir,
&can_rcvlist_proc_fops, (void *)RX_ALL);
pde_rcvlist_fil = proc_create_data(CAN_PROC_RCVLIST_FIL, 0644, can_dir,
&can_rcvlist_proc_fops, (void *)RX_FIL);
pde_rcvlist_inv = proc_create_data(CAN_PROC_RCVLIST_INV, 0644, can_dir,
&can_rcvlist_proc_fops, (void *)RX_INV);
pde_rcvlist_eff = proc_create(CAN_PROC_RCVLIST_EFF, 0644, can_dir,
&can_rcvlist_eff_proc_fops);
pde_rcvlist_sff = proc_create(CAN_PROC_RCVLIST_SFF, 0644, can_dir,
&can_rcvlist_sff_proc_fops);
net->can.pde_version = proc_create(CAN_PROC_VERSION, 0644,
net->can.proc_dir,
&can_version_proc_fops);
net->can.pde_stats = proc_create(CAN_PROC_STATS, 0644,
net->can.proc_dir,
&can_stats_proc_fops);
net->can.pde_reset_stats = proc_create(CAN_PROC_RESET_STATS, 0644,
net->can.proc_dir,
&can_reset_stats_proc_fops);
net->can.pde_rcvlist_err = proc_create_data(CAN_PROC_RCVLIST_ERR, 0644,
net->can.proc_dir,
&can_rcvlist_proc_fops,
(void *)RX_ERR);
net->can.pde_rcvlist_all = proc_create_data(CAN_PROC_RCVLIST_ALL, 0644,
net->can.proc_dir,
&can_rcvlist_proc_fops,
(void *)RX_ALL);
net->can.pde_rcvlist_fil = proc_create_data(CAN_PROC_RCVLIST_FIL, 0644,
net->can.proc_dir,
&can_rcvlist_proc_fops,
(void *)RX_FIL);
net->can.pde_rcvlist_inv = proc_create_data(CAN_PROC_RCVLIST_INV, 0644,
net->can.proc_dir,
&can_rcvlist_proc_fops,
(void *)RX_INV);
net->can.pde_rcvlist_eff = proc_create(CAN_PROC_RCVLIST_EFF, 0644,
net->can.proc_dir,
&can_rcvlist_eff_proc_fops);
net->can.pde_rcvlist_sff = proc_create(CAN_PROC_RCVLIST_SFF, 0644,
net->can.proc_dir,
&can_rcvlist_sff_proc_fops);
}
/*
* can_remove_proc - remove procfs entries and main CAN proc directory
*/
void can_remove_proc(void)
void can_remove_proc(struct net *net)
{
if (pde_version)
can_remove_proc_readentry(CAN_PROC_VERSION);
if (net->can.pde_version)
remove_proc_entry(CAN_PROC_VERSION, net->can.proc_dir);
if (pde_stats)
can_remove_proc_readentry(CAN_PROC_STATS);
if (net->can.pde_stats)
remove_proc_entry(CAN_PROC_STATS, net->can.proc_dir);
if (pde_reset_stats)
can_remove_proc_readentry(CAN_PROC_RESET_STATS);
if (net->can.pde_reset_stats)
remove_proc_entry(CAN_PROC_RESET_STATS, net->can.proc_dir);
if (pde_rcvlist_err)
can_remove_proc_readentry(CAN_PROC_RCVLIST_ERR);
if (net->can.pde_rcvlist_err)
remove_proc_entry(CAN_PROC_RCVLIST_ERR, net->can.proc_dir);
if (pde_rcvlist_all)
can_remove_proc_readentry(CAN_PROC_RCVLIST_ALL);
if (net->can.pde_rcvlist_all)
remove_proc_entry(CAN_PROC_RCVLIST_ALL, net->can.proc_dir);
if (pde_rcvlist_fil)
can_remove_proc_readentry(CAN_PROC_RCVLIST_FIL);
if (net->can.pde_rcvlist_fil)
remove_proc_entry(CAN_PROC_RCVLIST_FIL, net->can.proc_dir);
if (pde_rcvlist_inv)
can_remove_proc_readentry(CAN_PROC_RCVLIST_INV);
if (net->can.pde_rcvlist_inv)
remove_proc_entry(CAN_PROC_RCVLIST_INV, net->can.proc_dir);
if (pde_rcvlist_eff)
can_remove_proc_readentry(CAN_PROC_RCVLIST_EFF);
if (net->can.pde_rcvlist_eff)
remove_proc_entry(CAN_PROC_RCVLIST_EFF, net->can.proc_dir);
if (pde_rcvlist_sff)
can_remove_proc_readentry(CAN_PROC_RCVLIST_SFF);
if (net->can.pde_rcvlist_sff)
remove_proc_entry(CAN_PROC_RCVLIST_SFF, net->can.proc_dir);
if (can_dir)
remove_proc_entry("can", init_net.proc_net);
if (net->can.proc_dir)
remove_proc_entry("can", net->proc_net);
}
......@@ -181,20 +181,21 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
kfree_skb(skb);
}
static int raw_enable_filters(struct net_device *dev, struct sock *sk,
struct can_filter *filter, int count)
static int raw_enable_filters(struct net *net, struct net_device *dev,
struct sock *sk, struct can_filter *filter,
int count)
{
int err = 0;
int i;
for (i = 0; i < count; i++) {
err = can_rx_register(dev, filter[i].can_id,
err = can_rx_register(net, dev, filter[i].can_id,
filter[i].can_mask,
raw_rcv, sk, "raw", sk);
if (err) {
/* clean up successfully registered filters */
while (--i >= 0)
can_rx_unregister(dev, filter[i].can_id,
can_rx_unregister(net, dev, filter[i].can_id,
filter[i].can_mask,
raw_rcv, sk);
break;
......@@ -204,57 +205,62 @@ static int raw_enable_filters(struct net_device *dev, struct sock *sk,
return err;
}
static int raw_enable_errfilter(struct net_device *dev, struct sock *sk,
can_err_mask_t err_mask)
static int raw_enable_errfilter(struct net *net, struct net_device *dev,
struct sock *sk, can_err_mask_t err_mask)
{
int err = 0;
if (err_mask)
err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG,
err = can_rx_register(net, dev, 0, err_mask | CAN_ERR_FLAG,
raw_rcv, sk, "raw", sk);
return err;
}
static void raw_disable_filters(struct net_device *dev, struct sock *sk,
struct can_filter *filter, int count)
static void raw_disable_filters(struct net *net, struct net_device *dev,
struct sock *sk, struct can_filter *filter,
int count)
{
int i;
for (i = 0; i < count; i++)
can_rx_unregister(dev, filter[i].can_id, filter[i].can_mask,
raw_rcv, sk);
can_rx_unregister(net, dev, filter[i].can_id,
filter[i].can_mask, raw_rcv, sk);
}
static inline void raw_disable_errfilter(struct net_device *dev,
static inline void raw_disable_errfilter(struct net *net,
struct net_device *dev,
struct sock *sk,
can_err_mask_t err_mask)
{
if (err_mask)
can_rx_unregister(dev, 0, err_mask | CAN_ERR_FLAG,
can_rx_unregister(net, dev, 0, err_mask | CAN_ERR_FLAG,
raw_rcv, sk);
}
static inline void raw_disable_allfilters(struct net_device *dev,
static inline void raw_disable_allfilters(struct net *net,
struct net_device *dev,
struct sock *sk)
{
struct raw_sock *ro = raw_sk(sk);
raw_disable_filters(dev, sk, ro->filter, ro->count);
raw_disable_errfilter(dev, sk, ro->err_mask);
raw_disable_filters(net, dev, sk, ro->filter, ro->count);
raw_disable_errfilter(net, dev, sk, ro->err_mask);
}
static int raw_enable_allfilters(struct net_device *dev, struct sock *sk)
static int raw_enable_allfilters(struct net *net, struct net_device *dev,
struct sock *sk)
{
struct raw_sock *ro = raw_sk(sk);
int err;
err = raw_enable_filters(dev, sk, ro->filter, ro->count);
err = raw_enable_filters(net, dev, sk, ro->filter, ro->count);
if (!err) {
err = raw_enable_errfilter(dev, sk, ro->err_mask);
err = raw_enable_errfilter(net, dev, sk, ro->err_mask);
if (err)
raw_disable_filters(dev, sk, ro->filter, ro->count);
raw_disable_filters(net, dev, sk, ro->filter,
ro->count);
}
return err;
......@@ -267,7 +273,7 @@ static int raw_notifier(struct notifier_block *nb,
struct raw_sock *ro = container_of(nb, struct raw_sock, notifier);
struct sock *sk = &ro->sk;
if (!net_eq(dev_net(dev), &init_net))
if (!net_eq(dev_net(dev), sock_net(sk)))
return NOTIFY_DONE;
if (dev->type != ARPHRD_CAN)
......@@ -282,7 +288,7 @@ static int raw_notifier(struct notifier_block *nb,
lock_sock(sk);
/* remove current filters & unregister */
if (ro->bound)
raw_disable_allfilters(dev, sk);
raw_disable_allfilters(dev_net(dev), dev, sk);
if (ro->count > 1)
kfree(ro->filter);
......@@ -358,13 +364,13 @@ static int raw_release(struct socket *sock)
if (ro->ifindex) {
struct net_device *dev;
dev = dev_get_by_index(&init_net, ro->ifindex);
dev = dev_get_by_index(sock_net(sk), ro->ifindex);
if (dev) {
raw_disable_allfilters(dev, sk);
raw_disable_allfilters(dev_net(dev), dev, sk);
dev_put(dev);
}
} else
raw_disable_allfilters(NULL, sk);
raw_disable_allfilters(sock_net(sk), NULL, sk);
}
if (ro->count > 1)
......@@ -404,7 +410,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
if (addr->can_ifindex) {
struct net_device *dev;
dev = dev_get_by_index(&init_net, addr->can_ifindex);
dev = dev_get_by_index(sock_net(sk), addr->can_ifindex);
if (!dev) {
err = -ENODEV;
goto out;
......@@ -420,13 +426,13 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
ifindex = dev->ifindex;
/* filters set by default/setsockopt */
err = raw_enable_allfilters(dev, sk);
err = raw_enable_allfilters(sock_net(sk), dev, sk);
dev_put(dev);
} else {
ifindex = 0;
/* filters set by default/setsockopt */
err = raw_enable_allfilters(NULL, sk);
err = raw_enable_allfilters(sock_net(sk), NULL, sk);
}
if (!err) {
......@@ -435,13 +441,15 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
if (ro->ifindex) {
struct net_device *dev;
dev = dev_get_by_index(&init_net, ro->ifindex);
dev = dev_get_by_index(sock_net(sk),
ro->ifindex);
if (dev) {
raw_disable_allfilters(dev, sk);
raw_disable_allfilters(dev_net(dev),
dev, sk);
dev_put(dev);
}
} else
raw_disable_allfilters(NULL, sk);
raw_disable_allfilters(sock_net(sk), NULL, sk);
}
ro->ifindex = ifindex;
ro->bound = 1;
......@@ -517,15 +525,16 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
lock_sock(sk);
if (ro->bound && ro->ifindex)
dev = dev_get_by_index(&init_net, ro->ifindex);
dev = dev_get_by_index(sock_net(sk), ro->ifindex);
if (ro->bound) {
/* (try to) register the new filters */
if (count == 1)
err = raw_enable_filters(dev, sk, &sfilter, 1);
err = raw_enable_filters(sock_net(sk), dev, sk,
&sfilter, 1);
else
err = raw_enable_filters(dev, sk, filter,
count);
err = raw_enable_filters(sock_net(sk), dev, sk,
filter, count);
if (err) {
if (count > 1)
kfree(filter);
......@@ -533,7 +542,8 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
}
/* remove old filter registrations */
raw_disable_filters(dev, sk, ro->filter, ro->count);
raw_disable_filters(sock_net(sk), dev, sk, ro->filter,
ro->count);
}
/* remove old filter space */
......@@ -569,18 +579,20 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
lock_sock(sk);
if (ro->bound && ro->ifindex)
dev = dev_get_by_index(&init_net, ro->ifindex);
dev = dev_get_by_index(sock_net(sk), ro->ifindex);
/* remove current error mask */
if (ro->bound) {
/* (try to) register the new err_mask */
err = raw_enable_errfilter(dev, sk, err_mask);
err = raw_enable_errfilter(sock_net(sk), dev, sk,
err_mask);
if (err)
goto out_err;
/* remove old err_mask registration */
raw_disable_errfilter(dev, sk, ro->err_mask);
raw_disable_errfilter(sock_net(sk), dev, sk,
ro->err_mask);
}
/* link new err_mask to the socket */
......@@ -741,7 +753,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
return -EINVAL;
}
dev = dev_get_by_index(&init_net, ifindex);
dev = dev_get_by_index(sock_net(sk), ifindex);
if (!dev)
return -ENXIO;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment