Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller:
"As usual, there are a couple straggler bug fixes:
1) qlcnic_alloc_mbx_args() error returns are not checked in qlcnic
driver. Fix from Insu Yun.
2) SKB refcounting bug in connector, from Florian Westphal.
3) vrf_get_saddr() has to propagate fib_lookup() errors to it's
callers, from David Ahern.
4) Fix AF_UNIX splice/bind deadlock, from Rainer Weikusat.
5) qdisc_rcu_free() fails to free the per-cpu qstats. Fix from John
Fastabend.
6) vmxnet3 driver passes wrong page to dma_map_page(), fix from
Shrikrishna Khare.
7) Don't allow zero cwnd in tcp_cwnd_reduction(), from Yuchung Cheng"
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net:
tcp: fix zero cwnd in tcp_cwnd_reduction
Driver: Vmxnet3: Fix regression caused by 5738a09
net: qmi_wwan: Add WeTelecom-WPD600N
mkiss: fix scribble on freed memory
net: possible use after free in dst_release
net: sched: fix missing free per cpu on qstats
ARM: net: bpf: fix zero right shift
6pack: fix free memory scribbles
net: filter: make JITs zero A for SKF_AD_ALU_XOR_X
bridge: Only call /sbin/bridge-stp for the initial network namespace
af_unix: Fix splice-bind deadlock
net: Propagate lookup failure in l3mdev_get_saddr to caller
r8152: add reset_resume function
connector: bump skb->users before callback invocation
cxgb4: correctly handling failed allocation
qlcnic: correctly handle qlcnic_alloc_mbx_args
This commit is contained in:
commit
51cb67c0b0
|
@ -187,19 +187,6 @@ static inline int mem_words_used(struct jit_ctx *ctx)
|
||||||
return fls(ctx->seen & SEEN_MEM);
|
return fls(ctx->seen & SEEN_MEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool is_load_to_a(u16 inst)
|
|
||||||
{
|
|
||||||
switch (inst) {
|
|
||||||
case BPF_LD | BPF_W | BPF_LEN:
|
|
||||||
case BPF_LD | BPF_W | BPF_ABS:
|
|
||||||
case BPF_LD | BPF_H | BPF_ABS:
|
|
||||||
case BPF_LD | BPF_B | BPF_ABS:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jit_fill_hole(void *area, unsigned int size)
|
static void jit_fill_hole(void *area, unsigned int size)
|
||||||
{
|
{
|
||||||
u32 *ptr;
|
u32 *ptr;
|
||||||
|
@ -211,7 +198,6 @@ static void jit_fill_hole(void *area, unsigned int size)
|
||||||
static void build_prologue(struct jit_ctx *ctx)
|
static void build_prologue(struct jit_ctx *ctx)
|
||||||
{
|
{
|
||||||
u16 reg_set = saved_regs(ctx);
|
u16 reg_set = saved_regs(ctx);
|
||||||
u16 first_inst = ctx->skf->insns[0].code;
|
|
||||||
u16 off;
|
u16 off;
|
||||||
|
|
||||||
#ifdef CONFIG_FRAME_POINTER
|
#ifdef CONFIG_FRAME_POINTER
|
||||||
|
@ -241,7 +227,7 @@ static void build_prologue(struct jit_ctx *ctx)
|
||||||
emit(ARM_MOV_I(r_X, 0), ctx);
|
emit(ARM_MOV_I(r_X, 0), ctx);
|
||||||
|
|
||||||
/* do not leak kernel data to userspace */
|
/* do not leak kernel data to userspace */
|
||||||
if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst)))
|
if (bpf_needs_clear_a(&ctx->skf->insns[0]))
|
||||||
emit(ARM_MOV_I(r_A, 0), ctx);
|
emit(ARM_MOV_I(r_A, 0), ctx);
|
||||||
|
|
||||||
/* stack space for the BPF_MEM words */
|
/* stack space for the BPF_MEM words */
|
||||||
|
@ -770,7 +756,8 @@ load_ind:
|
||||||
case BPF_ALU | BPF_RSH | BPF_K:
|
case BPF_ALU | BPF_RSH | BPF_K:
|
||||||
if (unlikely(k > 31))
|
if (unlikely(k > 31))
|
||||||
return -1;
|
return -1;
|
||||||
emit(ARM_LSR_I(r_A, r_A, k), ctx);
|
if (k)
|
||||||
|
emit(ARM_LSR_I(r_A, r_A, k), ctx);
|
||||||
break;
|
break;
|
||||||
case BPF_ALU | BPF_RSH | BPF_X:
|
case BPF_ALU | BPF_RSH | BPF_X:
|
||||||
update_on_xread(ctx);
|
update_on_xread(ctx);
|
||||||
|
|
|
@ -521,19 +521,6 @@ static inline u16 align_sp(unsigned int num)
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_load_to_a(u16 inst)
|
|
||||||
{
|
|
||||||
switch (inst) {
|
|
||||||
case BPF_LD | BPF_W | BPF_LEN:
|
|
||||||
case BPF_LD | BPF_W | BPF_ABS:
|
|
||||||
case BPF_LD | BPF_H | BPF_ABS:
|
|
||||||
case BPF_LD | BPF_B | BPF_ABS:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset)
|
static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset)
|
||||||
{
|
{
|
||||||
int i = 0, real_off = 0;
|
int i = 0, real_off = 0;
|
||||||
|
@ -614,7 +601,6 @@ static unsigned int get_stack_depth(struct jit_ctx *ctx)
|
||||||
|
|
||||||
static void build_prologue(struct jit_ctx *ctx)
|
static void build_prologue(struct jit_ctx *ctx)
|
||||||
{
|
{
|
||||||
u16 first_inst = ctx->skf->insns[0].code;
|
|
||||||
int sp_off;
|
int sp_off;
|
||||||
|
|
||||||
/* Calculate the total offset for the stack pointer */
|
/* Calculate the total offset for the stack pointer */
|
||||||
|
@ -641,7 +627,7 @@ static void build_prologue(struct jit_ctx *ctx)
|
||||||
emit_jit_reg_move(r_X, r_zero, ctx);
|
emit_jit_reg_move(r_X, r_zero, ctx);
|
||||||
|
|
||||||
/* Do not leak kernel data to userspace */
|
/* Do not leak kernel data to userspace */
|
||||||
if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst)))
|
if (bpf_needs_clear_a(&ctx->skf->insns[0]))
|
||||||
emit_jit_reg_move(r_A, r_zero, ctx);
|
emit_jit_reg_move(r_A, r_zero, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,18 +78,9 @@ static void bpf_jit_build_prologue(struct bpf_prog *fp, u32 *image,
|
||||||
PPC_LI(r_X, 0);
|
PPC_LI(r_X, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (filter[0].code) {
|
/* make sure we dont leak kernel information to user */
|
||||||
case BPF_RET | BPF_K:
|
if (bpf_needs_clear_a(&filter[0]))
|
||||||
case BPF_LD | BPF_W | BPF_LEN:
|
|
||||||
case BPF_LD | BPF_W | BPF_ABS:
|
|
||||||
case BPF_LD | BPF_H | BPF_ABS:
|
|
||||||
case BPF_LD | BPF_B | BPF_ABS:
|
|
||||||
/* first instruction sets A register (or is RET 'constant') */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* make sure we dont leak kernel information to user */
|
|
||||||
PPC_LI(r_A, 0);
|
PPC_LI(r_A, 0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
|
static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
|
||||||
|
|
|
@ -420,22 +420,9 @@ void bpf_jit_compile(struct bpf_prog *fp)
|
||||||
}
|
}
|
||||||
emit_reg_move(O7, r_saved_O7);
|
emit_reg_move(O7, r_saved_O7);
|
||||||
|
|
||||||
switch (filter[0].code) {
|
/* Make sure we dont leak kernel information to the user. */
|
||||||
case BPF_RET | BPF_K:
|
if (bpf_needs_clear_a(&filter[0]))
|
||||||
case BPF_LD | BPF_W | BPF_LEN:
|
|
||||||
case BPF_LD | BPF_W | BPF_ABS:
|
|
||||||
case BPF_LD | BPF_H | BPF_ABS:
|
|
||||||
case BPF_LD | BPF_B | BPF_ABS:
|
|
||||||
/* The first instruction sets the A register (or is
|
|
||||||
* a "RET 'constant'")
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Make sure we dont leak kernel information to the
|
|
||||||
* user.
|
|
||||||
*/
|
|
||||||
emit_clear(r_A); /* A = 0 */
|
emit_clear(r_A); /* A = 0 */
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < flen; i++) {
|
for (i = 0; i < flen; i++) {
|
||||||
unsigned int K = filter[i].k;
|
unsigned int K = filter[i].k;
|
||||||
|
|
|
@ -179,26 +179,21 @@ static int cn_call_callback(struct sk_buff *skb)
|
||||||
*
|
*
|
||||||
* It checks skb, netlink header and msg sizes, and calls callback helper.
|
* It checks skb, netlink header and msg sizes, and calls callback helper.
|
||||||
*/
|
*/
|
||||||
static void cn_rx_skb(struct sk_buff *__skb)
|
static void cn_rx_skb(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct nlmsghdr *nlh;
|
struct nlmsghdr *nlh;
|
||||||
struct sk_buff *skb;
|
|
||||||
int len, err;
|
int len, err;
|
||||||
|
|
||||||
skb = skb_get(__skb);
|
|
||||||
|
|
||||||
if (skb->len >= NLMSG_HDRLEN) {
|
if (skb->len >= NLMSG_HDRLEN) {
|
||||||
nlh = nlmsg_hdr(skb);
|
nlh = nlmsg_hdr(skb);
|
||||||
len = nlmsg_len(nlh);
|
len = nlmsg_len(nlh);
|
||||||
|
|
||||||
if (len < (int)sizeof(struct cn_msg) ||
|
if (len < (int)sizeof(struct cn_msg) ||
|
||||||
skb->len < nlh->nlmsg_len ||
|
skb->len < nlh->nlmsg_len ||
|
||||||
len > CONNECTOR_MAX_MSG_SIZE) {
|
len > CONNECTOR_MAX_MSG_SIZE)
|
||||||
kfree_skb(skb);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
err = cn_call_callback(skb);
|
err = cn_call_callback(skb_get(skb));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,6 +295,10 @@ struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start,
|
||||||
INIT_LIST_HEAD(&ctbl->hash_list[i]);
|
INIT_LIST_HEAD(&ctbl->hash_list[i]);
|
||||||
|
|
||||||
cl_list = t4_alloc_mem(clipt_size*sizeof(struct clip_entry));
|
cl_list = t4_alloc_mem(clipt_size*sizeof(struct clip_entry));
|
||||||
|
if (!cl_list) {
|
||||||
|
t4_free_mem(ctbl);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ctbl->cl_list = (void *)cl_list;
|
ctbl->cl_list = (void *)cl_list;
|
||||||
|
|
||||||
for (i = 0; i < clipt_size; i++) {
|
for (i = 0; i < clipt_size; i++) {
|
||||||
|
|
|
@ -772,8 +772,10 @@ int qlcnic_82xx_config_intrpt(struct qlcnic_adapter *adapter, u8 op_type)
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
for (i = 0; i < ahw->num_msix; i++) {
|
for (i = 0; i < ahw->num_msix; i++) {
|
||||||
qlcnic_alloc_mbx_args(&cmd, adapter,
|
err = qlcnic_alloc_mbx_args(&cmd, adapter,
|
||||||
QLCNIC_CMD_MQ_TX_CONFIG_INTR);
|
QLCNIC_CMD_MQ_TX_CONFIG_INTR);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
|
type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
|
||||||
val = type | (ahw->intr_tbl[i].type << 4);
|
val = type | (ahw->intr_tbl[i].type << 4);
|
||||||
if (ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
|
if (ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
|
||||||
|
|
|
@ -683,6 +683,12 @@ static void sixpack_close(struct tty_struct *tty)
|
||||||
if (!atomic_dec_and_test(&sp->refcnt))
|
if (!atomic_dec_and_test(&sp->refcnt))
|
||||||
down(&sp->dead_sem);
|
down(&sp->dead_sem);
|
||||||
|
|
||||||
|
/* We must stop the queue to avoid potentially scribbling
|
||||||
|
* on the free buffers. The sp->dead_sem is not sufficient
|
||||||
|
* to protect us from sp->xbuff access.
|
||||||
|
*/
|
||||||
|
netif_stop_queue(sp->dev);
|
||||||
|
|
||||||
del_timer_sync(&sp->tx_t);
|
del_timer_sync(&sp->tx_t);
|
||||||
del_timer_sync(&sp->resync_t);
|
del_timer_sync(&sp->resync_t);
|
||||||
|
|
||||||
|
|
|
@ -797,6 +797,11 @@ static void mkiss_close(struct tty_struct *tty)
|
||||||
*/
|
*/
|
||||||
if (!atomic_dec_and_test(&ax->refcnt))
|
if (!atomic_dec_and_test(&ax->refcnt))
|
||||||
down(&ax->dead_sem);
|
down(&ax->dead_sem);
|
||||||
|
/*
|
||||||
|
* Halt the transmit queue so that a new transmit cannot scribble
|
||||||
|
* on our buffers
|
||||||
|
*/
|
||||||
|
netif_stop_queue(ax->dev);
|
||||||
|
|
||||||
/* Free all AX25 frame buffers. */
|
/* Free all AX25 frame buffers. */
|
||||||
kfree(ax->rbuff);
|
kfree(ax->rbuff);
|
||||||
|
|
|
@ -742,6 +742,7 @@ static const struct usb_device_id products[] = {
|
||||||
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
|
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
|
||||||
{QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
|
{QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
|
||||||
{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
|
{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
|
||||||
|
{QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
|
||||||
|
|
||||||
/* 4. Gobi 1000 devices */
|
/* 4. Gobi 1000 devices */
|
||||||
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
|
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
|
||||||
|
|
|
@ -3525,6 +3525,14 @@ static int rtl8152_resume(struct usb_interface *intf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtl8152_reset_resume(struct usb_interface *intf)
|
||||||
|
{
|
||||||
|
struct r8152 *tp = usb_get_intfdata(intf);
|
||||||
|
|
||||||
|
clear_bit(SELECTIVE_SUSPEND, &tp->flags);
|
||||||
|
return rtl8152_resume(intf);
|
||||||
|
}
|
||||||
|
|
||||||
static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||||
{
|
{
|
||||||
struct r8152 *tp = netdev_priv(dev);
|
struct r8152 *tp = netdev_priv(dev);
|
||||||
|
@ -4276,7 +4284,7 @@ static struct usb_driver rtl8152_driver = {
|
||||||
.disconnect = rtl8152_disconnect,
|
.disconnect = rtl8152_disconnect,
|
||||||
.suspend = rtl8152_suspend,
|
.suspend = rtl8152_suspend,
|
||||||
.resume = rtl8152_resume,
|
.resume = rtl8152_resume,
|
||||||
.reset_resume = rtl8152_resume,
|
.reset_resume = rtl8152_reset_resume,
|
||||||
.pre_reset = rtl8152_pre_reset,
|
.pre_reset = rtl8152_pre_reset,
|
||||||
.post_reset = rtl8152_post_reset,
|
.post_reset = rtl8152_post_reset,
|
||||||
.supports_autosuspend = 1,
|
.supports_autosuspend = 1,
|
||||||
|
|
|
@ -1380,10 +1380,10 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
|
||||||
skip_page_frags = true;
|
skip_page_frags = true;
|
||||||
goto rcd_done;
|
goto rcd_done;
|
||||||
}
|
}
|
||||||
new_dma_addr = dma_map_page(&adapter->pdev->dev
|
new_dma_addr = dma_map_page(&adapter->pdev->dev,
|
||||||
, rbi->page,
|
new_page,
|
||||||
0, PAGE_SIZE,
|
0, PAGE_SIZE,
|
||||||
PCI_DMA_FROMDEVICE);
|
PCI_DMA_FROMDEVICE);
|
||||||
if (dma_mapping_error(&adapter->pdev->dev,
|
if (dma_mapping_error(&adapter->pdev->dev,
|
||||||
new_dma_addr)) {
|
new_dma_addr)) {
|
||||||
put_page(new_page);
|
put_page(new_page);
|
||||||
|
|
|
@ -69,10 +69,10 @@
|
||||||
/*
|
/*
|
||||||
* Version numbers
|
* Version numbers
|
||||||
*/
|
*/
|
||||||
#define VMXNET3_DRIVER_VERSION_STRING "1.4.4.0-k"
|
#define VMXNET3_DRIVER_VERSION_STRING "1.4.5.0-k"
|
||||||
|
|
||||||
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
|
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
|
||||||
#define VMXNET3_DRIVER_VERSION_NUM 0x01040400
|
#define VMXNET3_DRIVER_VERSION_NUM 0x01040500
|
||||||
|
|
||||||
#if defined(CONFIG_PCI_MSI)
|
#if defined(CONFIG_PCI_MSI)
|
||||||
/* RSS only makes sense if MSI-X is supported. */
|
/* RSS only makes sense if MSI-X is supported. */
|
||||||
|
|
|
@ -800,7 +800,7 @@ static struct rtable *vrf_get_rtable(const struct net_device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called under rcu_read_lock */
|
/* called under rcu_read_lock */
|
||||||
static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
|
static int vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
|
||||||
{
|
{
|
||||||
struct fib_result res = { .tclassid = 0 };
|
struct fib_result res = { .tclassid = 0 };
|
||||||
struct net *net = dev_net(dev);
|
struct net *net = dev_net(dev);
|
||||||
|
@ -808,9 +808,10 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
|
||||||
u8 flags = fl4->flowi4_flags;
|
u8 flags = fl4->flowi4_flags;
|
||||||
u8 scope = fl4->flowi4_scope;
|
u8 scope = fl4->flowi4_scope;
|
||||||
u8 tos = RT_FL_TOS(fl4);
|
u8 tos = RT_FL_TOS(fl4);
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (unlikely(!fl4->daddr))
|
if (unlikely(!fl4->daddr))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF;
|
fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF;
|
||||||
fl4->flowi4_iif = LOOPBACK_IFINDEX;
|
fl4->flowi4_iif = LOOPBACK_IFINDEX;
|
||||||
|
@ -818,7 +819,8 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
|
||||||
fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
|
fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
|
||||||
RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
|
RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
|
||||||
|
|
||||||
if (!fib_lookup(net, fl4, &res, 0)) {
|
rc = fib_lookup(net, fl4, &res, 0);
|
||||||
|
if (!rc) {
|
||||||
if (res.type == RTN_LOCAL)
|
if (res.type == RTN_LOCAL)
|
||||||
fl4->saddr = res.fi->fib_prefsrc ? : fl4->daddr;
|
fl4->saddr = res.fi->fib_prefsrc ? : fl4->daddr;
|
||||||
else
|
else
|
||||||
|
@ -828,6 +830,8 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
|
||||||
fl4->flowi4_flags = flags;
|
fl4->flowi4_flags = flags;
|
||||||
fl4->flowi4_tos = orig_tos;
|
fl4->flowi4_tos = orig_tos;
|
||||||
fl4->flowi4_scope = scope;
|
fl4->flowi4_scope = scope;
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
|
|
@ -493,6 +493,25 @@ static inline void bpf_jit_free(struct bpf_prog *fp)
|
||||||
|
|
||||||
#define BPF_ANC BIT(15)
|
#define BPF_ANC BIT(15)
|
||||||
|
|
||||||
|
static inline bool bpf_needs_clear_a(const struct sock_filter *first)
|
||||||
|
{
|
||||||
|
switch (first->code) {
|
||||||
|
case BPF_RET | BPF_K:
|
||||||
|
case BPF_LD | BPF_W | BPF_LEN:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case BPF_LD | BPF_W | BPF_ABS:
|
||||||
|
case BPF_LD | BPF_H | BPF_ABS:
|
||||||
|
case BPF_LD | BPF_B | BPF_ABS:
|
||||||
|
if (first->k == SKF_AD_OFF + SKF_AD_ALU_XOR_X)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline u16 bpf_anc_helper(const struct sock_filter *ftest)
|
static inline u16 bpf_anc_helper(const struct sock_filter *ftest)
|
||||||
{
|
{
|
||||||
BUG_ON(ftest->code & BPF_ANC);
|
BUG_ON(ftest->code & BPF_ANC);
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct l3mdev_ops {
|
||||||
/* IPv4 ops */
|
/* IPv4 ops */
|
||||||
struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev,
|
struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev,
|
||||||
const struct flowi4 *fl4);
|
const struct flowi4 *fl4);
|
||||||
void (*l3mdev_get_saddr)(struct net_device *dev,
|
int (*l3mdev_get_saddr)(struct net_device *dev,
|
||||||
struct flowi4 *fl4);
|
struct flowi4 *fl4);
|
||||||
|
|
||||||
/* IPv6 ops */
|
/* IPv6 ops */
|
||||||
|
@ -112,10 +112,11 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void l3mdev_get_saddr(struct net *net, int ifindex,
|
static inline int l3mdev_get_saddr(struct net *net, int ifindex,
|
||||||
struct flowi4 *fl4)
|
struct flowi4 *fl4)
|
||||||
{
|
{
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
if (ifindex) {
|
if (ifindex) {
|
||||||
|
|
||||||
|
@ -124,11 +125,13 @@ static inline void l3mdev_get_saddr(struct net *net, int ifindex,
|
||||||
dev = dev_get_by_index_rcu(net, ifindex);
|
dev = dev_get_by_index_rcu(net, ifindex);
|
||||||
if (dev && netif_is_l3_master(dev) &&
|
if (dev && netif_is_l3_master(dev) &&
|
||||||
dev->l3mdev_ops->l3mdev_get_saddr) {
|
dev->l3mdev_ops->l3mdev_get_saddr) {
|
||||||
dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
|
rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev,
|
static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev,
|
||||||
|
@ -200,9 +203,10 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void l3mdev_get_saddr(struct net *net, int ifindex,
|
static inline int l3mdev_get_saddr(struct net *net, int ifindex,
|
||||||
struct flowi4 *fl4)
|
struct flowi4 *fl4)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
|
|
|
@ -283,7 +283,12 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
|
||||||
sport, dport, sk);
|
sport, dport, sk);
|
||||||
|
|
||||||
if (!src && oif) {
|
if (!src && oif) {
|
||||||
l3mdev_get_saddr(net, oif, fl4);
|
int rc;
|
||||||
|
|
||||||
|
rc = l3mdev_get_saddr(net, oif, fl4);
|
||||||
|
if (rc < 0)
|
||||||
|
return ERR_PTR(rc);
|
||||||
|
|
||||||
src = fl4->saddr;
|
src = fl4->saddr;
|
||||||
}
|
}
|
||||||
if (!dst || !src) {
|
if (!dst || !src) {
|
||||||
|
|
|
@ -142,7 +142,10 @@ static void br_stp_start(struct net_bridge *br)
|
||||||
char *envp[] = { NULL };
|
char *envp[] = { NULL };
|
||||||
struct net_bridge_port *p;
|
struct net_bridge_port *p;
|
||||||
|
|
||||||
r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
|
if (net_eq(dev_net(br->dev), &init_net))
|
||||||
|
r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
|
||||||
|
else
|
||||||
|
r = -ENOENT;
|
||||||
|
|
||||||
spin_lock_bh(&br->lock);
|
spin_lock_bh(&br->lock);
|
||||||
|
|
||||||
|
|
|
@ -301,12 +301,13 @@ void dst_release(struct dst_entry *dst)
|
||||||
{
|
{
|
||||||
if (dst) {
|
if (dst) {
|
||||||
int newrefcnt;
|
int newrefcnt;
|
||||||
|
unsigned short nocache = dst->flags & DST_NOCACHE;
|
||||||
|
|
||||||
newrefcnt = atomic_dec_return(&dst->__refcnt);
|
newrefcnt = atomic_dec_return(&dst->__refcnt);
|
||||||
if (unlikely(newrefcnt < 0))
|
if (unlikely(newrefcnt < 0))
|
||||||
net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
|
net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
|
||||||
__func__, dst, newrefcnt);
|
__func__, dst, newrefcnt);
|
||||||
if (!newrefcnt && unlikely(dst->flags & DST_NOCACHE))
|
if (!newrefcnt && unlikely(nocache))
|
||||||
call_rcu(&dst->rcu_head, dst_destroy_rcu);
|
call_rcu(&dst->rcu_head, dst_destroy_rcu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -601,8 +601,11 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||||
(inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
|
(inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
|
||||||
daddr, saddr, 0, 0);
|
daddr, saddr, 0, 0);
|
||||||
|
|
||||||
if (!saddr && ipc.oif)
|
if (!saddr && ipc.oif) {
|
||||||
l3mdev_get_saddr(net, ipc.oif, &fl4);
|
err = l3mdev_get_saddr(net, ipc.oif, &fl4);
|
||||||
|
if (err < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (!inet->hdrincl) {
|
if (!inet->hdrincl) {
|
||||||
rfv.msg = msg;
|
rfv.msg = msg;
|
||||||
|
|
|
@ -2478,6 +2478,9 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,
|
||||||
int newly_acked_sacked = prior_unsacked -
|
int newly_acked_sacked = prior_unsacked -
|
||||||
(tp->packets_out - tp->sacked_out);
|
(tp->packets_out - tp->sacked_out);
|
||||||
|
|
||||||
|
if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd))
|
||||||
|
return;
|
||||||
|
|
||||||
tp->prr_delivered += newly_acked_sacked;
|
tp->prr_delivered += newly_acked_sacked;
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered +
|
u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered +
|
||||||
|
|
|
@ -1025,8 +1025,11 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||||
flow_flags,
|
flow_flags,
|
||||||
faddr, saddr, dport, inet->inet_sport);
|
faddr, saddr, dport, inet->inet_sport);
|
||||||
|
|
||||||
if (!saddr && ipc.oif)
|
if (!saddr && ipc.oif) {
|
||||||
l3mdev_get_saddr(net, ipc.oif, fl4);
|
err = l3mdev_get_saddr(net, ipc.oif, fl4);
|
||||||
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
|
security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
|
||||||
rt = ip_route_output_flow(net, fl4, sk);
|
rt = ip_route_output_flow(net, fl4, sk);
|
||||||
|
|
|
@ -658,8 +658,10 @@ static void qdisc_rcu_free(struct rcu_head *head)
|
||||||
{
|
{
|
||||||
struct Qdisc *qdisc = container_of(head, struct Qdisc, rcu_head);
|
struct Qdisc *qdisc = container_of(head, struct Qdisc, rcu_head);
|
||||||
|
|
||||||
if (qdisc_is_percpu_stats(qdisc))
|
if (qdisc_is_percpu_stats(qdisc)) {
|
||||||
free_percpu(qdisc->cpu_bstats);
|
free_percpu(qdisc->cpu_bstats);
|
||||||
|
free_percpu(qdisc->cpu_qstats);
|
||||||
|
}
|
||||||
|
|
||||||
kfree((char *) qdisc - qdisc->padded);
|
kfree((char *) qdisc - qdisc->padded);
|
||||||
}
|
}
|
||||||
|
|
|
@ -953,32 +953,20 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
|
static int unix_mknod(struct dentry *dentry, struct path *path, umode_t mode,
|
||||||
|
struct path *res)
|
||||||
{
|
{
|
||||||
struct dentry *dentry;
|
int err;
|
||||||
struct path path;
|
|
||||||
int err = 0;
|
|
||||||
/*
|
|
||||||
* Get the parent directory, calculate the hash for last
|
|
||||||
* component.
|
|
||||||
*/
|
|
||||||
dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
|
|
||||||
err = PTR_ERR(dentry);
|
|
||||||
if (IS_ERR(dentry))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
/*
|
err = security_path_mknod(path, dentry, mode, 0);
|
||||||
* All right, let's create it.
|
|
||||||
*/
|
|
||||||
err = security_path_mknod(&path, dentry, mode, 0);
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0);
|
err = vfs_mknod(d_inode(path->dentry), dentry, mode, 0);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
res->mnt = mntget(path.mnt);
|
res->mnt = mntget(path->mnt);
|
||||||
res->dentry = dget(dentry);
|
res->dentry = dget(dentry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done_path_create(&path, dentry);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -989,10 +977,12 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||||
struct unix_sock *u = unix_sk(sk);
|
struct unix_sock *u = unix_sk(sk);
|
||||||
struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
|
struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
|
||||||
char *sun_path = sunaddr->sun_path;
|
char *sun_path = sunaddr->sun_path;
|
||||||
int err;
|
int err, name_err;
|
||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
struct unix_address *addr;
|
struct unix_address *addr;
|
||||||
struct hlist_head *list;
|
struct hlist_head *list;
|
||||||
|
struct path path;
|
||||||
|
struct dentry *dentry;
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (sunaddr->sun_family != AF_UNIX)
|
if (sunaddr->sun_family != AF_UNIX)
|
||||||
|
@ -1008,14 +998,34 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||||
goto out;
|
goto out;
|
||||||
addr_len = err;
|
addr_len = err;
|
||||||
|
|
||||||
|
name_err = 0;
|
||||||
|
dentry = NULL;
|
||||||
|
if (sun_path[0]) {
|
||||||
|
/* Get the parent directory, calculate the hash for last
|
||||||
|
* component.
|
||||||
|
*/
|
||||||
|
dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
|
||||||
|
|
||||||
|
if (IS_ERR(dentry)) {
|
||||||
|
/* delay report until after 'already bound' check */
|
||||||
|
name_err = PTR_ERR(dentry);
|
||||||
|
dentry = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = mutex_lock_interruptible(&u->readlock);
|
err = mutex_lock_interruptible(&u->readlock);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out_path;
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (u->addr)
|
if (u->addr)
|
||||||
goto out_up;
|
goto out_up;
|
||||||
|
|
||||||
|
if (name_err) {
|
||||||
|
err = name_err == -EEXIST ? -EADDRINUSE : name_err;
|
||||||
|
goto out_up;
|
||||||
|
}
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
|
addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
|
@ -1026,11 +1036,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||||
addr->hash = hash ^ sk->sk_type;
|
addr->hash = hash ^ sk->sk_type;
|
||||||
atomic_set(&addr->refcnt, 1);
|
atomic_set(&addr->refcnt, 1);
|
||||||
|
|
||||||
if (sun_path[0]) {
|
if (dentry) {
|
||||||
struct path path;
|
struct path u_path;
|
||||||
umode_t mode = S_IFSOCK |
|
umode_t mode = S_IFSOCK |
|
||||||
(SOCK_INODE(sock)->i_mode & ~current_umask());
|
(SOCK_INODE(sock)->i_mode & ~current_umask());
|
||||||
err = unix_mknod(sun_path, mode, &path);
|
err = unix_mknod(dentry, &path, mode, &u_path);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err == -EEXIST)
|
if (err == -EEXIST)
|
||||||
err = -EADDRINUSE;
|
err = -EADDRINUSE;
|
||||||
|
@ -1038,9 +1048,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||||
goto out_up;
|
goto out_up;
|
||||||
}
|
}
|
||||||
addr->hash = UNIX_HASH_SIZE;
|
addr->hash = UNIX_HASH_SIZE;
|
||||||
hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE-1);
|
hash = d_backing_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
|
||||||
spin_lock(&unix_table_lock);
|
spin_lock(&unix_table_lock);
|
||||||
u->path = path;
|
u->path = u_path;
|
||||||
list = &unix_socket_table[hash];
|
list = &unix_socket_table[hash];
|
||||||
} else {
|
} else {
|
||||||
spin_lock(&unix_table_lock);
|
spin_lock(&unix_table_lock);
|
||||||
|
@ -1063,6 +1073,10 @@ out_unlock:
|
||||||
spin_unlock(&unix_table_lock);
|
spin_unlock(&unix_table_lock);
|
||||||
out_up:
|
out_up:
|
||||||
mutex_unlock(&u->readlock);
|
mutex_unlock(&u->readlock);
|
||||||
|
out_path:
|
||||||
|
if (dentry)
|
||||||
|
done_path_create(&path, dentry);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue