mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-04 12:13:43 +00:00
linux-can-fixes-for-6.5-20230717
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEDs2BvajyNKlf9TJQvlAcSiqKBOgFAmS1gXMTHG1rbEBwZW5n dXRyb25peC5kZQAKCRC+UBxKKooE6LzRB/0bvAxT3Xm63DzSKtSwv4l0RimpzqCN T105KT82Y24/AUfVJfEHVUETSeOOR6xNTHYzijJq8kF+/9bSYEkfkVcq/gN5QSdd 7hdRFOQbTwfRUGHF5E6XFua/NcbjIrY9vZtttiI9scC7jLO8vz5wtdNFYUMSY1Bh 3hE079AHCtDxHX2wIM5dQN5P847QmJAykaErxRftJ+0dWpHbon4WyfT+6MAVCN5s 3VSwJ3p1fhKl5h3JmRYqSXeaJ6wV1vfGawj4HoyfENPWlMmTOuQ7uobrPuNrzE92 f1S21O+woe0eaypOkaJLeYg1X7ifDqyccT8sSNwSzys/9Ay6xmxQ9NNl =nSGE -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-6.5-20230717' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can Marc Kleine-Budde says: ==================== pull-request: can 2023-07-17 The 1st patch is by Ziyang Xuan and fixes a possible memory leak in the receiver handling in the CAN RAW protocol. YueHaibing contributes a use after free in bcm_proc_show() of the Broad Cast Manager (BCM) CAN protocol. The next 2 patches are by me and fix a possible null pointer dereference in the RX path of the gs_usb driver with activated hardware timestamps and the candlelight firmware. The last patch is by Fedor Ross, Marek Vasut and me and targets the mcp251xfd driver. The polling timeout of __mcp251xfd_chip_set_mode() is increased to fix bus joining on busy CAN buses and very low bit rate. * tag 'linux-can-fixes-for-6.5-20230717' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: mcp251xfd: __mcp251xfd_chip_set_mode(): increase poll timeout can: gs_usb: fix time stamp counter initialization can: gs_usb: gs_can_open(): improve error handling can: bcm: Fix UAF in bcm_proc_show() can: raw: fix receiver memory leak ==================== Link: https://lore.kernel.org/r/20230717180938.230816-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
936fd2c50b
@ -227,6 +227,8 @@ static int
|
||||
__mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv,
|
||||
const u8 mode_req, bool nowait)
|
||||
{
|
||||
const struct can_bittiming *bt = &priv->can.bittiming;
|
||||
unsigned long timeout_us = MCP251XFD_POLL_TIMEOUT_US;
|
||||
u32 con = 0, con_reqop, osc = 0;
|
||||
u8 mode;
|
||||
int err;
|
||||
@ -246,12 +248,16 @@ __mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv,
|
||||
if (mode_req == MCP251XFD_REG_CON_MODE_SLEEP || nowait)
|
||||
return 0;
|
||||
|
||||
if (bt->bitrate)
|
||||
timeout_us = max_t(unsigned long, timeout_us,
|
||||
MCP251XFD_FRAME_LEN_MAX_BITS * USEC_PER_SEC /
|
||||
bt->bitrate);
|
||||
|
||||
err = regmap_read_poll_timeout(priv->map_reg, MCP251XFD_REG_CON, con,
|
||||
!mcp251xfd_reg_invalid(con) &&
|
||||
FIELD_GET(MCP251XFD_REG_CON_OPMOD_MASK,
|
||||
con) == mode_req,
|
||||
MCP251XFD_POLL_SLEEP_US,
|
||||
MCP251XFD_POLL_TIMEOUT_US);
|
||||
MCP251XFD_POLL_SLEEP_US, timeout_us);
|
||||
if (err != -ETIMEDOUT && err != -EBADMSG)
|
||||
return err;
|
||||
|
||||
|
@ -387,6 +387,7 @@ static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC <
|
||||
#define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US)
|
||||
#define MCP251XFD_POLL_SLEEP_US (10)
|
||||
#define MCP251XFD_POLL_TIMEOUT_US (USEC_PER_MSEC)
|
||||
#define MCP251XFD_FRAME_LEN_MAX_BITS (736)
|
||||
|
||||
/* Misc */
|
||||
#define MCP251XFD_NAPI_WEIGHT 32
|
||||
|
@ -303,12 +303,6 @@ struct gs_can {
|
||||
struct can_bittiming_const bt_const, data_bt_const;
|
||||
unsigned int channel; /* channel number */
|
||||
|
||||
/* time counter for hardware timestamps */
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
spinlock_t tc_lock; /* spinlock to guard access tc->cycle_last */
|
||||
struct delayed_work timestamp;
|
||||
|
||||
u32 feature;
|
||||
unsigned int hf_size_tx;
|
||||
|
||||
@ -325,6 +319,13 @@ struct gs_usb {
|
||||
struct gs_can *canch[GS_MAX_INTF];
|
||||
struct usb_anchor rx_submitted;
|
||||
struct usb_device *udev;
|
||||
|
||||
/* time counter for hardware timestamps */
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
spinlock_t tc_lock; /* spinlock to guard access tc->cycle_last */
|
||||
struct delayed_work timestamp;
|
||||
|
||||
unsigned int hf_size_rx;
|
||||
u8 active_channels;
|
||||
};
|
||||
@ -388,15 +389,15 @@ static int gs_cmd_reset(struct gs_can *dev)
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
static inline int gs_usb_get_timestamp(const struct gs_can *dev,
|
||||
static inline int gs_usb_get_timestamp(const struct gs_usb *parent,
|
||||
u32 *timestamp_p)
|
||||
{
|
||||
__le32 timestamp;
|
||||
int rc;
|
||||
|
||||
rc = usb_control_msg_recv(dev->udev, 0, GS_USB_BREQ_TIMESTAMP,
|
||||
rc = usb_control_msg_recv(parent->udev, 0, GS_USB_BREQ_TIMESTAMP,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
dev->channel, 0,
|
||||
0, 0,
|
||||
×tamp, sizeof(timestamp),
|
||||
USB_CTRL_GET_TIMEOUT,
|
||||
GFP_KERNEL);
|
||||
@ -410,20 +411,20 @@ static inline int gs_usb_get_timestamp(const struct gs_can *dev,
|
||||
|
||||
static u64 gs_usb_timestamp_read(const struct cyclecounter *cc) __must_hold(&dev->tc_lock)
|
||||
{
|
||||
struct gs_can *dev = container_of(cc, struct gs_can, cc);
|
||||
struct gs_usb *parent = container_of(cc, struct gs_usb, cc);
|
||||
u32 timestamp = 0;
|
||||
int err;
|
||||
|
||||
lockdep_assert_held(&dev->tc_lock);
|
||||
lockdep_assert_held(&parent->tc_lock);
|
||||
|
||||
/* drop lock for synchronous USB transfer */
|
||||
spin_unlock_bh(&dev->tc_lock);
|
||||
err = gs_usb_get_timestamp(dev, ×tamp);
|
||||
spin_lock_bh(&dev->tc_lock);
|
||||
spin_unlock_bh(&parent->tc_lock);
|
||||
err = gs_usb_get_timestamp(parent, ×tamp);
|
||||
spin_lock_bh(&parent->tc_lock);
|
||||
if (err)
|
||||
netdev_err(dev->netdev,
|
||||
"Error %d while reading timestamp. HW timestamps may be inaccurate.",
|
||||
err);
|
||||
dev_err(&parent->udev->dev,
|
||||
"Error %d while reading timestamp. HW timestamps may be inaccurate.",
|
||||
err);
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
@ -431,14 +432,14 @@ static u64 gs_usb_timestamp_read(const struct cyclecounter *cc) __must_hold(&dev
|
||||
static void gs_usb_timestamp_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct gs_can *dev;
|
||||
struct gs_usb *parent;
|
||||
|
||||
dev = container_of(delayed_work, struct gs_can, timestamp);
|
||||
spin_lock_bh(&dev->tc_lock);
|
||||
timecounter_read(&dev->tc);
|
||||
spin_unlock_bh(&dev->tc_lock);
|
||||
parent = container_of(delayed_work, struct gs_usb, timestamp);
|
||||
spin_lock_bh(&parent->tc_lock);
|
||||
timecounter_read(&parent->tc);
|
||||
spin_unlock_bh(&parent->tc_lock);
|
||||
|
||||
schedule_delayed_work(&dev->timestamp,
|
||||
schedule_delayed_work(&parent->timestamp,
|
||||
GS_USB_TIMESTAMP_WORK_DELAY_SEC * HZ);
|
||||
}
|
||||
|
||||
@ -446,37 +447,38 @@ static void gs_usb_skb_set_timestamp(struct gs_can *dev,
|
||||
struct sk_buff *skb, u32 timestamp)
|
||||
{
|
||||
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
|
||||
struct gs_usb *parent = dev->parent;
|
||||
u64 ns;
|
||||
|
||||
spin_lock_bh(&dev->tc_lock);
|
||||
ns = timecounter_cyc2time(&dev->tc, timestamp);
|
||||
spin_unlock_bh(&dev->tc_lock);
|
||||
spin_lock_bh(&parent->tc_lock);
|
||||
ns = timecounter_cyc2time(&parent->tc, timestamp);
|
||||
spin_unlock_bh(&parent->tc_lock);
|
||||
|
||||
hwtstamps->hwtstamp = ns_to_ktime(ns);
|
||||
}
|
||||
|
||||
static void gs_usb_timestamp_init(struct gs_can *dev)
|
||||
static void gs_usb_timestamp_init(struct gs_usb *parent)
|
||||
{
|
||||
struct cyclecounter *cc = &dev->cc;
|
||||
struct cyclecounter *cc = &parent->cc;
|
||||
|
||||
cc->read = gs_usb_timestamp_read;
|
||||
cc->mask = CYCLECOUNTER_MASK(32);
|
||||
cc->shift = 32 - bits_per(NSEC_PER_SEC / GS_USB_TIMESTAMP_TIMER_HZ);
|
||||
cc->mult = clocksource_hz2mult(GS_USB_TIMESTAMP_TIMER_HZ, cc->shift);
|
||||
|
||||
spin_lock_init(&dev->tc_lock);
|
||||
spin_lock_bh(&dev->tc_lock);
|
||||
timecounter_init(&dev->tc, &dev->cc, ktime_get_real_ns());
|
||||
spin_unlock_bh(&dev->tc_lock);
|
||||
spin_lock_init(&parent->tc_lock);
|
||||
spin_lock_bh(&parent->tc_lock);
|
||||
timecounter_init(&parent->tc, &parent->cc, ktime_get_real_ns());
|
||||
spin_unlock_bh(&parent->tc_lock);
|
||||
|
||||
INIT_DELAYED_WORK(&dev->timestamp, gs_usb_timestamp_work);
|
||||
schedule_delayed_work(&dev->timestamp,
|
||||
INIT_DELAYED_WORK(&parent->timestamp, gs_usb_timestamp_work);
|
||||
schedule_delayed_work(&parent->timestamp,
|
||||
GS_USB_TIMESTAMP_WORK_DELAY_SEC * HZ);
|
||||
}
|
||||
|
||||
static void gs_usb_timestamp_stop(struct gs_can *dev)
|
||||
static void gs_usb_timestamp_stop(struct gs_usb *parent)
|
||||
{
|
||||
cancel_delayed_work_sync(&dev->timestamp);
|
||||
cancel_delayed_work_sync(&parent->timestamp);
|
||||
}
|
||||
|
||||
static void gs_update_state(struct gs_can *dev, struct can_frame *cf)
|
||||
@ -560,6 +562,9 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
||||
if (!netif_device_present(netdev))
|
||||
return;
|
||||
|
||||
if (!netif_running(netdev))
|
||||
goto resubmit_urb;
|
||||
|
||||
if (hf->echo_id == -1) { /* normal rx */
|
||||
if (hf->flags & GS_CAN_FLAG_FD) {
|
||||
skb = alloc_canfd_skb(dev->netdev, &cfd);
|
||||
@ -833,6 +838,7 @@ static int gs_can_open(struct net_device *netdev)
|
||||
.mode = cpu_to_le32(GS_CAN_MODE_START),
|
||||
};
|
||||
struct gs_host_frame *hf;
|
||||
struct urb *urb = NULL;
|
||||
u32 ctrlmode;
|
||||
u32 flags = 0;
|
||||
int rc, i;
|
||||
@ -855,14 +861,18 @@ static int gs_can_open(struct net_device *netdev)
|
||||
}
|
||||
|
||||
if (!parent->active_channels) {
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
gs_usb_timestamp_init(parent);
|
||||
|
||||
for (i = 0; i < GS_MAX_RX_URBS; i++) {
|
||||
struct urb *urb;
|
||||
u8 *buf;
|
||||
|
||||
/* alloc rx urb */
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
if (!urb) {
|
||||
rc = -ENOMEM;
|
||||
goto out_usb_kill_anchored_urbs;
|
||||
}
|
||||
|
||||
/* alloc rx buffer */
|
||||
buf = kmalloc(dev->parent->hf_size_rx,
|
||||
@ -870,8 +880,8 @@ static int gs_can_open(struct net_device *netdev)
|
||||
if (!buf) {
|
||||
netdev_err(netdev,
|
||||
"No memory left for USB buffer\n");
|
||||
usb_free_urb(urb);
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto out_usb_free_urb;
|
||||
}
|
||||
|
||||
/* fill, anchor, and submit rx urb */
|
||||
@ -894,9 +904,7 @@ static int gs_can_open(struct net_device *netdev)
|
||||
netdev_err(netdev,
|
||||
"usb_submit failed (err=%d)\n", rc);
|
||||
|
||||
usb_unanchor_urb(urb);
|
||||
usb_free_urb(urb);
|
||||
break;
|
||||
goto out_usb_unanchor_urb;
|
||||
}
|
||||
|
||||
/* Drop reference,
|
||||
@ -926,13 +934,9 @@ static int gs_can_open(struct net_device *netdev)
|
||||
flags |= GS_CAN_MODE_FD;
|
||||
|
||||
/* if hardware supports timestamps, enable it */
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) {
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
flags |= GS_CAN_MODE_HW_TIMESTAMP;
|
||||
|
||||
/* start polling timestamp */
|
||||
gs_usb_timestamp_init(dev);
|
||||
}
|
||||
|
||||
/* finally start device */
|
||||
dev->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
dm.flags = cpu_to_le32(flags);
|
||||
@ -942,10 +946,9 @@ static int gs_can_open(struct net_device *netdev)
|
||||
GFP_KERNEL);
|
||||
if (rc) {
|
||||
netdev_err(netdev, "Couldn't start device (err=%d)\n", rc);
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
gs_usb_timestamp_stop(dev);
|
||||
dev->can.state = CAN_STATE_STOPPED;
|
||||
return rc;
|
||||
|
||||
goto out_usb_kill_anchored_urbs;
|
||||
}
|
||||
|
||||
parent->active_channels++;
|
||||
@ -953,6 +956,22 @@ static int gs_can_open(struct net_device *netdev)
|
||||
netif_start_queue(netdev);
|
||||
|
||||
return 0;
|
||||
|
||||
out_usb_unanchor_urb:
|
||||
usb_unanchor_urb(urb);
|
||||
out_usb_free_urb:
|
||||
usb_free_urb(urb);
|
||||
out_usb_kill_anchored_urbs:
|
||||
if (!parent->active_channels) {
|
||||
usb_kill_anchored_urbs(&dev->tx_submitted);
|
||||
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
gs_usb_timestamp_stop(parent);
|
||||
}
|
||||
|
||||
close_candev(netdev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int gs_usb_get_state(const struct net_device *netdev,
|
||||
@ -998,14 +1017,13 @@ static int gs_can_close(struct net_device *netdev)
|
||||
|
||||
netif_stop_queue(netdev);
|
||||
|
||||
/* stop polling timestamp */
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
gs_usb_timestamp_stop(dev);
|
||||
|
||||
/* Stop polling */
|
||||
parent->active_channels--;
|
||||
if (!parent->active_channels) {
|
||||
usb_kill_anchored_urbs(&parent->rx_submitted);
|
||||
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
gs_usb_timestamp_stop(parent);
|
||||
}
|
||||
|
||||
/* Stop sending URBs */
|
||||
|
@ -1526,6 +1526,12 @@ static int bcm_release(struct socket *sock)
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
#if IS_ENABLED(CONFIG_PROC_FS)
|
||||
/* remove procfs entry */
|
||||
if (net->can.bcmproc_dir && bo->bcm_proc_read)
|
||||
remove_proc_entry(bo->procname, net->can.bcmproc_dir);
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
list_for_each_entry_safe(op, next, &bo->tx_ops, list)
|
||||
bcm_remove_op(op);
|
||||
|
||||
@ -1561,12 +1567,6 @@ static int bcm_release(struct socket *sock)
|
||||
list_for_each_entry_safe(op, next, &bo->rx_ops, list)
|
||||
bcm_remove_op(op);
|
||||
|
||||
#if IS_ENABLED(CONFIG_PROC_FS)
|
||||
/* remove procfs entry */
|
||||
if (net->can.bcmproc_dir && bo->bcm_proc_read)
|
||||
remove_proc_entry(bo->procname, net->can.bcmproc_dir);
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
/* remove device reference */
|
||||
if (bo->bound) {
|
||||
bo->bound = 0;
|
||||
|
@ -84,6 +84,7 @@ struct raw_sock {
|
||||
struct sock sk;
|
||||
int bound;
|
||||
int ifindex;
|
||||
struct net_device *dev;
|
||||
struct list_head notifier;
|
||||
int loopback;
|
||||
int recv_own_msgs;
|
||||
@ -277,7 +278,7 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,
|
||||
if (!net_eq(dev_net(dev), sock_net(sk)))
|
||||
return;
|
||||
|
||||
if (ro->ifindex != dev->ifindex)
|
||||
if (ro->dev != dev)
|
||||
return;
|
||||
|
||||
switch (msg) {
|
||||
@ -292,6 +293,7 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,
|
||||
|
||||
ro->ifindex = 0;
|
||||
ro->bound = 0;
|
||||
ro->dev = NULL;
|
||||
ro->count = 0;
|
||||
release_sock(sk);
|
||||
|
||||
@ -337,6 +339,7 @@ static int raw_init(struct sock *sk)
|
||||
|
||||
ro->bound = 0;
|
||||
ro->ifindex = 0;
|
||||
ro->dev = NULL;
|
||||
|
||||
/* set default filter to single entry dfilter */
|
||||
ro->dfilter.can_id = 0;
|
||||
@ -385,19 +388,13 @@ static int raw_release(struct socket *sock)
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
rtnl_lock();
|
||||
/* remove current filters & unregister */
|
||||
if (ro->bound) {
|
||||
if (ro->ifindex) {
|
||||
struct net_device *dev;
|
||||
|
||||
dev = dev_get_by_index(sock_net(sk), ro->ifindex);
|
||||
if (dev) {
|
||||
raw_disable_allfilters(dev_net(dev), dev, sk);
|
||||
dev_put(dev);
|
||||
}
|
||||
} else {
|
||||
if (ro->dev)
|
||||
raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
|
||||
else
|
||||
raw_disable_allfilters(sock_net(sk), NULL, sk);
|
||||
}
|
||||
}
|
||||
|
||||
if (ro->count > 1)
|
||||
@ -405,8 +402,10 @@ static int raw_release(struct socket *sock)
|
||||
|
||||
ro->ifindex = 0;
|
||||
ro->bound = 0;
|
||||
ro->dev = NULL;
|
||||
ro->count = 0;
|
||||
free_percpu(ro->uniq);
|
||||
rtnl_unlock();
|
||||
|
||||
sock_orphan(sk);
|
||||
sock->sk = NULL;
|
||||
@ -422,6 +421,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
|
||||
struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
|
||||
struct sock *sk = sock->sk;
|
||||
struct raw_sock *ro = raw_sk(sk);
|
||||
struct net_device *dev = NULL;
|
||||
int ifindex;
|
||||
int err = 0;
|
||||
int notify_enetdown = 0;
|
||||
@ -431,14 +431,13 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
|
||||
if (addr->can_family != AF_CAN)
|
||||
return -EINVAL;
|
||||
|
||||
rtnl_lock();
|
||||
lock_sock(sk);
|
||||
|
||||
if (ro->bound && addr->can_ifindex == ro->ifindex)
|
||||
goto out;
|
||||
|
||||
if (addr->can_ifindex) {
|
||||
struct net_device *dev;
|
||||
|
||||
dev = dev_get_by_index(sock_net(sk), addr->can_ifindex);
|
||||
if (!dev) {
|
||||
err = -ENODEV;
|
||||
@ -467,26 +466,20 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
|
||||
if (!err) {
|
||||
if (ro->bound) {
|
||||
/* unregister old filters */
|
||||
if (ro->ifindex) {
|
||||
struct net_device *dev;
|
||||
|
||||
dev = dev_get_by_index(sock_net(sk),
|
||||
ro->ifindex);
|
||||
if (dev) {
|
||||
raw_disable_allfilters(dev_net(dev),
|
||||
dev, sk);
|
||||
dev_put(dev);
|
||||
}
|
||||
} else {
|
||||
if (ro->dev)
|
||||
raw_disable_allfilters(dev_net(ro->dev),
|
||||
ro->dev, sk);
|
||||
else
|
||||
raw_disable_allfilters(sock_net(sk), NULL, sk);
|
||||
}
|
||||
}
|
||||
ro->ifindex = ifindex;
|
||||
ro->bound = 1;
|
||||
ro->dev = dev;
|
||||
}
|
||||
|
||||
out:
|
||||
release_sock(sk);
|
||||
rtnl_unlock();
|
||||
|
||||
if (notify_enetdown) {
|
||||
sk->sk_err = ENETDOWN;
|
||||
@ -553,9 +546,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
||||
rtnl_lock();
|
||||
lock_sock(sk);
|
||||
|
||||
if (ro->bound && ro->ifindex) {
|
||||
dev = dev_get_by_index(sock_net(sk), ro->ifindex);
|
||||
if (!dev) {
|
||||
dev = ro->dev;
|
||||
if (ro->bound && dev) {
|
||||
if (dev->reg_state != NETREG_REGISTERED) {
|
||||
if (count > 1)
|
||||
kfree(filter);
|
||||
err = -ENODEV;
|
||||
@ -596,7 +589,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
||||
ro->count = count;
|
||||
|
||||
out_fil:
|
||||
dev_put(dev);
|
||||
release_sock(sk);
|
||||
rtnl_unlock();
|
||||
|
||||
@ -614,9 +606,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
||||
rtnl_lock();
|
||||
lock_sock(sk);
|
||||
|
||||
if (ro->bound && ro->ifindex) {
|
||||
dev = dev_get_by_index(sock_net(sk), ro->ifindex);
|
||||
if (!dev) {
|
||||
dev = ro->dev;
|
||||
if (ro->bound && dev) {
|
||||
if (dev->reg_state != NETREG_REGISTERED) {
|
||||
err = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
@ -640,7 +632,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
||||
ro->err_mask = err_mask;
|
||||
|
||||
out_err:
|
||||
dev_put(dev);
|
||||
release_sock(sk);
|
||||
rtnl_unlock();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user