diff options
88 files changed, 1285 insertions, 518 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 664060179807..882ea01b4efe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4928,6 +4928,7 @@ F: include/linux/netfilter_bridge/ | |||
4928 | F: net/bridge/ | 4928 | F: net/bridge/ |
4929 | 4929 | ||
4930 | ETHERNET PHY LIBRARY | 4930 | ETHERNET PHY LIBRARY |
4931 | M: Andrew Lunn <andrew@lunn.ch> | ||
4931 | M: Florian Fainelli <f.fainelli@gmail.com> | 4932 | M: Florian Fainelli <f.fainelli@gmail.com> |
4932 | L: netdev@vger.kernel.org | 4933 | L: netdev@vger.kernel.org |
4933 | S: Maintained | 4934 | S: Maintained |
@@ -10814,6 +10815,7 @@ F: drivers/s390/block/dasd* | |||
10814 | F: block/partitions/ibm.c | 10815 | F: block/partitions/ibm.c |
10815 | 10816 | ||
10816 | S390 NETWORK DRIVERS | 10817 | S390 NETWORK DRIVERS |
10818 | M: Julian Wiedmann <jwi@linux.vnet.ibm.com> | ||
10817 | M: Ursula Braun <ubraun@linux.vnet.ibm.com> | 10819 | M: Ursula Braun <ubraun@linux.vnet.ibm.com> |
10818 | L: linux-s390@vger.kernel.org | 10820 | L: linux-s390@vger.kernel.org |
10819 | W: http://www.ibm.com/developerworks/linux/linux390/ | 10821 | W: http://www.ibm.com/developerworks/linux/linux390/ |
@@ -10844,6 +10846,7 @@ S: Supported | |||
10844 | F: drivers/s390/scsi/zfcp_* | 10846 | F: drivers/s390/scsi/zfcp_* |
10845 | 10847 | ||
10846 | S390 IUCV NETWORK LAYER | 10848 | S390 IUCV NETWORK LAYER |
10849 | M: Julian Wiedmann <jwi@linux.vnet.ibm.com> | ||
10847 | M: Ursula Braun <ubraun@linux.vnet.ibm.com> | 10850 | M: Ursula Braun <ubraun@linux.vnet.ibm.com> |
10848 | L: linux-s390@vger.kernel.org | 10851 | L: linux-s390@vger.kernel.org |
10849 | W: http://www.ibm.com/developerworks/linux/linux390/ | 10852 | W: http://www.ibm.com/developerworks/linux/linux390/ |
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 1dfd1085a04f..9ca691d6c13b 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c | |||
@@ -1032,6 +1032,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) | |||
1032 | sizeof(avmb1_carddef)))) | 1032 | sizeof(avmb1_carddef)))) |
1033 | return -EFAULT; | 1033 | return -EFAULT; |
1034 | cdef.cardtype = AVM_CARDTYPE_B1; | 1034 | cdef.cardtype = AVM_CARDTYPE_B1; |
1035 | cdef.cardnr = 0; | ||
1035 | } else { | 1036 | } else { |
1036 | if ((retval = copy_from_user(&cdef, data, | 1037 | if ((retval = copy_from_user(&cdef, data, |
1037 | sizeof(avmb1_extcarddef)))) | 1038 | sizeof(avmb1_extcarddef)))) |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index d05fbfdce5e5..5d6c40d86775 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c | |||
@@ -100,11 +100,6 @@ static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu) | |||
100 | goto err_exit; | 100 | goto err_exit; |
101 | ndev->mtu = new_mtu; | 101 | ndev->mtu = new_mtu; |
102 | 102 | ||
103 | if (netif_running(ndev)) { | ||
104 | aq_ndev_close(ndev); | ||
105 | aq_ndev_open(ndev); | ||
106 | } | ||
107 | |||
108 | err_exit: | 103 | err_exit: |
109 | return err; | 104 | return err; |
110 | } | 105 | } |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index ee78444bfb88..cdb02991f249 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c | |||
@@ -487,6 +487,9 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self, | |||
487 | dx_buff->mss = skb_shinfo(skb)->gso_size; | 487 | dx_buff->mss = skb_shinfo(skb)->gso_size; |
488 | dx_buff->is_txc = 1U; | 488 | dx_buff->is_txc = 1U; |
489 | 489 | ||
490 | dx_buff->is_ipv6 = | ||
491 | (ip_hdr(skb)->version == 6) ? 1U : 0U; | ||
492 | |||
490 | dx = aq_ring_next_dx(ring, dx); | 493 | dx = aq_ring_next_dx(ring, dx); |
491 | dx_buff = &ring->buff_ring[dx]; | 494 | dx_buff = &ring->buff_ring[dx]; |
492 | ++ret; | 495 | ++ret; |
@@ -510,10 +513,22 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self, | |||
510 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 513 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
511 | dx_buff->is_ip_cso = (htons(ETH_P_IP) == skb->protocol) ? | 514 | dx_buff->is_ip_cso = (htons(ETH_P_IP) == skb->protocol) ? |
512 | 1U : 0U; | 515 | 1U : 0U; |
513 | dx_buff->is_tcp_cso = | 516 | |
514 | (ip_hdr(skb)->protocol == IPPROTO_TCP) ? 1U : 0U; | 517 | if (ip_hdr(skb)->version == 4) { |
515 | dx_buff->is_udp_cso = | 518 | dx_buff->is_tcp_cso = |
516 | (ip_hdr(skb)->protocol == IPPROTO_UDP) ? 1U : 0U; | 519 | (ip_hdr(skb)->protocol == IPPROTO_TCP) ? |
520 | 1U : 0U; | ||
521 | dx_buff->is_udp_cso = | ||
522 | (ip_hdr(skb)->protocol == IPPROTO_UDP) ? | ||
523 | 1U : 0U; | ||
524 | } else if (ip_hdr(skb)->version == 6) { | ||
525 | dx_buff->is_tcp_cso = | ||
526 | (ipv6_hdr(skb)->nexthdr == NEXTHDR_TCP) ? | ||
527 | 1U : 0U; | ||
528 | dx_buff->is_udp_cso = | ||
529 | (ipv6_hdr(skb)->nexthdr == NEXTHDR_UDP) ? | ||
530 | 1U : 0U; | ||
531 | } | ||
517 | } | 532 | } |
518 | 533 | ||
519 | for (; nr_frags--; ++frag_count) { | 534 | for (; nr_frags--; ++frag_count) { |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 0358e6072d45..3a8a4aa13687 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c | |||
@@ -101,6 +101,7 @@ int aq_ring_init(struct aq_ring_s *self) | |||
101 | self->hw_head = 0; | 101 | self->hw_head = 0; |
102 | self->sw_head = 0; | 102 | self->sw_head = 0; |
103 | self->sw_tail = 0; | 103 | self->sw_tail = 0; |
104 | spin_lock_init(&self->header.lock); | ||
104 | return 0; | 105 | return 0; |
105 | } | 106 | } |
106 | 107 | ||
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h index 257254645068..eecd6d1c4d73 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h | |||
@@ -58,7 +58,8 @@ struct __packed aq_ring_buff_s { | |||
58 | u8 len_l2; | 58 | u8 len_l2; |
59 | u8 len_l3; | 59 | u8 len_l3; |
60 | u8 len_l4; | 60 | u8 len_l4; |
61 | u8 rsvd2; | 61 | u8 is_ipv6:1; |
62 | u8 rsvd2:7; | ||
62 | u32 len_pkt; | 63 | u32 len_pkt; |
63 | }; | 64 | }; |
64 | }; | 65 | }; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index a2b746a2dd50..4ee15ff06a44 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c | |||
@@ -433,6 +433,9 @@ static int hw_atl_a0_hw_ring_tx_xmit(struct aq_hw_s *self, | |||
433 | buff->len_l3 + | 433 | buff->len_l3 + |
434 | buff->len_l2); | 434 | buff->len_l2); |
435 | is_gso = true; | 435 | is_gso = true; |
436 | |||
437 | if (buff->is_ipv6) | ||
438 | txd->ctl |= HW_ATL_A0_TXD_CTL_CMD_IPV6; | ||
436 | } else { | 439 | } else { |
437 | buff_pa_len = buff->len; | 440 | buff_pa_len = buff->len; |
438 | 441 | ||
@@ -458,6 +461,7 @@ static int hw_atl_a0_hw_ring_tx_xmit(struct aq_hw_s *self, | |||
458 | if (unlikely(buff->is_eop)) { | 461 | if (unlikely(buff->is_eop)) { |
459 | txd->ctl |= HW_ATL_A0_TXD_CTL_EOP; | 462 | txd->ctl |= HW_ATL_A0_TXD_CTL_EOP; |
460 | txd->ctl |= HW_ATL_A0_TXD_CTL_CMD_WB; | 463 | txd->ctl |= HW_ATL_A0_TXD_CTL_CMD_WB; |
464 | is_gso = false; | ||
461 | } | 465 | } |
462 | } | 466 | } |
463 | 467 | ||
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index cab2931dab9a..42150708191d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | |||
@@ -471,6 +471,9 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self, | |||
471 | buff->len_l3 + | 471 | buff->len_l3 + |
472 | buff->len_l2); | 472 | buff->len_l2); |
473 | is_gso = true; | 473 | is_gso = true; |
474 | |||
475 | if (buff->is_ipv6) | ||
476 | txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_IPV6; | ||
474 | } else { | 477 | } else { |
475 | buff_pa_len = buff->len; | 478 | buff_pa_len = buff->len; |
476 | 479 | ||
@@ -496,6 +499,7 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self, | |||
496 | if (unlikely(buff->is_eop)) { | 499 | if (unlikely(buff->is_eop)) { |
497 | txd->ctl |= HW_ATL_B0_TXD_CTL_EOP; | 500 | txd->ctl |= HW_ATL_B0_TXD_CTL_EOP; |
498 | txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_WB; | 501 | txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_WB; |
502 | is_gso = false; | ||
499 | } | 503 | } |
500 | } | 504 | } |
501 | 505 | ||
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 0a23034bbe3f..352beff796ae 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | |||
@@ -2277,7 +2277,7 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, | |||
2277 | GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCP) | \ | 2277 | GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCP) | \ |
2278 | GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RSVD_GRC)) | 2278 | GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RSVD_GRC)) |
2279 | 2279 | ||
2280 | #define HW_INTERRUT_ASSERT_SET_0 \ | 2280 | #define HW_INTERRUPT_ASSERT_SET_0 \ |
2281 | (AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \ | 2281 | (AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \ |
2282 | AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \ | 2282 | AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \ |
2283 | AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \ | 2283 | AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \ |
@@ -2290,7 +2290,7 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, | |||
2290 | AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR |\ | 2290 | AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR |\ |
2291 | AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR |\ | 2291 | AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR |\ |
2292 | AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR) | 2292 | AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR) |
2293 | #define HW_INTERRUT_ASSERT_SET_1 \ | 2293 | #define HW_INTERRUPT_ASSERT_SET_1 \ |
2294 | (AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT | \ | 2294 | (AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT | \ |
2295 | AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT | \ | 2295 | AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT | \ |
2296 | AEU_INPUTS_ATTN_BITS_XSDM_HW_INTERRUPT | \ | 2296 | AEU_INPUTS_ATTN_BITS_XSDM_HW_INTERRUPT | \ |
@@ -2318,7 +2318,7 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, | |||
2318 | AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR | \ | 2318 | AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR | \ |
2319 | AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR |\ | 2319 | AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR |\ |
2320 | AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR) | 2320 | AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR) |
2321 | #define HW_INTERRUT_ASSERT_SET_2 \ | 2321 | #define HW_INTERRUPT_ASSERT_SET_2 \ |
2322 | (AEU_INPUTS_ATTN_BITS_CSEMI_HW_INTERRUPT | \ | 2322 | (AEU_INPUTS_ATTN_BITS_CSEMI_HW_INTERRUPT | \ |
2323 | AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT | \ | 2323 | AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT | \ |
2324 | AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT | \ | 2324 | AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT | \ |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index ac76fc251d26..a851f95c307a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | |||
@@ -4166,14 +4166,14 @@ static void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) | |||
4166 | bnx2x_release_phy_lock(bp); | 4166 | bnx2x_release_phy_lock(bp); |
4167 | } | 4167 | } |
4168 | 4168 | ||
4169 | if (attn & HW_INTERRUT_ASSERT_SET_0) { | 4169 | if (attn & HW_INTERRUPT_ASSERT_SET_0) { |
4170 | 4170 | ||
4171 | val = REG_RD(bp, reg_offset); | 4171 | val = REG_RD(bp, reg_offset); |
4172 | val &= ~(attn & HW_INTERRUT_ASSERT_SET_0); | 4172 | val &= ~(attn & HW_INTERRUPT_ASSERT_SET_0); |
4173 | REG_WR(bp, reg_offset, val); | 4173 | REG_WR(bp, reg_offset, val); |
4174 | 4174 | ||
4175 | BNX2X_ERR("FATAL HW block attention set0 0x%x\n", | 4175 | BNX2X_ERR("FATAL HW block attention set0 0x%x\n", |
4176 | (u32)(attn & HW_INTERRUT_ASSERT_SET_0)); | 4176 | (u32)(attn & HW_INTERRUPT_ASSERT_SET_0)); |
4177 | bnx2x_panic(); | 4177 | bnx2x_panic(); |
4178 | } | 4178 | } |
4179 | } | 4179 | } |
@@ -4191,7 +4191,7 @@ static void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) | |||
4191 | BNX2X_ERR("FATAL error from DORQ\n"); | 4191 | BNX2X_ERR("FATAL error from DORQ\n"); |
4192 | } | 4192 | } |
4193 | 4193 | ||
4194 | if (attn & HW_INTERRUT_ASSERT_SET_1) { | 4194 | if (attn & HW_INTERRUPT_ASSERT_SET_1) { |
4195 | 4195 | ||
4196 | int port = BP_PORT(bp); | 4196 | int port = BP_PORT(bp); |
4197 | int reg_offset; | 4197 | int reg_offset; |
@@ -4200,11 +4200,11 @@ static void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) | |||
4200 | MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1); | 4200 | MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1); |
4201 | 4201 | ||
4202 | val = REG_RD(bp, reg_offset); | 4202 | val = REG_RD(bp, reg_offset); |
4203 | val &= ~(attn & HW_INTERRUT_ASSERT_SET_1); | 4203 | val &= ~(attn & HW_INTERRUPT_ASSERT_SET_1); |
4204 | REG_WR(bp, reg_offset, val); | 4204 | REG_WR(bp, reg_offset, val); |
4205 | 4205 | ||
4206 | BNX2X_ERR("FATAL HW block attention set1 0x%x\n", | 4206 | BNX2X_ERR("FATAL HW block attention set1 0x%x\n", |
4207 | (u32)(attn & HW_INTERRUT_ASSERT_SET_1)); | 4207 | (u32)(attn & HW_INTERRUPT_ASSERT_SET_1)); |
4208 | bnx2x_panic(); | 4208 | bnx2x_panic(); |
4209 | } | 4209 | } |
4210 | } | 4210 | } |
@@ -4235,7 +4235,7 @@ static void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) | |||
4235 | } | 4235 | } |
4236 | } | 4236 | } |
4237 | 4237 | ||
4238 | if (attn & HW_INTERRUT_ASSERT_SET_2) { | 4238 | if (attn & HW_INTERRUPT_ASSERT_SET_2) { |
4239 | 4239 | ||
4240 | int port = BP_PORT(bp); | 4240 | int port = BP_PORT(bp); |
4241 | int reg_offset; | 4241 | int reg_offset; |
@@ -4244,11 +4244,11 @@ static void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) | |||
4244 | MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2); | 4244 | MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2); |
4245 | 4245 | ||
4246 | val = REG_RD(bp, reg_offset); | 4246 | val = REG_RD(bp, reg_offset); |
4247 | val &= ~(attn & HW_INTERRUT_ASSERT_SET_2); | 4247 | val &= ~(attn & HW_INTERRUPT_ASSERT_SET_2); |
4248 | REG_WR(bp, reg_offset, val); | 4248 | REG_WR(bp, reg_offset, val); |
4249 | 4249 | ||
4250 | BNX2X_ERR("FATAL HW block attention set2 0x%x\n", | 4250 | BNX2X_ERR("FATAL HW block attention set2 0x%x\n", |
4251 | (u32)(attn & HW_INTERRUT_ASSERT_SET_2)); | 4251 | (u32)(attn & HW_INTERRUPT_ASSERT_SET_2)); |
4252 | bnx2x_panic(); | 4252 | bnx2x_panic(); |
4253 | } | 4253 | } |
4254 | } | 4254 | } |
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 32de4589d16a..1f1e54ba0ecb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c | |||
@@ -1983,20 +1983,25 @@ static void bnxt_free_rx_skbs(struct bnxt *bp) | |||
1983 | 1983 | ||
1984 | for (j = 0; j < max_idx; j++) { | 1984 | for (j = 0; j < max_idx; j++) { |
1985 | struct bnxt_sw_rx_bd *rx_buf = &rxr->rx_buf_ring[j]; | 1985 | struct bnxt_sw_rx_bd *rx_buf = &rxr->rx_buf_ring[j]; |
1986 | dma_addr_t mapping = rx_buf->mapping; | ||
1986 | void *data = rx_buf->data; | 1987 | void *data = rx_buf->data; |
1987 | 1988 | ||
1988 | if (!data) | 1989 | if (!data) |
1989 | continue; | 1990 | continue; |
1990 | 1991 | ||
1991 | dma_unmap_single(&pdev->dev, rx_buf->mapping, | ||
1992 | bp->rx_buf_use_size, bp->rx_dir); | ||
1993 | |||
1994 | rx_buf->data = NULL; | 1992 | rx_buf->data = NULL; |
1995 | 1993 | ||
1996 | if (BNXT_RX_PAGE_MODE(bp)) | 1994 | if (BNXT_RX_PAGE_MODE(bp)) { |
1995 | mapping -= bp->rx_dma_offset; | ||
1996 | dma_unmap_page(&pdev->dev, mapping, | ||
1997 | PAGE_SIZE, bp->rx_dir); | ||
1997 | __free_page(data); | 1998 | __free_page(data); |
1998 | else | 1999 | } else { |
2000 | dma_unmap_single(&pdev->dev, mapping, | ||
2001 | bp->rx_buf_use_size, | ||
2002 | bp->rx_dir); | ||
1999 | kfree(data); | 2003 | kfree(data); |
2004 | } | ||
2000 | } | 2005 | } |
2001 | 2006 | ||
2002 | for (j = 0; j < max_agg_idx; j++) { | 2007 | for (j = 0; j < max_agg_idx; j++) { |
@@ -2455,6 +2460,18 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr) | |||
2455 | return 0; | 2460 | return 0; |
2456 | } | 2461 | } |
2457 | 2462 | ||
2463 | static void bnxt_init_cp_rings(struct bnxt *bp) | ||
2464 | { | ||
2465 | int i; | ||
2466 | |||
2467 | for (i = 0; i < bp->cp_nr_rings; i++) { | ||
2468 | struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring; | ||
2469 | struct bnxt_ring_struct *ring = &cpr->cp_ring_struct; | ||
2470 | |||
2471 | ring->fw_ring_id = INVALID_HW_RING_ID; | ||
2472 | } | ||
2473 | } | ||
2474 | |||
2458 | static int bnxt_init_rx_rings(struct bnxt *bp) | 2475 | static int bnxt_init_rx_rings(struct bnxt *bp) |
2459 | { | 2476 | { |
2460 | int i, rc = 0; | 2477 | int i, rc = 0; |
@@ -4732,7 +4749,7 @@ static int bnxt_set_tpa(struct bnxt *bp, bool set_tpa) | |||
4732 | rc = bnxt_hwrm_vnic_set_tpa(bp, i, tpa_flags); | 4749 | rc = bnxt_hwrm_vnic_set_tpa(bp, i, tpa_flags); |
4733 | if (rc) { | 4750 | if (rc) { |
4734 | netdev_err(bp->dev, "hwrm vnic set tpa failure rc for vnic %d: %x\n", | 4751 | netdev_err(bp->dev, "hwrm vnic set tpa failure rc for vnic %d: %x\n", |
4735 | rc, i); | 4752 | i, rc); |
4736 | return rc; | 4753 | return rc; |
4737 | } | 4754 | } |
4738 | } | 4755 | } |
@@ -5006,6 +5023,7 @@ static int bnxt_shutdown_nic(struct bnxt *bp, bool irq_re_init) | |||
5006 | 5023 | ||
5007 | static int bnxt_init_nic(struct bnxt *bp, bool irq_re_init) | 5024 | static int bnxt_init_nic(struct bnxt *bp, bool irq_re_init) |
5008 | { | 5025 | { |
5026 | bnxt_init_cp_rings(bp); | ||
5009 | bnxt_init_rx_rings(bp); | 5027 | bnxt_init_rx_rings(bp); |
5010 | bnxt_init_tx_rings(bp); | 5028 | bnxt_init_tx_rings(bp); |
5011 | bnxt_init_ring_grps(bp, irq_re_init); | 5029 | bnxt_init_ring_grps(bp, irq_re_init); |
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c index 9e59663a6ead..0f6811860ad5 100644 --- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c +++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c | |||
@@ -1930,13 +1930,13 @@ static void | |||
1930 | bfa_ioc_send_enable(struct bfa_ioc *ioc) | 1930 | bfa_ioc_send_enable(struct bfa_ioc *ioc) |
1931 | { | 1931 | { |
1932 | struct bfi_ioc_ctrl_req enable_req; | 1932 | struct bfi_ioc_ctrl_req enable_req; |
1933 | struct timeval tv; | ||
1934 | 1933 | ||
1935 | bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ, | 1934 | bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ, |
1936 | bfa_ioc_portid(ioc)); | 1935 | bfa_ioc_portid(ioc)); |
1937 | enable_req.clscode = htons(ioc->clscode); | 1936 | enable_req.clscode = htons(ioc->clscode); |
1938 | do_gettimeofday(&tv); | 1937 | enable_req.rsvd = htons(0); |
1939 | enable_req.tv_sec = ntohl(tv.tv_sec); | 1938 | /* overflow in 2106 */ |
1939 | enable_req.tv_sec = ntohl(ktime_get_real_seconds()); | ||
1940 | bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req)); | 1940 | bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req)); |
1941 | } | 1941 | } |
1942 | 1942 | ||
@@ -1947,6 +1947,10 @@ bfa_ioc_send_disable(struct bfa_ioc *ioc) | |||
1947 | 1947 | ||
1948 | bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ, | 1948 | bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ, |
1949 | bfa_ioc_portid(ioc)); | 1949 | bfa_ioc_portid(ioc)); |
1950 | disable_req.clscode = htons(ioc->clscode); | ||
1951 | disable_req.rsvd = htons(0); | ||
1952 | /* overflow in 2106 */ | ||
1953 | disable_req.tv_sec = ntohl(ktime_get_real_seconds()); | ||
1950 | bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req)); | 1954 | bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req)); |
1951 | } | 1955 | } |
1952 | 1956 | ||
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 30e855004c57..02dd5246dfae 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c | |||
@@ -4939,8 +4939,9 @@ static int | |||
4939 | __be_cmd_set_logical_link_config(struct be_adapter *adapter, | 4939 | __be_cmd_set_logical_link_config(struct be_adapter *adapter, |
4940 | int link_state, int version, u8 domain) | 4940 | int link_state, int version, u8 domain) |
4941 | { | 4941 | { |
4942 | struct be_mcc_wrb *wrb; | ||
4943 | struct be_cmd_req_set_ll_link *req; | 4942 | struct be_cmd_req_set_ll_link *req; |
4943 | struct be_mcc_wrb *wrb; | ||
4944 | u32 link_config = 0; | ||
4944 | int status; | 4945 | int status; |
4945 | 4946 | ||
4946 | mutex_lock(&adapter->mcc_lock); | 4947 | mutex_lock(&adapter->mcc_lock); |
@@ -4962,10 +4963,12 @@ __be_cmd_set_logical_link_config(struct be_adapter *adapter, | |||
4962 | 4963 | ||
4963 | if (link_state == IFLA_VF_LINK_STATE_ENABLE || | 4964 | if (link_state == IFLA_VF_LINK_STATE_ENABLE || |
4964 | link_state == IFLA_VF_LINK_STATE_AUTO) | 4965 | link_state == IFLA_VF_LINK_STATE_AUTO) |
4965 | req->link_config |= PLINK_ENABLE; | 4966 | link_config |= PLINK_ENABLE; |
4966 | 4967 | ||
4967 | if (link_state == IFLA_VF_LINK_STATE_AUTO) | 4968 | if (link_state == IFLA_VF_LINK_STATE_AUTO) |
4968 | req->link_config |= PLINK_TRACK; | 4969 | link_config |= PLINK_TRACK; |
4970 | |||
4971 | req->link_config = cpu_to_le32(link_config); | ||
4969 | 4972 | ||
4970 | status = be_mcc_notify_wait(adapter); | 4973 | status = be_mcc_notify_wait(adapter); |
4971 | err: | 4974 | err: |
diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 992ebe973d25..f819843e2bae 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c | |||
@@ -189,11 +189,9 @@ static int nps_enet_poll(struct napi_struct *napi, int budget) | |||
189 | 189 | ||
190 | nps_enet_tx_handler(ndev); | 190 | nps_enet_tx_handler(ndev); |
191 | work_done = nps_enet_rx_handler(ndev); | 191 | work_done = nps_enet_rx_handler(ndev); |
192 | if (work_done < budget) { | 192 | if ((work_done < budget) && napi_complete_done(napi, work_done)) { |
193 | u32 buf_int_enable_value = 0; | 193 | u32 buf_int_enable_value = 0; |
194 | 194 | ||
195 | napi_complete_done(napi, work_done); | ||
196 | |||
197 | /* set tx_done and rx_rdy bits */ | 195 | /* set tx_done and rx_rdy bits */ |
198 | buf_int_enable_value |= NPS_ENET_ENABLE << RX_RDY_SHIFT; | 196 | buf_int_enable_value |= NPS_ENET_ENABLE << RX_RDY_SHIFT; |
199 | buf_int_enable_value |= NPS_ENET_ENABLE << TX_DONE_SHIFT; | 197 | buf_int_enable_value |= NPS_ENET_ENABLE << TX_DONE_SHIFT; |
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 928b0df2b8e0..ade6b3e4ed13 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c | |||
@@ -28,8 +28,10 @@ | |||
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/netdevice.h> | 30 | #include <linux/netdevice.h> |
31 | #include <linux/of.h> | ||
31 | #include <linux/phy.h> | 32 | #include <linux/phy.h> |
32 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
34 | #include <linux/property.h> | ||
33 | #include <net/ip.h> | 35 | #include <net/ip.h> |
34 | #include <net/ncsi.h> | 36 | #include <net/ncsi.h> |
35 | 37 | ||
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c index 3239d27143b9..bdd8cdd732fb 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | |||
@@ -82,9 +82,12 @@ void hns_mac_get_link_status(struct hns_mac_cb *mac_cb, u32 *link_status) | |||
82 | else | 82 | else |
83 | *link_status = 0; | 83 | *link_status = 0; |
84 | 84 | ||
85 | ret = mac_cb->dsaf_dev->misc_op->get_sfp_prsnt(mac_cb, &sfp_prsnt); | 85 | if (mac_cb->media_type == HNAE_MEDIA_TYPE_FIBER) { |
86 | if (!ret) | 86 | ret = mac_cb->dsaf_dev->misc_op->get_sfp_prsnt(mac_cb, |
87 | *link_status = *link_status && sfp_prsnt; | 87 | &sfp_prsnt); |
88 | if (!ret) | ||
89 | *link_status = *link_status && sfp_prsnt; | ||
90 | } | ||
88 | 91 | ||
89 | mac_cb->link = *link_status; | 92 | mac_cb->link = *link_status; |
90 | } | 93 | } |
@@ -855,7 +858,7 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb) | |||
855 | of_node_put(np); | 858 | of_node_put(np); |
856 | 859 | ||
857 | np = of_parse_phandle(to_of_node(mac_cb->fw_port), | 860 | np = of_parse_phandle(to_of_node(mac_cb->fw_port), |
858 | "serdes-syscon", 0); | 861 | "serdes-syscon", 0); |
859 | syscon = syscon_node_to_regmap(np); | 862 | syscon = syscon_node_to_regmap(np); |
860 | of_node_put(np); | 863 | of_node_put(np); |
861 | if (IS_ERR_OR_NULL(syscon)) { | 864 | if (IS_ERR_OR_NULL(syscon)) { |
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 90dbda792614..403ea9db6dbd 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c | |||
@@ -1519,6 +1519,7 @@ static void hns_dsaf_set_mac_key( | |||
1519 | mac_key->high.bits.mac_3 = addr[3]; | 1519 | mac_key->high.bits.mac_3 = addr[3]; |
1520 | mac_key->low.bits.mac_4 = addr[4]; | 1520 | mac_key->low.bits.mac_4 = addr[4]; |
1521 | mac_key->low.bits.mac_5 = addr[5]; | 1521 | mac_key->low.bits.mac_5 = addr[5]; |
1522 | mac_key->low.bits.port_vlan = 0; | ||
1522 | dsaf_set_field(mac_key->low.bits.port_vlan, DSAF_TBL_TCAM_KEY_VLAN_M, | 1523 | dsaf_set_field(mac_key->low.bits.port_vlan, DSAF_TBL_TCAM_KEY_VLAN_M, |
1523 | DSAF_TBL_TCAM_KEY_VLAN_S, vlan_id); | 1524 | DSAF_TBL_TCAM_KEY_VLAN_S, vlan_id); |
1524 | dsaf_set_field(mac_key->low.bits.port_vlan, DSAF_TBL_TCAM_KEY_PORT_M, | 1525 | dsaf_set_field(mac_key->low.bits.port_vlan, DSAF_TBL_TCAM_KEY_PORT_M, |
@@ -2924,10 +2925,11 @@ void hns_dsaf_set_promisc_tcam(struct dsaf_device *dsaf_dev, | |||
2924 | /* find the tcam entry index for promisc */ | 2925 | /* find the tcam entry index for promisc */ |
2925 | entry_index = dsaf_promisc_tcam_entry(port); | 2926 | entry_index = dsaf_promisc_tcam_entry(port); |
2926 | 2927 | ||
2928 | memset(&tbl_tcam_data, 0, sizeof(tbl_tcam_data)); | ||
2929 | memset(&tbl_tcam_mask, 0, sizeof(tbl_tcam_mask)); | ||
2930 | |||
2927 | /* config key mask */ | 2931 | /* config key mask */ |
2928 | if (enable) { | 2932 | if (enable) { |
2929 | memset(&tbl_tcam_data, 0, sizeof(tbl_tcam_data)); | ||
2930 | memset(&tbl_tcam_mask, 0, sizeof(tbl_tcam_mask)); | ||
2931 | dsaf_set_field(tbl_tcam_data.low.bits.port_vlan, | 2933 | dsaf_set_field(tbl_tcam_data.low.bits.port_vlan, |
2932 | DSAF_TBL_TCAM_KEY_PORT_M, | 2934 | DSAF_TBL_TCAM_KEY_PORT_M, |
2933 | DSAF_TBL_TCAM_KEY_PORT_S, port); | 2935 | DSAF_TBL_TCAM_KEY_PORT_S, port); |
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c index a2c22d084ce9..e13aa064a8e9 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c | |||
@@ -461,6 +461,32 @@ int hns_mac_get_sfp_prsnt(struct hns_mac_cb *mac_cb, int *sfp_prsnt) | |||
461 | return 0; | 461 | return 0; |
462 | } | 462 | } |
463 | 463 | ||
464 | int hns_mac_get_sfp_prsnt_acpi(struct hns_mac_cb *mac_cb, int *sfp_prsnt) | ||
465 | { | ||
466 | union acpi_object *obj; | ||
467 | union acpi_object obj_args, argv4; | ||
468 | |||
469 | obj_args.integer.type = ACPI_TYPE_INTEGER; | ||
470 | obj_args.integer.value = mac_cb->mac_id; | ||
471 | |||
472 | argv4.type = ACPI_TYPE_PACKAGE, | ||
473 | argv4.package.count = 1, | ||
474 | argv4.package.elements = &obj_args, | ||
475 | |||
476 | obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev), | ||
477 | hns_dsaf_acpi_dsm_uuid, 0, | ||
478 | HNS_OP_GET_SFP_STAT_FUNC, &argv4); | ||
479 | |||
480 | if (!obj || obj->type != ACPI_TYPE_INTEGER) | ||
481 | return -ENODEV; | ||
482 | |||
483 | *sfp_prsnt = obj->integer.value; | ||
484 | |||
485 | ACPI_FREE(obj); | ||
486 | |||
487 | return 0; | ||
488 | } | ||
489 | |||
464 | /** | 490 | /** |
465 | * hns_mac_config_sds_loopback - set loop back for serdes | 491 | * hns_mac_config_sds_loopback - set loop back for serdes |
466 | * @mac_cb: mac control block | 492 | * @mac_cb: mac control block |
@@ -592,7 +618,7 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) | |||
592 | misc_op->hns_dsaf_roce_srst = hns_dsaf_roce_srst_acpi; | 618 | misc_op->hns_dsaf_roce_srst = hns_dsaf_roce_srst_acpi; |
593 | 619 | ||
594 | misc_op->get_phy_if = hns_mac_get_phy_if_acpi; | 620 | misc_op->get_phy_if = hns_mac_get_phy_if_acpi; |
595 | misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt; | 621 | misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt_acpi; |
596 | 622 | ||
597 | misc_op->cfg_serdes_loopback = hns_mac_config_sds_loopback_acpi; | 623 | misc_op->cfg_serdes_loopback = hns_mac_config_sds_loopback_acpi; |
598 | } else { | 624 | } else { |
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 2175cced402f..e9af89ad039c 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c | |||
@@ -6274,8 +6274,8 @@ static int e1000e_pm_freeze(struct device *dev) | |||
6274 | /* Quiesce the device without resetting the hardware */ | 6274 | /* Quiesce the device without resetting the hardware */ |
6275 | e1000e_down(adapter, false); | 6275 | e1000e_down(adapter, false); |
6276 | e1000_free_irq(adapter); | 6276 | e1000_free_irq(adapter); |
6277 | e1000e_reset_interrupt_capability(adapter); | ||
6278 | } | 6277 | } |
6278 | e1000e_reset_interrupt_capability(adapter); | ||
6279 | 6279 | ||
6280 | /* Allow time for pending master requests to run */ | 6280 | /* Allow time for pending master requests to run */ |
6281 | e1000e_disable_pcie_master(&adapter->hw); | 6281 | e1000e_disable_pcie_master(&adapter->hw); |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index e8a8351c8ea9..82a95cc2c8ee 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c | |||
@@ -4438,8 +4438,12 @@ static void i40e_napi_enable_all(struct i40e_vsi *vsi) | |||
4438 | if (!vsi->netdev) | 4438 | if (!vsi->netdev) |
4439 | return; | 4439 | return; |
4440 | 4440 | ||
4441 | for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) | 4441 | for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) { |
4442 | napi_enable(&vsi->q_vectors[q_idx]->napi); | 4442 | struct i40e_q_vector *q_vector = vsi->q_vectors[q_idx]; |
4443 | |||
4444 | if (q_vector->rx.ring || q_vector->tx.ring) | ||
4445 | napi_enable(&q_vector->napi); | ||
4446 | } | ||
4443 | } | 4447 | } |
4444 | 4448 | ||
4445 | /** | 4449 | /** |
@@ -4453,8 +4457,12 @@ static void i40e_napi_disable_all(struct i40e_vsi *vsi) | |||
4453 | if (!vsi->netdev) | 4457 | if (!vsi->netdev) |
4454 | return; | 4458 | return; |
4455 | 4459 | ||
4456 | for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) | 4460 | for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++) { |
4457 | napi_disable(&vsi->q_vectors[q_idx]->napi); | 4461 | struct i40e_q_vector *q_vector = vsi->q_vectors[q_idx]; |
4462 | |||
4463 | if (q_vector->rx.ring || q_vector->tx.ring) | ||
4464 | napi_disable(&q_vector->napi); | ||
4465 | } | ||
4458 | } | 4466 | } |
4459 | 4467 | ||
4460 | /** | 4468 | /** |
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c index 55957246c0e8..b5d5519542e8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c | |||
@@ -294,7 +294,7 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev, | |||
294 | struct netdev_notifier_changeupper_info *info) | 294 | struct netdev_notifier_changeupper_info *info) |
295 | { | 295 | { |
296 | struct net_device *upper = info->upper_dev, *ndev_tmp; | 296 | struct net_device *upper = info->upper_dev, *ndev_tmp; |
297 | struct netdev_lag_upper_info *lag_upper_info; | 297 | struct netdev_lag_upper_info *lag_upper_info = NULL; |
298 | bool is_bonded; | 298 | bool is_bonded; |
299 | int bond_status = 0; | 299 | int bond_status = 0; |
300 | int num_slaves = 0; | 300 | int num_slaves = 0; |
@@ -303,7 +303,8 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev, | |||
303 | if (!netif_is_lag_master(upper)) | 303 | if (!netif_is_lag_master(upper)) |
304 | return 0; | 304 | return 0; |
305 | 305 | ||
306 | lag_upper_info = info->upper_info; | 306 | if (info->linking) |
307 | lag_upper_info = info->upper_info; | ||
307 | 308 | ||
308 | /* The event may still be of interest if the slave does not belong to | 309 | /* The event may still be of interest if the slave does not belong to |
309 | * us, but is enslaved to a master which has one or more of our netdevs | 310 | * us, but is enslaved to a master which has one or more of our netdevs |
diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c index 06c9f4100cb9..6ad44be08b33 100644 --- a/drivers/net/ethernet/moxa/moxart_ether.c +++ b/drivers/net/ethernet/moxa/moxart_ether.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/of_irq.h> | 25 | #include <linux/of_irq.h> |
26 | #include <linux/crc32.h> | 26 | #include <linux/crc32.h> |
27 | #include <linux/crc32c.h> | 27 | #include <linux/crc32c.h> |
28 | #include <linux/circ_buf.h> | ||
28 | 29 | ||
29 | #include "moxart_ether.h" | 30 | #include "moxart_ether.h" |
30 | 31 | ||
@@ -278,6 +279,13 @@ rx_next: | |||
278 | return rx; | 279 | return rx; |
279 | } | 280 | } |
280 | 281 | ||
282 | static int moxart_tx_queue_space(struct net_device *ndev) | ||
283 | { | ||
284 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | ||
285 | |||
286 | return CIRC_SPACE(priv->tx_head, priv->tx_tail, TX_DESC_NUM); | ||
287 | } | ||
288 | |||
281 | static void moxart_tx_finished(struct net_device *ndev) | 289 | static void moxart_tx_finished(struct net_device *ndev) |
282 | { | 290 | { |
283 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | 291 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); |
@@ -297,6 +305,9 @@ static void moxart_tx_finished(struct net_device *ndev) | |||
297 | tx_tail = TX_NEXT(tx_tail); | 305 | tx_tail = TX_NEXT(tx_tail); |
298 | } | 306 | } |
299 | priv->tx_tail = tx_tail; | 307 | priv->tx_tail = tx_tail; |
308 | if (netif_queue_stopped(ndev) && | ||
309 | moxart_tx_queue_space(ndev) >= TX_WAKE_THRESHOLD) | ||
310 | netif_wake_queue(ndev); | ||
300 | } | 311 | } |
301 | 312 | ||
302 | static irqreturn_t moxart_mac_interrupt(int irq, void *dev_id) | 313 | static irqreturn_t moxart_mac_interrupt(int irq, void *dev_id) |
@@ -324,13 +335,18 @@ static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
324 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); | 335 | struct moxart_mac_priv_t *priv = netdev_priv(ndev); |
325 | void *desc; | 336 | void *desc; |
326 | unsigned int len; | 337 | unsigned int len; |
327 | unsigned int tx_head = priv->tx_head; | 338 | unsigned int tx_head; |
328 | u32 txdes1; | 339 | u32 txdes1; |
329 | int ret = NETDEV_TX_BUSY; | 340 | int ret = NETDEV_TX_BUSY; |
330 | 341 | ||
342 | spin_lock_irq(&priv->txlock); | ||
343 | |||
344 | tx_head = priv->tx_head; | ||
331 | desc = priv->tx_desc_base + (TX_REG_DESC_SIZE * tx_head); | 345 | desc = priv->tx_desc_base + (TX_REG_DESC_SIZE * tx_head); |
332 | 346 | ||
333 | spin_lock_irq(&priv->txlock); | 347 | if (moxart_tx_queue_space(ndev) == 1) |
348 | netif_stop_queue(ndev); | ||
349 | |||
334 | if (moxart_desc_read(desc + TX_REG_OFFSET_DESC0) & TX_DESC0_DMA_OWN) { | 350 | if (moxart_desc_read(desc + TX_REG_OFFSET_DESC0) & TX_DESC0_DMA_OWN) { |
335 | net_dbg_ratelimited("no TX space for packet\n"); | 351 | net_dbg_ratelimited("no TX space for packet\n"); |
336 | priv->stats.tx_dropped++; | 352 | priv->stats.tx_dropped++; |
diff --git a/drivers/net/ethernet/moxa/moxart_ether.h b/drivers/net/ethernet/moxa/moxart_ether.h index 93a9563ac7c6..afc32ec998c0 100644 --- a/drivers/net/ethernet/moxa/moxart_ether.h +++ b/drivers/net/ethernet/moxa/moxart_ether.h | |||
@@ -59,6 +59,7 @@ | |||
59 | #define TX_NEXT(N) (((N) + 1) & (TX_DESC_NUM_MASK)) | 59 | #define TX_NEXT(N) (((N) + 1) & (TX_DESC_NUM_MASK)) |
60 | #define TX_BUF_SIZE 1600 | 60 | #define TX_BUF_SIZE 1600 |
61 | #define TX_BUF_SIZE_MAX (TX_DESC1_BUF_SIZE_MASK+1) | 61 | #define TX_BUF_SIZE_MAX (TX_DESC1_BUF_SIZE_MASK+1) |
62 | #define TX_WAKE_THRESHOLD 16 | ||
62 | 63 | ||
63 | #define RX_DESC_NUM 64 | 64 | #define RX_DESC_NUM 64 |
64 | #define RX_DESC_NUM_MASK (RX_DESC_NUM-1) | 65 | #define RX_DESC_NUM_MASK (RX_DESC_NUM-1) |
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 9179a99563af..a41377e26c07 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c | |||
@@ -3275,9 +3275,10 @@ void nfp_net_netdev_clean(struct net_device *netdev) | |||
3275 | { | 3275 | { |
3276 | struct nfp_net *nn = netdev_priv(netdev); | 3276 | struct nfp_net *nn = netdev_priv(netdev); |
3277 | 3277 | ||
3278 | unregister_netdev(nn->netdev); | ||
3279 | |||
3278 | if (nn->xdp_prog) | 3280 | if (nn->xdp_prog) |
3279 | bpf_prog_put(nn->xdp_prog); | 3281 | bpf_prog_put(nn->xdp_prog); |
3280 | if (nn->bpf_offload_xdp) | 3282 | if (nn->bpf_offload_xdp) |
3281 | nfp_net_xdp_offload(nn, NULL); | 3283 | nfp_net_xdp_offload(nn, NULL); |
3282 | unregister_netdev(nn->netdev); | ||
3283 | } | 3284 | } |
diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 7cd76b6b5cb9..2ae852454780 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c | |||
@@ -2216,18 +2216,15 @@ static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port, | |||
2216 | { | 2216 | { |
2217 | bool want[OFDPA_CTRL_MAX] = { 0, }; | 2217 | bool want[OFDPA_CTRL_MAX] = { 0, }; |
2218 | bool prev_ctrls[OFDPA_CTRL_MAX]; | 2218 | bool prev_ctrls[OFDPA_CTRL_MAX]; |
2219 | u8 uninitialized_var(prev_state); | 2219 | u8 prev_state; |
2220 | int err; | 2220 | int err; |
2221 | int i; | 2221 | int i; |
2222 | 2222 | ||
2223 | if (switchdev_trans_ph_prepare(trans)) { | 2223 | prev_state = ofdpa_port->stp_state; |
2224 | memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls)); | 2224 | if (prev_state == state) |
2225 | prev_state = ofdpa_port->stp_state; | ||
2226 | } | ||
2227 | |||
2228 | if (ofdpa_port->stp_state == state) | ||
2229 | return 0; | 2225 | return 0; |
2230 | 2226 | ||
2227 | memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls)); | ||
2231 | ofdpa_port->stp_state = state; | 2228 | ofdpa_port->stp_state = state; |
2232 | 2229 | ||
2233 | switch (state) { | 2230 | switch (state) { |
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 9f3d9c67e3fe..fa674a8bda0c 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -1267,6 +1267,7 @@ static void soft_reset_slave(struct cpsw_slave *slave) | |||
1267 | static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) | 1267 | static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) |
1268 | { | 1268 | { |
1269 | u32 slave_port; | 1269 | u32 slave_port; |
1270 | struct phy_device *phy; | ||
1270 | struct cpsw_common *cpsw = priv->cpsw; | 1271 | struct cpsw_common *cpsw = priv->cpsw; |
1271 | 1272 | ||
1272 | soft_reset_slave(slave); | 1273 | soft_reset_slave(slave); |
@@ -1300,27 +1301,28 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) | |||
1300 | 1 << slave_port, 0, 0, ALE_MCAST_FWD_2); | 1301 | 1 << slave_port, 0, 0, ALE_MCAST_FWD_2); |
1301 | 1302 | ||
1302 | if (slave->data->phy_node) { | 1303 | if (slave->data->phy_node) { |
1303 | slave->phy = of_phy_connect(priv->ndev, slave->data->phy_node, | 1304 | phy = of_phy_connect(priv->ndev, slave->data->phy_node, |
1304 | &cpsw_adjust_link, 0, slave->data->phy_if); | 1305 | &cpsw_adjust_link, 0, slave->data->phy_if); |
1305 | if (!slave->phy) { | 1306 | if (!phy) { |
1306 | dev_err(priv->dev, "phy \"%s\" not found on slave %d\n", | 1307 | dev_err(priv->dev, "phy \"%s\" not found on slave %d\n", |
1307 | slave->data->phy_node->full_name, | 1308 | slave->data->phy_node->full_name, |
1308 | slave->slave_num); | 1309 | slave->slave_num); |
1309 | return; | 1310 | return; |
1310 | } | 1311 | } |
1311 | } else { | 1312 | } else { |
1312 | slave->phy = phy_connect(priv->ndev, slave->data->phy_id, | 1313 | phy = phy_connect(priv->ndev, slave->data->phy_id, |
1313 | &cpsw_adjust_link, slave->data->phy_if); | 1314 | &cpsw_adjust_link, slave->data->phy_if); |
1314 | if (IS_ERR(slave->phy)) { | 1315 | if (IS_ERR(phy)) { |
1315 | dev_err(priv->dev, | 1316 | dev_err(priv->dev, |
1316 | "phy \"%s\" not found on slave %d, err %ld\n", | 1317 | "phy \"%s\" not found on slave %d, err %ld\n", |
1317 | slave->data->phy_id, slave->slave_num, | 1318 | slave->data->phy_id, slave->slave_num, |
1318 | PTR_ERR(slave->phy)); | 1319 | PTR_ERR(phy)); |
1319 | slave->phy = NULL; | ||
1320 | return; | 1320 | return; |
1321 | } | 1321 | } |
1322 | } | 1322 | } |
1323 | 1323 | ||
1324 | slave->phy = phy; | ||
1325 | |||
1324 | phy_attached_info(slave->phy); | 1326 | phy_attached_info(slave->phy); |
1325 | 1327 | ||
1326 | phy_start(slave->phy); | 1328 | phy_start(slave->phy); |
@@ -1817,6 +1819,8 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev) | |||
1817 | } | 1819 | } |
1818 | 1820 | ||
1819 | cpsw_intr_enable(cpsw); | 1821 | cpsw_intr_enable(cpsw); |
1822 | netif_trans_update(ndev); | ||
1823 | netif_tx_wake_all_queues(ndev); | ||
1820 | } | 1824 | } |
1821 | 1825 | ||
1822 | static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) | 1826 | static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) |
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index ffedad2a360a..15b920086251 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c | |||
@@ -418,8 +418,9 @@ static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr | |||
418 | memset(rd, 0, sizeof(*rd)); | 418 | memset(rd, 0, sizeof(*rd)); |
419 | rd->hw = hwmap + i; | 419 | rd->hw = hwmap + i; |
420 | rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA); | 420 | rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA); |
421 | if (rd->buf == NULL || | 421 | if (rd->buf) |
422 | !(busaddr = pci_map_single(pdev, rd->buf, len, dir))) { | 422 | busaddr = pci_map_single(pdev, rd->buf, len, dir); |
423 | if (rd->buf == NULL || pci_dma_mapping_error(pdev, busaddr)) { | ||
423 | if (rd->buf) { | 424 | if (rd->buf) { |
424 | net_err_ratelimited("%s: failed to create PCI-MAP for %p\n", | 425 | net_err_ratelimited("%s: failed to create PCI-MAP for %p\n", |
425 | __func__, rd->buf); | 426 | __func__, rd->buf); |
@@ -430,8 +431,7 @@ static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr | |||
430 | rd = r->rd + j; | 431 | rd = r->rd + j; |
431 | busaddr = rd_get_addr(rd); | 432 | busaddr = rd_get_addr(rd); |
432 | rd_set_addr_status(rd, 0, 0); | 433 | rd_set_addr_status(rd, 0, 0); |
433 | if (busaddr) | 434 | pci_unmap_single(pdev, busaddr, len, dir); |
434 | pci_unmap_single(pdev, busaddr, len, dir); | ||
435 | kfree(rd->buf); | 435 | kfree(rd->buf); |
436 | rd->buf = NULL; | 436 | rd->buf = NULL; |
437 | } | 437 | } |
diff --git a/drivers/net/phy/mdio-boardinfo.c b/drivers/net/phy/mdio-boardinfo.c index 6b988f77da08..61941e29daae 100644 --- a/drivers/net/phy/mdio-boardinfo.c +++ b/drivers/net/phy/mdio-boardinfo.c | |||
@@ -84,3 +84,4 @@ int mdiobus_register_board_info(const struct mdio_board_info *info, | |||
84 | 84 | ||
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | EXPORT_SYMBOL(mdiobus_register_board_info); | ||
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 1be69d8bc909..a2bfc82e95d7 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -681,7 +681,7 @@ void phy_stop_machine(struct phy_device *phydev) | |||
681 | cancel_delayed_work_sync(&phydev->state_queue); | 681 | cancel_delayed_work_sync(&phydev->state_queue); |
682 | 682 | ||
683 | mutex_lock(&phydev->lock); | 683 | mutex_lock(&phydev->lock); |
684 | if (phydev->state > PHY_UP) | 684 | if (phydev->state > PHY_UP && phydev->state != PHY_HALTED) |
685 | phydev->state = PHY_UP; | 685 | phydev->state = PHY_UP; |
686 | mutex_unlock(&phydev->lock); | 686 | mutex_unlock(&phydev->lock); |
687 | } | 687 | } |
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index f5552aaaa77a..f3ae88fdf332 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c | |||
@@ -532,6 +532,7 @@ static const struct driver_info wwan_info = { | |||
532 | #define LENOVO_VENDOR_ID 0x17ef | 532 | #define LENOVO_VENDOR_ID 0x17ef |
533 | #define NVIDIA_VENDOR_ID 0x0955 | 533 | #define NVIDIA_VENDOR_ID 0x0955 |
534 | #define HP_VENDOR_ID 0x03f0 | 534 | #define HP_VENDOR_ID 0x03f0 |
535 | #define MICROSOFT_VENDOR_ID 0x045e | ||
535 | 536 | ||
536 | static const struct usb_device_id products[] = { | 537 | static const struct usb_device_id products[] = { |
537 | /* BLACKLIST !! | 538 | /* BLACKLIST !! |
@@ -761,6 +762,20 @@ static const struct usb_device_id products[] = { | |||
761 | .driver_info = 0, | 762 | .driver_info = 0, |
762 | }, | 763 | }, |
763 | 764 | ||
765 | /* Microsoft Surface 2 dock (based on Realtek RTL8152) */ | ||
766 | { | ||
767 | USB_DEVICE_AND_INTERFACE_INFO(MICROSOFT_VENDOR_ID, 0x07ab, USB_CLASS_COMM, | ||
768 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), | ||
769 | .driver_info = 0, | ||
770 | }, | ||
771 | |||
772 | /* Microsoft Surface 3 dock (based on Realtek RTL8153) */ | ||
773 | { | ||
774 | USB_DEVICE_AND_INTERFACE_INFO(MICROSOFT_VENDOR_ID, 0x07c6, USB_CLASS_COMM, | ||
775 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), | ||
776 | .driver_info = 0, | ||
777 | }, | ||
778 | |||
764 | /* WHITELIST!!! | 779 | /* WHITELIST!!! |
765 | * | 780 | * |
766 | * CDC Ether uses two interfaces, not necessarily consecutive. | 781 | * CDC Ether uses two interfaces, not necessarily consecutive. |
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0b1b9188625d..07f788c49d57 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c | |||
@@ -517,6 +517,7 @@ enum rtl8152_flags { | |||
517 | 517 | ||
518 | /* Define these values to match your device */ | 518 | /* Define these values to match your device */ |
519 | #define VENDOR_ID_REALTEK 0x0bda | 519 | #define VENDOR_ID_REALTEK 0x0bda |
520 | #define VENDOR_ID_MICROSOFT 0x045e | ||
520 | #define VENDOR_ID_SAMSUNG 0x04e8 | 521 | #define VENDOR_ID_SAMSUNG 0x04e8 |
521 | #define VENDOR_ID_LENOVO 0x17ef | 522 | #define VENDOR_ID_LENOVO 0x17ef |
522 | #define VENDOR_ID_NVIDIA 0x0955 | 523 | #define VENDOR_ID_NVIDIA 0x0955 |
@@ -1294,6 +1295,7 @@ static void intr_callback(struct urb *urb) | |||
1294 | } | 1295 | } |
1295 | } else { | 1296 | } else { |
1296 | if (netif_carrier_ok(tp->netdev)) { | 1297 | if (netif_carrier_ok(tp->netdev)) { |
1298 | netif_stop_queue(tp->netdev); | ||
1297 | set_bit(RTL8152_LINK_CHG, &tp->flags); | 1299 | set_bit(RTL8152_LINK_CHG, &tp->flags); |
1298 | schedule_delayed_work(&tp->schedule, 0); | 1300 | schedule_delayed_work(&tp->schedule, 0); |
1299 | } | 1301 | } |
@@ -3169,6 +3171,9 @@ static void set_carrier(struct r8152 *tp) | |||
3169 | napi_enable(&tp->napi); | 3171 | napi_enable(&tp->napi); |
3170 | netif_wake_queue(netdev); | 3172 | netif_wake_queue(netdev); |
3171 | netif_info(tp, link, netdev, "carrier on\n"); | 3173 | netif_info(tp, link, netdev, "carrier on\n"); |
3174 | } else if (netif_queue_stopped(netdev) && | ||
3175 | skb_queue_len(&tp->tx_queue) < tp->tx_qlen) { | ||
3176 | netif_wake_queue(netdev); | ||
3172 | } | 3177 | } |
3173 | } else { | 3178 | } else { |
3174 | if (netif_carrier_ok(netdev)) { | 3179 | if (netif_carrier_ok(netdev)) { |
@@ -3702,8 +3707,18 @@ static int rtl8152_resume(struct usb_interface *intf) | |||
3702 | tp->rtl_ops.autosuspend_en(tp, false); | 3707 | tp->rtl_ops.autosuspend_en(tp, false); |
3703 | napi_disable(&tp->napi); | 3708 | napi_disable(&tp->napi); |
3704 | set_bit(WORK_ENABLE, &tp->flags); | 3709 | set_bit(WORK_ENABLE, &tp->flags); |
3705 | if (netif_carrier_ok(tp->netdev)) | 3710 | |
3706 | rtl_start_rx(tp); | 3711 | if (netif_carrier_ok(tp->netdev)) { |
3712 | if (rtl8152_get_speed(tp) & LINK_STATUS) { | ||
3713 | rtl_start_rx(tp); | ||
3714 | } else { | ||
3715 | netif_carrier_off(tp->netdev); | ||
3716 | tp->rtl_ops.disable(tp); | ||
3717 | netif_info(tp, link, tp->netdev, | ||
3718 | "linking down\n"); | ||
3719 | } | ||
3720 | } | ||
3721 | |||
3707 | napi_enable(&tp->napi); | 3722 | napi_enable(&tp->napi); |
3708 | clear_bit(SELECTIVE_SUSPEND, &tp->flags); | 3723 | clear_bit(SELECTIVE_SUSPEND, &tp->flags); |
3709 | smp_mb__after_atomic(); | 3724 | smp_mb__after_atomic(); |
@@ -4507,6 +4522,8 @@ static void rtl8152_disconnect(struct usb_interface *intf) | |||
4507 | static struct usb_device_id rtl8152_table[] = { | 4522 | static struct usb_device_id rtl8152_table[] = { |
4508 | {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)}, | 4523 | {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)}, |
4509 | {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, | 4524 | {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, |
4525 | {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)}, | ||
4526 | {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6)}, | ||
4510 | {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, | 4527 | {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, |
4511 | {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, | 4528 | {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, |
4512 | {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062)}, | 4529 | {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062)}, |
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index de19c7c92bc6..85d949e03f79 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | |||
@@ -2238,14 +2238,16 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) | |||
2238 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); | 2238 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); |
2239 | struct brcmf_p2p_info *p2p = &cfg->p2p; | 2239 | struct brcmf_p2p_info *p2p = &cfg->p2p; |
2240 | struct brcmf_cfg80211_vif *vif; | 2240 | struct brcmf_cfg80211_vif *vif; |
2241 | enum nl80211_iftype iftype; | ||
2241 | bool wait_for_disable = false; | 2242 | bool wait_for_disable = false; |
2242 | int err; | 2243 | int err; |
2243 | 2244 | ||
2244 | brcmf_dbg(TRACE, "delete P2P vif\n"); | 2245 | brcmf_dbg(TRACE, "delete P2P vif\n"); |
2245 | vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); | 2246 | vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); |
2246 | 2247 | ||
2248 | iftype = vif->wdev.iftype; | ||
2247 | brcmf_cfg80211_arm_vif_event(cfg, vif); | 2249 | brcmf_cfg80211_arm_vif_event(cfg, vif); |
2248 | switch (vif->wdev.iftype) { | 2250 | switch (iftype) { |
2249 | case NL80211_IFTYPE_P2P_CLIENT: | 2251 | case NL80211_IFTYPE_P2P_CLIENT: |
2250 | if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state)) | 2252 | if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state)) |
2251 | wait_for_disable = true; | 2253 | wait_for_disable = true; |
@@ -2275,7 +2277,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) | |||
2275 | BRCMF_P2P_DISABLE_TIMEOUT); | 2277 | BRCMF_P2P_DISABLE_TIMEOUT); |
2276 | 2278 | ||
2277 | err = 0; | 2279 | err = 0; |
2278 | if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) { | 2280 | if (iftype != NL80211_IFTYPE_P2P_DEVICE) { |
2279 | brcmf_vif_clear_mgmt_ies(vif); | 2281 | brcmf_vif_clear_mgmt_ies(vif); |
2280 | err = brcmf_p2p_release_p2p_if(vif); | 2282 | err = brcmf_p2p_release_p2p_if(vif); |
2281 | } | 2283 | } |
@@ -2291,7 +2293,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) | |||
2291 | brcmf_remove_interface(vif->ifp, true); | 2293 | brcmf_remove_interface(vif->ifp, true); |
2292 | 2294 | ||
2293 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | 2295 | brcmf_cfg80211_arm_vif_event(cfg, NULL); |
2294 | if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) | 2296 | if (iftype != NL80211_IFTYPE_P2P_DEVICE) |
2295 | p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; | 2297 | p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; |
2296 | 2298 | ||
2297 | return err; | 2299 | return err; |
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index a260cd503200..077bfd8f4c0c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | |||
@@ -1056,6 +1056,8 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, | |||
1056 | 1056 | ||
1057 | if (ret) | 1057 | if (ret) |
1058 | return ret; | 1058 | return ret; |
1059 | if (count == 0) | ||
1060 | return 0; | ||
1059 | 1061 | ||
1060 | iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, buf, | 1062 | iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, buf, |
1061 | (count - 1), NULL); | 1063 | (count - 1), NULL); |
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 99132ea16ede..c5734e1a02d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | |||
@@ -216,7 +216,8 @@ u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) | |||
216 | qmask |= BIT(vif->hw_queue[ac]); | 216 | qmask |= BIT(vif->hw_queue[ac]); |
217 | } | 217 | } |
218 | 218 | ||
219 | if (vif->type == NL80211_IFTYPE_AP) | 219 | if (vif->type == NL80211_IFTYPE_AP || |
220 | vif->type == NL80211_IFTYPE_ADHOC) | ||
220 | qmask |= BIT(vif->cab_queue); | 221 | qmask |= BIT(vif->cab_queue); |
221 | 222 | ||
222 | return qmask; | 223 | return qmask; |
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 6927caecd48e..486dcceed17a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | |||
@@ -2401,7 +2401,7 @@ void iwl_mvm_sta_pm_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) | |||
2401 | return; | 2401 | return; |
2402 | 2402 | ||
2403 | rcu_read_lock(); | 2403 | rcu_read_lock(); |
2404 | sta = mvm->fw_id_to_mac_id[notif->sta_id]; | 2404 | sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]); |
2405 | if (WARN_ON(IS_ERR_OR_NULL(sta))) { | 2405 | if (WARN_ON(IS_ERR_OR_NULL(sta))) { |
2406 | rcu_read_unlock(); | 2406 | rcu_read_unlock(); |
2407 | return; | 2407 | return; |
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b51a2853cc80..9d28db7f56aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c | |||
@@ -1806,7 +1806,8 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1806 | iwl_mvm_get_wd_timeout(mvm, vif, false, false); | 1806 | iwl_mvm_get_wd_timeout(mvm, vif, false, false); |
1807 | int queue; | 1807 | int queue; |
1808 | 1808 | ||
1809 | if (vif->type == NL80211_IFTYPE_AP) | 1809 | if (vif->type == NL80211_IFTYPE_AP || |
1810 | vif->type == NL80211_IFTYPE_ADHOC) | ||
1810 | queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; | 1811 | queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; |
1811 | else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) | 1812 | else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) |
1812 | queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; | 1813 | queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; |
@@ -1837,7 +1838,8 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1837 | * enabled-cab_queue to the mask) | 1838 | * enabled-cab_queue to the mask) |
1838 | */ | 1839 | */ |
1839 | if (iwl_mvm_is_dqa_supported(mvm) && | 1840 | if (iwl_mvm_is_dqa_supported(mvm) && |
1840 | vif->type == NL80211_IFTYPE_AP) { | 1841 | (vif->type == NL80211_IFTYPE_AP || |
1842 | vif->type == NL80211_IFTYPE_ADHOC)) { | ||
1841 | struct iwl_trans_txq_scd_cfg cfg = { | 1843 | struct iwl_trans_txq_scd_cfg cfg = { |
1842 | .fifo = IWL_MVM_TX_FIFO_MCAST, | 1844 | .fifo = IWL_MVM_TX_FIFO_MCAST, |
1843 | .sta_id = mvmvif->bcast_sta.sta_id, | 1845 | .sta_id = mvmvif->bcast_sta.sta_id, |
@@ -1862,7 +1864,8 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, | |||
1862 | 1864 | ||
1863 | lockdep_assert_held(&mvm->mutex); | 1865 | lockdep_assert_held(&mvm->mutex); |
1864 | 1866 | ||
1865 | if (vif->type == NL80211_IFTYPE_AP) | 1867 | if (vif->type == NL80211_IFTYPE_AP || |
1868 | vif->type == NL80211_IFTYPE_ADHOC) | ||
1866 | iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue, | 1869 | iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue, |
1867 | IWL_MAX_TID_COUNT, 0); | 1870 | IWL_MAX_TID_COUNT, 0); |
1868 | 1871 | ||
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 3f37075f4cde..1ba0a6f55503 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c | |||
@@ -506,6 +506,7 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, | |||
506 | 506 | ||
507 | switch (info->control.vif->type) { | 507 | switch (info->control.vif->type) { |
508 | case NL80211_IFTYPE_AP: | 508 | case NL80211_IFTYPE_AP: |
509 | case NL80211_IFTYPE_ADHOC: | ||
509 | /* | 510 | /* |
510 | * Handle legacy hostapd as well, where station may be added | 511 | * Handle legacy hostapd as well, where station may be added |
511 | * only after assoc. Take care of the case where we send a | 512 | * only after assoc. Take care of the case where we send a |
@@ -517,7 +518,8 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, | |||
517 | if (info->hw_queue == info->control.vif->cab_queue) | 518 | if (info->hw_queue == info->control.vif->cab_queue) |
518 | return info->hw_queue; | 519 | return info->hw_queue; |
519 | 520 | ||
520 | WARN_ONCE(1, "fc=0x%02x", le16_to_cpu(fc)); | 521 | WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC, |
522 | "fc=0x%02x", le16_to_cpu(fc)); | ||
521 | return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; | 523 | return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; |
522 | case NL80211_IFTYPE_P2P_DEVICE: | 524 | case NL80211_IFTYPE_P2P_DEVICE: |
523 | if (ieee80211_is_mgmt(fc)) | 525 | if (ieee80211_is_mgmt(fc)) |
@@ -584,7 +586,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) | |||
584 | iwl_mvm_vif_from_mac80211(info.control.vif); | 586 | iwl_mvm_vif_from_mac80211(info.control.vif); |
585 | 587 | ||
586 | if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE || | 588 | if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE || |
587 | info.control.vif->type == NL80211_IFTYPE_AP) { | 589 | info.control.vif->type == NL80211_IFTYPE_AP || |
590 | info.control.vif->type == NL80211_IFTYPE_ADHOC) { | ||
588 | sta_id = mvmvif->bcast_sta.sta_id; | 591 | sta_id = mvmvif->bcast_sta.sta_id; |
589 | queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, | 592 | queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, |
590 | hdr->frame_control); | 593 | hdr->frame_control); |
diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index caea350f05aa..bdc379178e87 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c | |||
@@ -1742,12 +1742,14 @@ void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val) | |||
1742 | unsigned long flags; | 1742 | unsigned long flags; |
1743 | struct rtl_c2hcmd *c2hcmd; | 1743 | struct rtl_c2hcmd *c2hcmd; |
1744 | 1744 | ||
1745 | c2hcmd = kmalloc(sizeof(*c2hcmd), GFP_KERNEL); | 1745 | c2hcmd = kmalloc(sizeof(*c2hcmd), |
1746 | in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); | ||
1746 | 1747 | ||
1747 | if (!c2hcmd) | 1748 | if (!c2hcmd) |
1748 | goto label_err; | 1749 | goto label_err; |
1749 | 1750 | ||
1750 | c2hcmd->val = kmalloc(len, GFP_KERNEL); | 1751 | c2hcmd->val = kmalloc(len, |
1752 | in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); | ||
1751 | 1753 | ||
1752 | if (!c2hcmd->val) | 1754 | if (!c2hcmd->val) |
1753 | goto label_err2; | 1755 | goto label_err2; |
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index e7addea8741b..d9561e39c3b2 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -961,7 +961,8 @@ int qeth_bridgeport_query_ports(struct qeth_card *card, | |||
961 | int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role); | 961 | int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role); |
962 | int qeth_bridgeport_an_set(struct qeth_card *card, int enable); | 962 | int qeth_bridgeport_an_set(struct qeth_card *card, int enable); |
963 | int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); | 963 | int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); |
964 | int qeth_get_elements_no(struct qeth_card *, struct sk_buff *, int); | 964 | int qeth_get_elements_no(struct qeth_card *card, struct sk_buff *skb, |
965 | int extra_elems, int data_offset); | ||
965 | int qeth_get_elements_for_frags(struct sk_buff *); | 966 | int qeth_get_elements_for_frags(struct sk_buff *); |
966 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, | 967 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, |
967 | struct sk_buff *, struct qeth_hdr *, int, int, int); | 968 | struct sk_buff *, struct qeth_hdr *, int, int, int); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 315d8a2db7c0..9a5f99ccb122 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -3837,6 +3837,7 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); | |||
3837 | * @card: qeth card structure, to check max. elems. | 3837 | * @card: qeth card structure, to check max. elems. |
3838 | * @skb: SKB address | 3838 | * @skb: SKB address |
3839 | * @extra_elems: extra elems needed, to check against max. | 3839 | * @extra_elems: extra elems needed, to check against max. |
3840 | * @data_offset: range starts at skb->data + data_offset | ||
3840 | * | 3841 | * |
3841 | * Returns the number of pages, and thus QDIO buffer elements, needed to cover | 3842 | * Returns the number of pages, and thus QDIO buffer elements, needed to cover |
3842 | * skb data, including linear part and fragments. Checks if the result plus | 3843 | * skb data, including linear part and fragments. Checks if the result plus |
@@ -3844,10 +3845,10 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); | |||
3844 | * Note: extra_elems is not included in the returned result. | 3845 | * Note: extra_elems is not included in the returned result. |
3845 | */ | 3846 | */ |
3846 | int qeth_get_elements_no(struct qeth_card *card, | 3847 | int qeth_get_elements_no(struct qeth_card *card, |
3847 | struct sk_buff *skb, int extra_elems) | 3848 | struct sk_buff *skb, int extra_elems, int data_offset) |
3848 | { | 3849 | { |
3849 | int elements = qeth_get_elements_for_range( | 3850 | int elements = qeth_get_elements_for_range( |
3850 | (addr_t)skb->data, | 3851 | (addr_t)skb->data + data_offset, |
3851 | (addr_t)skb->data + skb_headlen(skb)) + | 3852 | (addr_t)skb->data + skb_headlen(skb)) + |
3852 | qeth_get_elements_for_frags(skb); | 3853 | qeth_get_elements_for_frags(skb); |
3853 | 3854 | ||
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index bea483307618..af4e6a639fec 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -849,7 +849,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
849 | * chaining we can not send long frag lists | 849 | * chaining we can not send long frag lists |
850 | */ | 850 | */ |
851 | if ((card->info.type != QETH_CARD_TYPE_IQD) && | 851 | if ((card->info.type != QETH_CARD_TYPE_IQD) && |
852 | !qeth_get_elements_no(card, new_skb, 0)) { | 852 | !qeth_get_elements_no(card, new_skb, 0, 0)) { |
853 | int lin_rc = skb_linearize(new_skb); | 853 | int lin_rc = skb_linearize(new_skb); |
854 | 854 | ||
855 | if (card->options.performance_stats) { | 855 | if (card->options.performance_stats) { |
@@ -894,7 +894,8 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
894 | } | 894 | } |
895 | } | 895 | } |
896 | 896 | ||
897 | elements = qeth_get_elements_no(card, new_skb, elements_needed); | 897 | elements = qeth_get_elements_no(card, new_skb, elements_needed, |
898 | (data_offset > 0) ? data_offset : 0); | ||
898 | if (!elements) { | 899 | if (!elements) { |
899 | if (data_offset >= 0) | 900 | if (data_offset >= 0) |
900 | kmem_cache_free(qeth_core_header_cache, hdr); | 901 | kmem_cache_free(qeth_core_header_cache, hdr); |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 06d0addcc058..653f0fb76573 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -2609,17 +2609,13 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card, | |||
2609 | char daddr[16]; | 2609 | char daddr[16]; |
2610 | struct af_iucv_trans_hdr *iucv_hdr; | 2610 | struct af_iucv_trans_hdr *iucv_hdr; |
2611 | 2611 | ||
2612 | skb_pull(skb, 14); | ||
2613 | card->dev->header_ops->create(skb, card->dev, 0, | ||
2614 | card->dev->dev_addr, card->dev->dev_addr, | ||
2615 | card->dev->addr_len); | ||
2616 | skb_pull(skb, 14); | ||
2617 | iucv_hdr = (struct af_iucv_trans_hdr *)skb->data; | ||
2618 | memset(hdr, 0, sizeof(struct qeth_hdr)); | 2612 | memset(hdr, 0, sizeof(struct qeth_hdr)); |
2619 | hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; | 2613 | hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; |
2620 | hdr->hdr.l3.ext_flags = 0; | 2614 | hdr->hdr.l3.ext_flags = 0; |
2621 | hdr->hdr.l3.length = skb->len; | 2615 | hdr->hdr.l3.length = skb->len - ETH_HLEN; |
2622 | hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; | 2616 | hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; |
2617 | |||
2618 | iucv_hdr = (struct af_iucv_trans_hdr *) (skb->data + ETH_HLEN); | ||
2623 | memset(daddr, 0, sizeof(daddr)); | 2619 | memset(daddr, 0, sizeof(daddr)); |
2624 | daddr[0] = 0xfe; | 2620 | daddr[0] = 0xfe; |
2625 | daddr[1] = 0x80; | 2621 | daddr[1] = 0x80; |
@@ -2823,10 +2819,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2823 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2819 | if ((card->info.type == QETH_CARD_TYPE_IQD) && |
2824 | !skb_is_nonlinear(skb)) { | 2820 | !skb_is_nonlinear(skb)) { |
2825 | new_skb = skb; | 2821 | new_skb = skb; |
2826 | if (new_skb->protocol == ETH_P_AF_IUCV) | 2822 | data_offset = ETH_HLEN; |
2827 | data_offset = 0; | ||
2828 | else | ||
2829 | data_offset = ETH_HLEN; | ||
2830 | hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); | 2823 | hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); |
2831 | if (!hdr) | 2824 | if (!hdr) |
2832 | goto tx_drop; | 2825 | goto tx_drop; |
@@ -2867,7 +2860,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2867 | */ | 2860 | */ |
2868 | if ((card->info.type != QETH_CARD_TYPE_IQD) && | 2861 | if ((card->info.type != QETH_CARD_TYPE_IQD) && |
2869 | ((use_tso && !qeth_l3_get_elements_no_tso(card, new_skb, 1)) || | 2862 | ((use_tso && !qeth_l3_get_elements_no_tso(card, new_skb, 1)) || |
2870 | (!use_tso && !qeth_get_elements_no(card, new_skb, 0)))) { | 2863 | (!use_tso && !qeth_get_elements_no(card, new_skb, 0, 0)))) { |
2871 | int lin_rc = skb_linearize(new_skb); | 2864 | int lin_rc = skb_linearize(new_skb); |
2872 | 2865 | ||
2873 | if (card->options.performance_stats) { | 2866 | if (card->options.performance_stats) { |
@@ -2909,7 +2902,8 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2909 | 2902 | ||
2910 | elements = use_tso ? | 2903 | elements = use_tso ? |
2911 | qeth_l3_get_elements_no_tso(card, new_skb, hdr_elements) : | 2904 | qeth_l3_get_elements_no_tso(card, new_skb, hdr_elements) : |
2912 | qeth_get_elements_no(card, new_skb, hdr_elements); | 2905 | qeth_get_elements_no(card, new_skb, hdr_elements, |
2906 | (data_offset > 0) ? data_offset : 0); | ||
2913 | if (!elements) { | 2907 | if (!elements) { |
2914 | if (data_offset >= 0) | 2908 | if (data_offset >= 0) |
2915 | kmem_cache_free(qeth_core_header_cache, hdr); | 2909 | kmem_cache_free(qeth_core_header_cache, hdr); |
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 1f71ee5ab518..069582ee5d7f 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h | |||
@@ -448,10 +448,9 @@ static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu) | |||
448 | return frag; | 448 | return frag; |
449 | } | 449 | } |
450 | 450 | ||
451 | static inline void sctp_assoc_pending_pmtu(struct sock *sk, struct sctp_association *asoc) | 451 | static inline void sctp_assoc_pending_pmtu(struct sctp_association *asoc) |
452 | { | 452 | { |
453 | 453 | sctp_assoc_sync_pmtu(asoc); | |
454 | sctp_assoc_sync_pmtu(sk, asoc); | ||
455 | asoc->pmtu_pending = 0; | 454 | asoc->pmtu_pending = 0; |
456 | } | 455 | } |
457 | 456 | ||
@@ -596,12 +595,23 @@ static inline void sctp_v4_map_v6(union sctp_addr *addr) | |||
596 | */ | 595 | */ |
597 | static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t) | 596 | static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t) |
598 | { | 597 | { |
599 | if (t->dst && (!dst_check(t->dst, t->dst_cookie) || | 598 | if (t->dst && !dst_check(t->dst, t->dst_cookie)) |
600 | t->pathmtu != max_t(size_t, SCTP_TRUNC4(dst_mtu(t->dst)), | ||
601 | SCTP_DEFAULT_MINSEGMENT))) | ||
602 | sctp_transport_dst_release(t); | 599 | sctp_transport_dst_release(t); |
603 | 600 | ||
604 | return t->dst; | 601 | return t->dst; |
605 | } | 602 | } |
606 | 603 | ||
604 | static inline bool sctp_transport_pmtu_check(struct sctp_transport *t) | ||
605 | { | ||
606 | __u32 pmtu = max_t(size_t, SCTP_TRUNC4(dst_mtu(t->dst)), | ||
607 | SCTP_DEFAULT_MINSEGMENT); | ||
608 | |||
609 | if (t->pathmtu == pmtu) | ||
610 | return true; | ||
611 | |||
612 | t->pathmtu = pmtu; | ||
613 | |||
614 | return false; | ||
615 | } | ||
616 | |||
607 | #endif /* __net_sctp_h__ */ | 617 | #endif /* __net_sctp_h__ */ |
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 592decebac75..138f8615acf0 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -377,7 +377,8 @@ typedef struct sctp_sender_hb_info { | |||
377 | __u64 hb_nonce; | 377 | __u64 hb_nonce; |
378 | } sctp_sender_hb_info_t; | 378 | } sctp_sender_hb_info_t; |
379 | 379 | ||
380 | struct sctp_stream *sctp_stream_new(__u16 incnt, __u16 outcnt, gfp_t gfp); | 380 | int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp); |
381 | int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp); | ||
381 | void sctp_stream_free(struct sctp_stream *stream); | 382 | void sctp_stream_free(struct sctp_stream *stream); |
382 | void sctp_stream_clear(struct sctp_stream *stream); | 383 | void sctp_stream_clear(struct sctp_stream *stream); |
383 | 384 | ||
@@ -499,7 +500,6 @@ struct sctp_datamsg { | |||
499 | /* Did the messenge fail to send? */ | 500 | /* Did the messenge fail to send? */ |
500 | int send_error; | 501 | int send_error; |
501 | u8 send_failed:1, | 502 | u8 send_failed:1, |
502 | force_delay:1, | ||
503 | can_delay; /* should this message be Nagle delayed */ | 503 | can_delay; /* should this message be Nagle delayed */ |
504 | }; | 504 | }; |
505 | 505 | ||
@@ -952,8 +952,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t); | |||
952 | void sctp_transport_burst_limited(struct sctp_transport *); | 952 | void sctp_transport_burst_limited(struct sctp_transport *); |
953 | void sctp_transport_burst_reset(struct sctp_transport *); | 953 | void sctp_transport_burst_reset(struct sctp_transport *); |
954 | unsigned long sctp_transport_timeout(struct sctp_transport *); | 954 | unsigned long sctp_transport_timeout(struct sctp_transport *); |
955 | void sctp_transport_reset(struct sctp_transport *); | 955 | void sctp_transport_reset(struct sctp_transport *t); |
956 | void sctp_transport_update_pmtu(struct sock *, struct sctp_transport *, u32); | 956 | void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu); |
957 | void sctp_transport_immediate_rtx(struct sctp_transport *); | 957 | void sctp_transport_immediate_rtx(struct sctp_transport *); |
958 | void sctp_transport_dst_release(struct sctp_transport *t); | 958 | void sctp_transport_dst_release(struct sctp_transport *t); |
959 | void sctp_transport_dst_confirm(struct sctp_transport *t); | 959 | void sctp_transport_dst_confirm(struct sctp_transport *t); |
@@ -1878,6 +1878,7 @@ struct sctp_association { | |||
1878 | 1878 | ||
1879 | __u8 need_ecne:1, /* Need to send an ECNE Chunk? */ | 1879 | __u8 need_ecne:1, /* Need to send an ECNE Chunk? */ |
1880 | temp:1, /* Is it a temporary association? */ | 1880 | temp:1, /* Is it a temporary association? */ |
1881 | force_delay:1, | ||
1881 | prsctp_enable:1, | 1882 | prsctp_enable:1, |
1882 | reconf_enable:1; | 1883 | reconf_enable:1; |
1883 | 1884 | ||
@@ -1953,7 +1954,7 @@ void sctp_assoc_update(struct sctp_association *old, | |||
1953 | 1954 | ||
1954 | __u32 sctp_association_get_next_tsn(struct sctp_association *); | 1955 | __u32 sctp_association_get_next_tsn(struct sctp_association *); |
1955 | 1956 | ||
1956 | void sctp_assoc_sync_pmtu(struct sock *, struct sctp_association *); | 1957 | void sctp_assoc_sync_pmtu(struct sctp_association *asoc); |
1957 | void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned int); | 1958 | void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned int); |
1958 | void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned int); | 1959 | void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned int); |
1959 | void sctp_assoc_set_primary(struct sctp_association *, | 1960 | void sctp_assoc_set_primary(struct sctp_association *, |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 796b68d00119..a834068a400e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -765,38 +765,56 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno) | |||
765 | } | 765 | } |
766 | } | 766 | } |
767 | 767 | ||
768 | static int check_ptr_alignment(struct bpf_verifier_env *env, | 768 | static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, |
769 | struct bpf_reg_state *reg, int off, int size) | 769 | int off, int size) |
770 | { | 770 | { |
771 | if (reg->type != PTR_TO_PACKET && reg->type != PTR_TO_MAP_VALUE_ADJ) { | ||
772 | if (off % size != 0) { | ||
773 | verbose("misaligned access off %d size %d\n", | ||
774 | off, size); | ||
775 | return -EACCES; | ||
776 | } else { | ||
777 | return 0; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) | ||
782 | /* misaligned access to packet is ok on x86,arm,arm64 */ | ||
783 | return 0; | ||
784 | |||
785 | if (reg->id && size != 1) { | 771 | if (reg->id && size != 1) { |
786 | verbose("Unknown packet alignment. Only byte-sized access allowed\n"); | 772 | verbose("Unknown alignment. Only byte-sized access allowed in packet access.\n"); |
787 | return -EACCES; | 773 | return -EACCES; |
788 | } | 774 | } |
789 | 775 | ||
790 | /* skb->data is NET_IP_ALIGN-ed */ | 776 | /* skb->data is NET_IP_ALIGN-ed */ |
791 | if (reg->type == PTR_TO_PACKET && | 777 | if ((NET_IP_ALIGN + reg->off + off) % size != 0) { |
792 | (NET_IP_ALIGN + reg->off + off) % size != 0) { | ||
793 | verbose("misaligned packet access off %d+%d+%d size %d\n", | 778 | verbose("misaligned packet access off %d+%d+%d size %d\n", |
794 | NET_IP_ALIGN, reg->off, off, size); | 779 | NET_IP_ALIGN, reg->off, off, size); |
795 | return -EACCES; | 780 | return -EACCES; |
796 | } | 781 | } |
782 | |||
797 | return 0; | 783 | return 0; |
798 | } | 784 | } |
799 | 785 | ||
786 | static int check_val_ptr_alignment(const struct bpf_reg_state *reg, | ||
787 | int size) | ||
788 | { | ||
789 | if (size != 1) { | ||
790 | verbose("Unknown alignment. Only byte-sized access allowed in value access.\n"); | ||
791 | return -EACCES; | ||
792 | } | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static int check_ptr_alignment(const struct bpf_reg_state *reg, | ||
798 | int off, int size) | ||
799 | { | ||
800 | switch (reg->type) { | ||
801 | case PTR_TO_PACKET: | ||
802 | return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 : | ||
803 | check_pkt_ptr_alignment(reg, off, size); | ||
804 | case PTR_TO_MAP_VALUE_ADJ: | ||
805 | return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 : | ||
806 | check_val_ptr_alignment(reg, size); | ||
807 | default: | ||
808 | if (off % size != 0) { | ||
809 | verbose("misaligned access off %d size %d\n", | ||
810 | off, size); | ||
811 | return -EACCES; | ||
812 | } | ||
813 | |||
814 | return 0; | ||
815 | } | ||
816 | } | ||
817 | |||
800 | /* check whether memory at (regno + off) is accessible for t = (read | write) | 818 | /* check whether memory at (regno + off) is accessible for t = (read | write) |
801 | * if t==write, value_regno is a register which value is stored into memory | 819 | * if t==write, value_regno is a register which value is stored into memory |
802 | * if t==read, value_regno is a register which will receive the value from memory | 820 | * if t==read, value_regno is a register which will receive the value from memory |
@@ -818,7 +836,7 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off, | |||
818 | if (size < 0) | 836 | if (size < 0) |
819 | return size; | 837 | return size; |
820 | 838 | ||
821 | err = check_ptr_alignment(env, reg, off, size); | 839 | err = check_ptr_alignment(reg, off, size); |
822 | if (err) | 840 | if (err) |
823 | return err; | 841 | return err; |
824 | 842 | ||
@@ -1925,6 +1943,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) | |||
1925 | * register as unknown. | 1943 | * register as unknown. |
1926 | */ | 1944 | */ |
1927 | if (env->allow_ptr_leaks && | 1945 | if (env->allow_ptr_leaks && |
1946 | BPF_CLASS(insn->code) == BPF_ALU64 && opcode == BPF_ADD && | ||
1928 | (dst_reg->type == PTR_TO_MAP_VALUE || | 1947 | (dst_reg->type == PTR_TO_MAP_VALUE || |
1929 | dst_reg->type == PTR_TO_MAP_VALUE_ADJ)) | 1948 | dst_reg->type == PTR_TO_MAP_VALUE_ADJ)) |
1930 | dst_reg->type = PTR_TO_MAP_VALUE_ADJ; | 1949 | dst_reg->type = PTR_TO_MAP_VALUE_ADJ; |
@@ -1973,14 +1992,15 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, | |||
1973 | 1992 | ||
1974 | for (i = 0; i < MAX_BPF_REG; i++) | 1993 | for (i = 0; i < MAX_BPF_REG; i++) |
1975 | if (regs[i].type == PTR_TO_PACKET && regs[i].id == dst_reg->id) | 1994 | if (regs[i].type == PTR_TO_PACKET && regs[i].id == dst_reg->id) |
1976 | regs[i].range = dst_reg->off; | 1995 | /* keep the maximum range already checked */ |
1996 | regs[i].range = max(regs[i].range, dst_reg->off); | ||
1977 | 1997 | ||
1978 | for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { | 1998 | for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) { |
1979 | if (state->stack_slot_type[i] != STACK_SPILL) | 1999 | if (state->stack_slot_type[i] != STACK_SPILL) |
1980 | continue; | 2000 | continue; |
1981 | reg = &state->spilled_regs[i / BPF_REG_SIZE]; | 2001 | reg = &state->spilled_regs[i / BPF_REG_SIZE]; |
1982 | if (reg->type == PTR_TO_PACKET && reg->id == dst_reg->id) | 2002 | if (reg->type == PTR_TO_PACKET && reg->id == dst_reg->id) |
1983 | reg->range = dst_reg->off; | 2003 | reg->range = max(reg->range, dst_reg->off); |
1984 | } | 2004 | } |
1985 | } | 2005 | } |
1986 | 2006 | ||
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index c35aae13c8d2..d98d4998213d 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c | |||
@@ -390,7 +390,7 @@ mpls: | |||
390 | unsigned char ar_tip[4]; | 390 | unsigned char ar_tip[4]; |
391 | } *arp_eth, _arp_eth; | 391 | } *arp_eth, _arp_eth; |
392 | const struct arphdr *arp; | 392 | const struct arphdr *arp; |
393 | struct arphdr *_arp; | 393 | struct arphdr _arp; |
394 | 394 | ||
395 | arp = __skb_header_pointer(skb, nhoff, sizeof(_arp), data, | 395 | arp = __skb_header_pointer(skb, nhoff, sizeof(_arp), data, |
396 | hlen, &_arp); | 396 | hlen, &_arp); |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index e7c12caa20c8..4526cbd7e28a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -860,7 +860,8 @@ static void neigh_probe(struct neighbour *neigh) | |||
860 | if (skb) | 860 | if (skb) |
861 | skb = skb_clone(skb, GFP_ATOMIC); | 861 | skb = skb_clone(skb, GFP_ATOMIC); |
862 | write_unlock(&neigh->lock); | 862 | write_unlock(&neigh->lock); |
863 | neigh->ops->solicit(neigh, skb); | 863 | if (neigh->ops->solicit) |
864 | neigh->ops->solicit(neigh, skb); | ||
864 | atomic_inc(&neigh->probes); | 865 | atomic_inc(&neigh->probes); |
865 | kfree_skb(skb); | 866 | kfree_skb(skb); |
866 | } | 867 | } |
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 758f140b6bed..d28da7d363f1 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c | |||
@@ -20,9 +20,11 @@ | |||
20 | #include <net/tcp.h> | 20 | #include <net/tcp.h> |
21 | 21 | ||
22 | static siphash_key_t net_secret __read_mostly; | 22 | static siphash_key_t net_secret __read_mostly; |
23 | static siphash_key_t ts_secret __read_mostly; | ||
23 | 24 | ||
24 | static __always_inline void net_secret_init(void) | 25 | static __always_inline void net_secret_init(void) |
25 | { | 26 | { |
27 | net_get_random_once(&ts_secret, sizeof(ts_secret)); | ||
26 | net_get_random_once(&net_secret, sizeof(net_secret)); | 28 | net_get_random_once(&net_secret, sizeof(net_secret)); |
27 | } | 29 | } |
28 | #endif | 30 | #endif |
@@ -45,6 +47,23 @@ static u32 seq_scale(u32 seq) | |||
45 | #endif | 47 | #endif |
46 | 48 | ||
47 | #if IS_ENABLED(CONFIG_IPV6) | 49 | #if IS_ENABLED(CONFIG_IPV6) |
50 | static u32 secure_tcpv6_ts_off(const __be32 *saddr, const __be32 *daddr) | ||
51 | { | ||
52 | const struct { | ||
53 | struct in6_addr saddr; | ||
54 | struct in6_addr daddr; | ||
55 | } __aligned(SIPHASH_ALIGNMENT) combined = { | ||
56 | .saddr = *(struct in6_addr *)saddr, | ||
57 | .daddr = *(struct in6_addr *)daddr, | ||
58 | }; | ||
59 | |||
60 | if (sysctl_tcp_timestamps != 1) | ||
61 | return 0; | ||
62 | |||
63 | return siphash(&combined, offsetofend(typeof(combined), daddr), | ||
64 | &ts_secret); | ||
65 | } | ||
66 | |||
48 | u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, | 67 | u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, |
49 | __be16 sport, __be16 dport, u32 *tsoff) | 68 | __be16 sport, __be16 dport, u32 *tsoff) |
50 | { | 69 | { |
@@ -63,7 +82,7 @@ u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, | |||
63 | net_secret_init(); | 82 | net_secret_init(); |
64 | hash = siphash(&combined, offsetofend(typeof(combined), dport), | 83 | hash = siphash(&combined, offsetofend(typeof(combined), dport), |
65 | &net_secret); | 84 | &net_secret); |
66 | *tsoff = sysctl_tcp_timestamps == 1 ? (hash >> 32) : 0; | 85 | *tsoff = secure_tcpv6_ts_off(saddr, daddr); |
67 | return seq_scale(hash); | 86 | return seq_scale(hash); |
68 | } | 87 | } |
69 | EXPORT_SYMBOL(secure_tcpv6_sequence_number); | 88 | EXPORT_SYMBOL(secure_tcpv6_sequence_number); |
@@ -88,6 +107,14 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral); | |||
88 | #endif | 107 | #endif |
89 | 108 | ||
90 | #ifdef CONFIG_INET | 109 | #ifdef CONFIG_INET |
110 | static u32 secure_tcp_ts_off(__be32 saddr, __be32 daddr) | ||
111 | { | ||
112 | if (sysctl_tcp_timestamps != 1) | ||
113 | return 0; | ||
114 | |||
115 | return siphash_2u32((__force u32)saddr, (__force u32)daddr, | ||
116 | &ts_secret); | ||
117 | } | ||
91 | 118 | ||
92 | /* secure_tcp_sequence_number(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d), | 119 | /* secure_tcp_sequence_number(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d), |
93 | * but fortunately, `sport' cannot be 0 in any circumstances. If this changes, | 120 | * but fortunately, `sport' cannot be 0 in any circumstances. If this changes, |
@@ -103,7 +130,7 @@ u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, | |||
103 | hash = siphash_3u32((__force u32)saddr, (__force u32)daddr, | 130 | hash = siphash_3u32((__force u32)saddr, (__force u32)daddr, |
104 | (__force u32)sport << 16 | (__force u32)dport, | 131 | (__force u32)sport << 16 | (__force u32)dport, |
105 | &net_secret); | 132 | &net_secret); |
106 | *tsoff = sysctl_tcp_timestamps == 1 ? (hash >> 32) : 0; | 133 | *tsoff = secure_tcp_ts_off(saddr, daddr); |
107 | return seq_scale(hash); | 134 | return seq_scale(hash); |
108 | } | 135 | } |
109 | 136 | ||
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 4ead336e14ea..7f9cc400eca0 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
@@ -408,14 +408,16 @@ static struct ctl_table net_core_table[] = { | |||
408 | .data = &sysctl_net_busy_poll, | 408 | .data = &sysctl_net_busy_poll, |
409 | .maxlen = sizeof(unsigned int), | 409 | .maxlen = sizeof(unsigned int), |
410 | .mode = 0644, | 410 | .mode = 0644, |
411 | .proc_handler = proc_dointvec | 411 | .proc_handler = proc_dointvec_minmax, |
412 | .extra1 = &zero, | ||
412 | }, | 413 | }, |
413 | { | 414 | { |
414 | .procname = "busy_read", | 415 | .procname = "busy_read", |
415 | .data = &sysctl_net_busy_read, | 416 | .data = &sysctl_net_busy_read, |
416 | .maxlen = sizeof(unsigned int), | 417 | .maxlen = sizeof(unsigned int), |
417 | .mode = 0644, | 418 | .mode = 0644, |
418 | .proc_handler = proc_dointvec | 419 | .proc_handler = proc_dointvec_minmax, |
420 | .extra1 = &zero, | ||
419 | }, | 421 | }, |
420 | #endif | 422 | #endif |
421 | #ifdef CONFIG_NET_SCHED | 423 | #ifdef CONFIG_NET_SCHED |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index fd9f34bbd740..dfb2ab2dd3c8 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -306,7 +306,7 @@ static void __init ic_close_devs(void) | |||
306 | while ((d = next)) { | 306 | while ((d = next)) { |
307 | next = d->next; | 307 | next = d->next; |
308 | dev = d->dev; | 308 | dev = d->dev; |
309 | if ((!ic_dev || dev != ic_dev->dev) && !netdev_uses_dsa(dev)) { | 309 | if (d != ic_dev && !netdev_uses_dsa(dev)) { |
310 | pr_debug("IP-Config: Downing %s\n", dev->name); | 310 | pr_debug("IP-Config: Downing %s\n", dev->name); |
311 | dev_change_flags(dev, d->flags); | 311 | dev_change_flags(dev, d->flags); |
312 | } | 312 | } |
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index c9b52c361da2..53e49f5011d3 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c | |||
@@ -1260,16 +1260,6 @@ static const struct nf_conntrack_expect_policy snmp_exp_policy = { | |||
1260 | .timeout = 180, | 1260 | .timeout = 180, |
1261 | }; | 1261 | }; |
1262 | 1262 | ||
1263 | static struct nf_conntrack_helper snmp_helper __read_mostly = { | ||
1264 | .me = THIS_MODULE, | ||
1265 | .help = help, | ||
1266 | .expect_policy = &snmp_exp_policy, | ||
1267 | .name = "snmp", | ||
1268 | .tuple.src.l3num = AF_INET, | ||
1269 | .tuple.src.u.udp.port = cpu_to_be16(SNMP_PORT), | ||
1270 | .tuple.dst.protonum = IPPROTO_UDP, | ||
1271 | }; | ||
1272 | |||
1273 | static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { | 1263 | static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { |
1274 | .me = THIS_MODULE, | 1264 | .me = THIS_MODULE, |
1275 | .help = help, | 1265 | .help = help, |
@@ -1288,22 +1278,16 @@ static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { | |||
1288 | 1278 | ||
1289 | static int __init nf_nat_snmp_basic_init(void) | 1279 | static int __init nf_nat_snmp_basic_init(void) |
1290 | { | 1280 | { |
1291 | int ret = 0; | ||
1292 | |||
1293 | BUG_ON(nf_nat_snmp_hook != NULL); | 1281 | BUG_ON(nf_nat_snmp_hook != NULL); |
1294 | RCU_INIT_POINTER(nf_nat_snmp_hook, help); | 1282 | RCU_INIT_POINTER(nf_nat_snmp_hook, help); |
1295 | 1283 | ||
1296 | ret = nf_conntrack_helper_register(&snmp_trap_helper); | 1284 | return nf_conntrack_helper_register(&snmp_trap_helper); |
1297 | if (ret < 0) { | ||
1298 | nf_conntrack_helper_unregister(&snmp_helper); | ||
1299 | return ret; | ||
1300 | } | ||
1301 | return ret; | ||
1302 | } | 1285 | } |
1303 | 1286 | ||
1304 | static void __exit nf_nat_snmp_basic_fini(void) | 1287 | static void __exit nf_nat_snmp_basic_fini(void) |
1305 | { | 1288 | { |
1306 | RCU_INIT_POINTER(nf_nat_snmp_hook, NULL); | 1289 | RCU_INIT_POINTER(nf_nat_snmp_hook, NULL); |
1290 | synchronize_rcu(); | ||
1307 | nf_conntrack_helper_unregister(&snmp_trap_helper); | 1291 | nf_conntrack_helper_unregister(&snmp_trap_helper); |
1308 | } | 1292 | } |
1309 | 1293 | ||
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 2af6244b83e2..ccfbce13a633 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -156,17 +156,18 @@ int ping_hash(struct sock *sk) | |||
156 | void ping_unhash(struct sock *sk) | 156 | void ping_unhash(struct sock *sk) |
157 | { | 157 | { |
158 | struct inet_sock *isk = inet_sk(sk); | 158 | struct inet_sock *isk = inet_sk(sk); |
159 | |||
159 | pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); | 160 | pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); |
161 | write_lock_bh(&ping_table.lock); | ||
160 | if (sk_hashed(sk)) { | 162 | if (sk_hashed(sk)) { |
161 | write_lock_bh(&ping_table.lock); | ||
162 | hlist_nulls_del(&sk->sk_nulls_node); | 163 | hlist_nulls_del(&sk->sk_nulls_node); |
163 | sk_nulls_node_init(&sk->sk_nulls_node); | 164 | sk_nulls_node_init(&sk->sk_nulls_node); |
164 | sock_put(sk); | 165 | sock_put(sk); |
165 | isk->inet_num = 0; | 166 | isk->inet_num = 0; |
166 | isk->inet_sport = 0; | 167 | isk->inet_sport = 0; |
167 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | 168 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); |
168 | write_unlock_bh(&ping_table.lock); | ||
169 | } | 169 | } |
170 | write_unlock_bh(&ping_table.lock); | ||
170 | } | 171 | } |
171 | EXPORT_SYMBOL_GPL(ping_unhash); | 172 | EXPORT_SYMBOL_GPL(ping_unhash); |
172 | 173 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c43119726a62..2c1f59386a7b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -126,7 +126,8 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2; | |||
126 | #define REXMIT_LOST 1 /* retransmit packets marked lost */ | 126 | #define REXMIT_LOST 1 /* retransmit packets marked lost */ |
127 | #define REXMIT_NEW 2 /* FRTO-style transmit of unsent/new packets */ | 127 | #define REXMIT_NEW 2 /* FRTO-style transmit of unsent/new packets */ |
128 | 128 | ||
129 | static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb) | 129 | static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb, |
130 | unsigned int len) | ||
130 | { | 131 | { |
131 | static bool __once __read_mostly; | 132 | static bool __once __read_mostly; |
132 | 133 | ||
@@ -137,8 +138,9 @@ static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb) | |||
137 | 138 | ||
138 | rcu_read_lock(); | 139 | rcu_read_lock(); |
139 | dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif); | 140 | dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif); |
140 | pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", | 141 | if (!dev || len >= dev->mtu) |
141 | dev ? dev->name : "Unknown driver"); | 142 | pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", |
143 | dev ? dev->name : "Unknown driver"); | ||
142 | rcu_read_unlock(); | 144 | rcu_read_unlock(); |
143 | } | 145 | } |
144 | } | 146 | } |
@@ -161,8 +163,10 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb) | |||
161 | if (len >= icsk->icsk_ack.rcv_mss) { | 163 | if (len >= icsk->icsk_ack.rcv_mss) { |
162 | icsk->icsk_ack.rcv_mss = min_t(unsigned int, len, | 164 | icsk->icsk_ack.rcv_mss = min_t(unsigned int, len, |
163 | tcp_sk(sk)->advmss); | 165 | tcp_sk(sk)->advmss); |
164 | if (unlikely(icsk->icsk_ack.rcv_mss != len)) | 166 | /* Account for possibly-removed options */ |
165 | tcp_gro_dev_warn(sk, skb); | 167 | if (unlikely(len > icsk->icsk_ack.rcv_mss + |
168 | MAX_TCP_OPTION_SPACE)) | ||
169 | tcp_gro_dev_warn(sk, skb, len); | ||
166 | } else { | 170 | } else { |
167 | /* Otherwise, we make more careful check taking into account, | 171 | /* Otherwise, we make more careful check taking into account, |
168 | * that SACKs block is variable. | 172 | * that SACKs block is variable. |
@@ -874,22 +878,11 @@ static void tcp_update_reordering(struct sock *sk, const int metric, | |||
874 | const int ts) | 878 | const int ts) |
875 | { | 879 | { |
876 | struct tcp_sock *tp = tcp_sk(sk); | 880 | struct tcp_sock *tp = tcp_sk(sk); |
877 | if (metric > tp->reordering) { | 881 | int mib_idx; |
878 | int mib_idx; | ||
879 | 882 | ||
883 | if (metric > tp->reordering) { | ||
880 | tp->reordering = min(sysctl_tcp_max_reordering, metric); | 884 | tp->reordering = min(sysctl_tcp_max_reordering, metric); |
881 | 885 | ||
882 | /* This exciting event is worth to be remembered. 8) */ | ||
883 | if (ts) | ||
884 | mib_idx = LINUX_MIB_TCPTSREORDER; | ||
885 | else if (tcp_is_reno(tp)) | ||
886 | mib_idx = LINUX_MIB_TCPRENOREORDER; | ||
887 | else if (tcp_is_fack(tp)) | ||
888 | mib_idx = LINUX_MIB_TCPFACKREORDER; | ||
889 | else | ||
890 | mib_idx = LINUX_MIB_TCPSACKREORDER; | ||
891 | |||
892 | NET_INC_STATS(sock_net(sk), mib_idx); | ||
893 | #if FASTRETRANS_DEBUG > 1 | 886 | #if FASTRETRANS_DEBUG > 1 |
894 | pr_debug("Disorder%d %d %u f%u s%u rr%d\n", | 887 | pr_debug("Disorder%d %d %u f%u s%u rr%d\n", |
895 | tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state, | 888 | tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state, |
@@ -902,6 +895,18 @@ static void tcp_update_reordering(struct sock *sk, const int metric, | |||
902 | } | 895 | } |
903 | 896 | ||
904 | tp->rack.reord = 1; | 897 | tp->rack.reord = 1; |
898 | |||
899 | /* This exciting event is worth to be remembered. 8) */ | ||
900 | if (ts) | ||
901 | mib_idx = LINUX_MIB_TCPTSREORDER; | ||
902 | else if (tcp_is_reno(tp)) | ||
903 | mib_idx = LINUX_MIB_TCPRENOREORDER; | ||
904 | else if (tcp_is_fack(tp)) | ||
905 | mib_idx = LINUX_MIB_TCPFACKREORDER; | ||
906 | else | ||
907 | mib_idx = LINUX_MIB_TCPSACKREORDER; | ||
908 | |||
909 | NET_INC_STATS(sock_net(sk), mib_idx); | ||
905 | } | 910 | } |
906 | 911 | ||
907 | /* This must be called before lost_out is incremented */ | 912 | /* This must be called before lost_out is incremented */ |
diff --git a/net/ipv4/tcp_recovery.c b/net/ipv4/tcp_recovery.c index 4ecb38ae8504..d8acbd9f477a 100644 --- a/net/ipv4/tcp_recovery.c +++ b/net/ipv4/tcp_recovery.c | |||
@@ -12,7 +12,8 @@ static void tcp_rack_mark_skb_lost(struct sock *sk, struct sk_buff *skb) | |||
12 | /* Account for retransmits that are lost again */ | 12 | /* Account for retransmits that are lost again */ |
13 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; | 13 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; |
14 | tp->retrans_out -= tcp_skb_pcount(skb); | 14 | tp->retrans_out -= tcp_skb_pcount(skb); |
15 | NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT); | 15 | NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT, |
16 | tcp_skb_pcount(skb)); | ||
16 | } | 17 | } |
17 | } | 18 | } |
18 | 19 | ||
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 309062f3debe..31762f76cdb5 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c | |||
@@ -1687,7 +1687,7 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1687 | struct kcm_attach info; | 1687 | struct kcm_attach info; |
1688 | 1688 | ||
1689 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) | 1689 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) |
1690 | err = -EFAULT; | 1690 | return -EFAULT; |
1691 | 1691 | ||
1692 | err = kcm_attach_ioctl(sock, &info); | 1692 | err = kcm_attach_ioctl(sock, &info); |
1693 | 1693 | ||
@@ -1697,7 +1697,7 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1697 | struct kcm_unattach info; | 1697 | struct kcm_unattach info; |
1698 | 1698 | ||
1699 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) | 1699 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) |
1700 | err = -EFAULT; | 1700 | return -EFAULT; |
1701 | 1701 | ||
1702 | err = kcm_unattach_ioctl(sock, &info); | 1702 | err = kcm_unattach_ioctl(sock, &info); |
1703 | 1703 | ||
@@ -1708,7 +1708,7 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1708 | struct socket *newsock = NULL; | 1708 | struct socket *newsock = NULL; |
1709 | 1709 | ||
1710 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) | 1710 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) |
1711 | err = -EFAULT; | 1711 | return -EFAULT; |
1712 | 1712 | ||
1713 | err = kcm_clone(sock, &info, &newsock); | 1713 | err = kcm_clone(sock, &info, &newsock); |
1714 | 1714 | ||
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 8adab6335ced..e37d9554da7b 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -278,7 +278,57 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn | |||
278 | } | 278 | } |
279 | EXPORT_SYMBOL_GPL(l2tp_session_find); | 279 | EXPORT_SYMBOL_GPL(l2tp_session_find); |
280 | 280 | ||
281 | struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) | 281 | /* Like l2tp_session_find() but takes a reference on the returned session. |
282 | * Optionally calls session->ref() too if do_ref is true. | ||
283 | */ | ||
284 | struct l2tp_session *l2tp_session_get(struct net *net, | ||
285 | struct l2tp_tunnel *tunnel, | ||
286 | u32 session_id, bool do_ref) | ||
287 | { | ||
288 | struct hlist_head *session_list; | ||
289 | struct l2tp_session *session; | ||
290 | |||
291 | if (!tunnel) { | ||
292 | struct l2tp_net *pn = l2tp_pernet(net); | ||
293 | |||
294 | session_list = l2tp_session_id_hash_2(pn, session_id); | ||
295 | |||
296 | rcu_read_lock_bh(); | ||
297 | hlist_for_each_entry_rcu(session, session_list, global_hlist) { | ||
298 | if (session->session_id == session_id) { | ||
299 | l2tp_session_inc_refcount(session); | ||
300 | if (do_ref && session->ref) | ||
301 | session->ref(session); | ||
302 | rcu_read_unlock_bh(); | ||
303 | |||
304 | return session; | ||
305 | } | ||
306 | } | ||
307 | rcu_read_unlock_bh(); | ||
308 | |||
309 | return NULL; | ||
310 | } | ||
311 | |||
312 | session_list = l2tp_session_id_hash(tunnel, session_id); | ||
313 | read_lock_bh(&tunnel->hlist_lock); | ||
314 | hlist_for_each_entry(session, session_list, hlist) { | ||
315 | if (session->session_id == session_id) { | ||
316 | l2tp_session_inc_refcount(session); | ||
317 | if (do_ref && session->ref) | ||
318 | session->ref(session); | ||
319 | read_unlock_bh(&tunnel->hlist_lock); | ||
320 | |||
321 | return session; | ||
322 | } | ||
323 | } | ||
324 | read_unlock_bh(&tunnel->hlist_lock); | ||
325 | |||
326 | return NULL; | ||
327 | } | ||
328 | EXPORT_SYMBOL_GPL(l2tp_session_get); | ||
329 | |||
330 | struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, | ||
331 | bool do_ref) | ||
282 | { | 332 | { |
283 | int hash; | 333 | int hash; |
284 | struct l2tp_session *session; | 334 | struct l2tp_session *session; |
@@ -288,6 +338,9 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) | |||
288 | for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { | 338 | for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { |
289 | hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { | 339 | hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { |
290 | if (++count > nth) { | 340 | if (++count > nth) { |
341 | l2tp_session_inc_refcount(session); | ||
342 | if (do_ref && session->ref) | ||
343 | session->ref(session); | ||
291 | read_unlock_bh(&tunnel->hlist_lock); | 344 | read_unlock_bh(&tunnel->hlist_lock); |
292 | return session; | 345 | return session; |
293 | } | 346 | } |
@@ -298,12 +351,13 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) | |||
298 | 351 | ||
299 | return NULL; | 352 | return NULL; |
300 | } | 353 | } |
301 | EXPORT_SYMBOL_GPL(l2tp_session_find_nth); | 354 | EXPORT_SYMBOL_GPL(l2tp_session_get_nth); |
302 | 355 | ||
303 | /* Lookup a session by interface name. | 356 | /* Lookup a session by interface name. |
304 | * This is very inefficient but is only used by management interfaces. | 357 | * This is very inefficient but is only used by management interfaces. |
305 | */ | 358 | */ |
306 | struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) | 359 | struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname, |
360 | bool do_ref) | ||
307 | { | 361 | { |
308 | struct l2tp_net *pn = l2tp_pernet(net); | 362 | struct l2tp_net *pn = l2tp_pernet(net); |
309 | int hash; | 363 | int hash; |
@@ -313,7 +367,11 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) | |||
313 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { | 367 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { |
314 | hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) { | 368 | hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) { |
315 | if (!strcmp(session->ifname, ifname)) { | 369 | if (!strcmp(session->ifname, ifname)) { |
370 | l2tp_session_inc_refcount(session); | ||
371 | if (do_ref && session->ref) | ||
372 | session->ref(session); | ||
316 | rcu_read_unlock_bh(); | 373 | rcu_read_unlock_bh(); |
374 | |||
317 | return session; | 375 | return session; |
318 | } | 376 | } |
319 | } | 377 | } |
@@ -323,7 +381,49 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) | |||
323 | 381 | ||
324 | return NULL; | 382 | return NULL; |
325 | } | 383 | } |
326 | EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname); | 384 | EXPORT_SYMBOL_GPL(l2tp_session_get_by_ifname); |
385 | |||
386 | static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel, | ||
387 | struct l2tp_session *session) | ||
388 | { | ||
389 | struct l2tp_session *session_walk; | ||
390 | struct hlist_head *g_head; | ||
391 | struct hlist_head *head; | ||
392 | struct l2tp_net *pn; | ||
393 | |||
394 | head = l2tp_session_id_hash(tunnel, session->session_id); | ||
395 | |||
396 | write_lock_bh(&tunnel->hlist_lock); | ||
397 | hlist_for_each_entry(session_walk, head, hlist) | ||
398 | if (session_walk->session_id == session->session_id) | ||
399 | goto exist; | ||
400 | |||
401 | if (tunnel->version == L2TP_HDR_VER_3) { | ||
402 | pn = l2tp_pernet(tunnel->l2tp_net); | ||
403 | g_head = l2tp_session_id_hash_2(l2tp_pernet(tunnel->l2tp_net), | ||
404 | session->session_id); | ||
405 | |||
406 | spin_lock_bh(&pn->l2tp_session_hlist_lock); | ||
407 | hlist_for_each_entry(session_walk, g_head, global_hlist) | ||
408 | if (session_walk->session_id == session->session_id) | ||
409 | goto exist_glob; | ||
410 | |||
411 | hlist_add_head_rcu(&session->global_hlist, g_head); | ||
412 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); | ||
413 | } | ||
414 | |||
415 | hlist_add_head(&session->hlist, head); | ||
416 | write_unlock_bh(&tunnel->hlist_lock); | ||
417 | |||
418 | return 0; | ||
419 | |||
420 | exist_glob: | ||
421 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); | ||
422 | exist: | ||
423 | write_unlock_bh(&tunnel->hlist_lock); | ||
424 | |||
425 | return -EEXIST; | ||
426 | } | ||
327 | 427 | ||
328 | /* Lookup a tunnel by id | 428 | /* Lookup a tunnel by id |
329 | */ | 429 | */ |
@@ -633,6 +733,9 @@ discard: | |||
633 | * a data (not control) frame before coming here. Fields up to the | 733 | * a data (not control) frame before coming here. Fields up to the |
634 | * session-id have already been parsed and ptr points to the data | 734 | * session-id have already been parsed and ptr points to the data |
635 | * after the session-id. | 735 | * after the session-id. |
736 | * | ||
737 | * session->ref() must have been called prior to l2tp_recv_common(). | ||
738 | * session->deref() will be called automatically after skb is processed. | ||
636 | */ | 739 | */ |
637 | void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, | 740 | void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, |
638 | unsigned char *ptr, unsigned char *optr, u16 hdrflags, | 741 | unsigned char *ptr, unsigned char *optr, u16 hdrflags, |
@@ -642,14 +745,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, | |||
642 | int offset; | 745 | int offset; |
643 | u32 ns, nr; | 746 | u32 ns, nr; |
644 | 747 | ||
645 | /* The ref count is increased since we now hold a pointer to | ||
646 | * the session. Take care to decrement the refcnt when exiting | ||
647 | * this function from now on... | ||
648 | */ | ||
649 | l2tp_session_inc_refcount(session); | ||
650 | if (session->ref) | ||
651 | (*session->ref)(session); | ||
652 | |||
653 | /* Parse and check optional cookie */ | 748 | /* Parse and check optional cookie */ |
654 | if (session->peer_cookie_len > 0) { | 749 | if (session->peer_cookie_len > 0) { |
655 | if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { | 750 | if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { |
@@ -802,8 +897,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, | |||
802 | /* Try to dequeue as many skbs from reorder_q as we can. */ | 897 | /* Try to dequeue as many skbs from reorder_q as we can. */ |
803 | l2tp_recv_dequeue(session); | 898 | l2tp_recv_dequeue(session); |
804 | 899 | ||
805 | l2tp_session_dec_refcount(session); | ||
806 | |||
807 | return; | 900 | return; |
808 | 901 | ||
809 | discard: | 902 | discard: |
@@ -812,8 +905,6 @@ discard: | |||
812 | 905 | ||
813 | if (session->deref) | 906 | if (session->deref) |
814 | (*session->deref)(session); | 907 | (*session->deref)(session); |
815 | |||
816 | l2tp_session_dec_refcount(session); | ||
817 | } | 908 | } |
818 | EXPORT_SYMBOL(l2tp_recv_common); | 909 | EXPORT_SYMBOL(l2tp_recv_common); |
819 | 910 | ||
@@ -920,8 +1011,14 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, | |||
920 | } | 1011 | } |
921 | 1012 | ||
922 | /* Find the session context */ | 1013 | /* Find the session context */ |
923 | session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id); | 1014 | session = l2tp_session_get(tunnel->l2tp_net, tunnel, session_id, true); |
924 | if (!session || !session->recv_skb) { | 1015 | if (!session || !session->recv_skb) { |
1016 | if (session) { | ||
1017 | if (session->deref) | ||
1018 | session->deref(session); | ||
1019 | l2tp_session_dec_refcount(session); | ||
1020 | } | ||
1021 | |||
925 | /* Not found? Pass to userspace to deal with */ | 1022 | /* Not found? Pass to userspace to deal with */ |
926 | l2tp_info(tunnel, L2TP_MSG_DATA, | 1023 | l2tp_info(tunnel, L2TP_MSG_DATA, |
927 | "%s: no session found (%u/%u). Passing up.\n", | 1024 | "%s: no session found (%u/%u). Passing up.\n", |
@@ -930,6 +1027,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, | |||
930 | } | 1027 | } |
931 | 1028 | ||
932 | l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook); | 1029 | l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook); |
1030 | l2tp_session_dec_refcount(session); | ||
933 | 1031 | ||
934 | return 0; | 1032 | return 0; |
935 | 1033 | ||
@@ -1738,6 +1836,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_set_header_len); | |||
1738 | struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) | 1836 | struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) |
1739 | { | 1837 | { |
1740 | struct l2tp_session *session; | 1838 | struct l2tp_session *session; |
1839 | int err; | ||
1741 | 1840 | ||
1742 | session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL); | 1841 | session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL); |
1743 | if (session != NULL) { | 1842 | if (session != NULL) { |
@@ -1793,6 +1892,13 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn | |||
1793 | 1892 | ||
1794 | l2tp_session_set_header_len(session, tunnel->version); | 1893 | l2tp_session_set_header_len(session, tunnel->version); |
1795 | 1894 | ||
1895 | err = l2tp_session_add_to_tunnel(tunnel, session); | ||
1896 | if (err) { | ||
1897 | kfree(session); | ||
1898 | |||
1899 | return ERR_PTR(err); | ||
1900 | } | ||
1901 | |||
1796 | /* Bump the reference count. The session context is deleted | 1902 | /* Bump the reference count. The session context is deleted |
1797 | * only when this drops to zero. | 1903 | * only when this drops to zero. |
1798 | */ | 1904 | */ |
@@ -1802,28 +1908,14 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn | |||
1802 | /* Ensure tunnel socket isn't deleted */ | 1908 | /* Ensure tunnel socket isn't deleted */ |
1803 | sock_hold(tunnel->sock); | 1909 | sock_hold(tunnel->sock); |
1804 | 1910 | ||
1805 | /* Add session to the tunnel's hash list */ | ||
1806 | write_lock_bh(&tunnel->hlist_lock); | ||
1807 | hlist_add_head(&session->hlist, | ||
1808 | l2tp_session_id_hash(tunnel, session_id)); | ||
1809 | write_unlock_bh(&tunnel->hlist_lock); | ||
1810 | |||
1811 | /* And to the global session list if L2TPv3 */ | ||
1812 | if (tunnel->version != L2TP_HDR_VER_2) { | ||
1813 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | ||
1814 | |||
1815 | spin_lock_bh(&pn->l2tp_session_hlist_lock); | ||
1816 | hlist_add_head_rcu(&session->global_hlist, | ||
1817 | l2tp_session_id_hash_2(pn, session_id)); | ||
1818 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); | ||
1819 | } | ||
1820 | |||
1821 | /* Ignore management session in session count value */ | 1911 | /* Ignore management session in session count value */ |
1822 | if (session->session_id != 0) | 1912 | if (session->session_id != 0) |
1823 | atomic_inc(&l2tp_session_count); | 1913 | atomic_inc(&l2tp_session_count); |
1914 | |||
1915 | return session; | ||
1824 | } | 1916 | } |
1825 | 1917 | ||
1826 | return session; | 1918 | return ERR_PTR(-ENOMEM); |
1827 | } | 1919 | } |
1828 | EXPORT_SYMBOL_GPL(l2tp_session_create); | 1920 | EXPORT_SYMBOL_GPL(l2tp_session_create); |
1829 | 1921 | ||
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index aebf281d09ee..8ce7818c7a9d 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
@@ -230,11 +230,16 @@ out: | |||
230 | return tunnel; | 230 | return tunnel; |
231 | } | 231 | } |
232 | 232 | ||
233 | struct l2tp_session *l2tp_session_get(struct net *net, | ||
234 | struct l2tp_tunnel *tunnel, | ||
235 | u32 session_id, bool do_ref); | ||
233 | struct l2tp_session *l2tp_session_find(struct net *net, | 236 | struct l2tp_session *l2tp_session_find(struct net *net, |
234 | struct l2tp_tunnel *tunnel, | 237 | struct l2tp_tunnel *tunnel, |
235 | u32 session_id); | 238 | u32 session_id); |
236 | struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); | 239 | struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, |
237 | struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); | 240 | bool do_ref); |
241 | struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname, | ||
242 | bool do_ref); | ||
238 | struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); | 243 | struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); |
239 | struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); | 244 | struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); |
240 | 245 | ||
diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index 2d6760a2ae34..d100aed3d06f 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c | |||
@@ -53,7 +53,7 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd) | |||
53 | 53 | ||
54 | static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) | 54 | static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) |
55 | { | 55 | { |
56 | pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); | 56 | pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); |
57 | pd->session_idx++; | 57 | pd->session_idx++; |
58 | 58 | ||
59 | if (pd->session == NULL) { | 59 | if (pd->session == NULL) { |
@@ -238,10 +238,14 @@ static int l2tp_dfs_seq_show(struct seq_file *m, void *v) | |||
238 | } | 238 | } |
239 | 239 | ||
240 | /* Show the tunnel or session context */ | 240 | /* Show the tunnel or session context */ |
241 | if (pd->session == NULL) | 241 | if (!pd->session) { |
242 | l2tp_dfs_seq_tunnel_show(m, pd->tunnel); | 242 | l2tp_dfs_seq_tunnel_show(m, pd->tunnel); |
243 | else | 243 | } else { |
244 | l2tp_dfs_seq_session_show(m, pd->session); | 244 | l2tp_dfs_seq_session_show(m, pd->session); |
245 | if (pd->session->deref) | ||
246 | pd->session->deref(pd->session); | ||
247 | l2tp_session_dec_refcount(pd->session); | ||
248 | } | ||
245 | 249 | ||
246 | out: | 250 | out: |
247 | return 0; | 251 | return 0; |
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 8bf18a5f66e0..6fd41d7afe1e 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c | |||
@@ -221,12 +221,6 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p | |||
221 | goto out; | 221 | goto out; |
222 | } | 222 | } |
223 | 223 | ||
224 | session = l2tp_session_find(net, tunnel, session_id); | ||
225 | if (session) { | ||
226 | rc = -EEXIST; | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | if (cfg->ifname) { | 224 | if (cfg->ifname) { |
231 | dev = dev_get_by_name(net, cfg->ifname); | 225 | dev = dev_get_by_name(net, cfg->ifname); |
232 | if (dev) { | 226 | if (dev) { |
@@ -240,8 +234,8 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p | |||
240 | 234 | ||
241 | session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, | 235 | session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, |
242 | peer_session_id, cfg); | 236 | peer_session_id, cfg); |
243 | if (!session) { | 237 | if (IS_ERR(session)) { |
244 | rc = -ENOMEM; | 238 | rc = PTR_ERR(session); |
245 | goto out; | 239 | goto out; |
246 | } | 240 | } |
247 | 241 | ||
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index d25038cfd64e..4d322c1b7233 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -143,19 +143,19 @@ static int l2tp_ip_recv(struct sk_buff *skb) | |||
143 | } | 143 | } |
144 | 144 | ||
145 | /* Ok, this is a data packet. Lookup the session. */ | 145 | /* Ok, this is a data packet. Lookup the session. */ |
146 | session = l2tp_session_find(net, NULL, session_id); | 146 | session = l2tp_session_get(net, NULL, session_id, true); |
147 | if (session == NULL) | 147 | if (!session) |
148 | goto discard; | 148 | goto discard; |
149 | 149 | ||
150 | tunnel = session->tunnel; | 150 | tunnel = session->tunnel; |
151 | if (tunnel == NULL) | 151 | if (!tunnel) |
152 | goto discard; | 152 | goto discard_sess; |
153 | 153 | ||
154 | /* Trace packet contents, if enabled */ | 154 | /* Trace packet contents, if enabled */ |
155 | if (tunnel->debug & L2TP_MSG_DATA) { | 155 | if (tunnel->debug & L2TP_MSG_DATA) { |
156 | length = min(32u, skb->len); | 156 | length = min(32u, skb->len); |
157 | if (!pskb_may_pull(skb, length)) | 157 | if (!pskb_may_pull(skb, length)) |
158 | goto discard; | 158 | goto discard_sess; |
159 | 159 | ||
160 | /* Point to L2TP header */ | 160 | /* Point to L2TP header */ |
161 | optr = ptr = skb->data; | 161 | optr = ptr = skb->data; |
@@ -165,6 +165,7 @@ static int l2tp_ip_recv(struct sk_buff *skb) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook); | 167 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook); |
168 | l2tp_session_dec_refcount(session); | ||
168 | 169 | ||
169 | return 0; | 170 | return 0; |
170 | 171 | ||
@@ -178,9 +179,10 @@ pass_up: | |||
178 | 179 | ||
179 | tunnel_id = ntohl(*(__be32 *) &skb->data[4]); | 180 | tunnel_id = ntohl(*(__be32 *) &skb->data[4]); |
180 | tunnel = l2tp_tunnel_find(net, tunnel_id); | 181 | tunnel = l2tp_tunnel_find(net, tunnel_id); |
181 | if (tunnel != NULL) | 182 | if (tunnel) { |
182 | sk = tunnel->sock; | 183 | sk = tunnel->sock; |
183 | else { | 184 | sock_hold(sk); |
185 | } else { | ||
184 | struct iphdr *iph = (struct iphdr *) skb_network_header(skb); | 186 | struct iphdr *iph = (struct iphdr *) skb_network_header(skb); |
185 | 187 | ||
186 | read_lock_bh(&l2tp_ip_lock); | 188 | read_lock_bh(&l2tp_ip_lock); |
@@ -202,6 +204,12 @@ pass_up: | |||
202 | 204 | ||
203 | return sk_receive_skb(sk, skb, 1); | 205 | return sk_receive_skb(sk, skb, 1); |
204 | 206 | ||
207 | discard_sess: | ||
208 | if (session->deref) | ||
209 | session->deref(session); | ||
210 | l2tp_session_dec_refcount(session); | ||
211 | goto discard; | ||
212 | |||
205 | discard_put: | 213 | discard_put: |
206 | sock_put(sk); | 214 | sock_put(sk); |
207 | 215 | ||
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index a4abcbc4c09a..88b397c30d86 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c | |||
@@ -156,19 +156,19 @@ static int l2tp_ip6_recv(struct sk_buff *skb) | |||
156 | } | 156 | } |
157 | 157 | ||
158 | /* Ok, this is a data packet. Lookup the session. */ | 158 | /* Ok, this is a data packet. Lookup the session. */ |
159 | session = l2tp_session_find(net, NULL, session_id); | 159 | session = l2tp_session_get(net, NULL, session_id, true); |
160 | if (session == NULL) | 160 | if (!session) |
161 | goto discard; | 161 | goto discard; |
162 | 162 | ||
163 | tunnel = session->tunnel; | 163 | tunnel = session->tunnel; |
164 | if (tunnel == NULL) | 164 | if (!tunnel) |
165 | goto discard; | 165 | goto discard_sess; |
166 | 166 | ||
167 | /* Trace packet contents, if enabled */ | 167 | /* Trace packet contents, if enabled */ |
168 | if (tunnel->debug & L2TP_MSG_DATA) { | 168 | if (tunnel->debug & L2TP_MSG_DATA) { |
169 | length = min(32u, skb->len); | 169 | length = min(32u, skb->len); |
170 | if (!pskb_may_pull(skb, length)) | 170 | if (!pskb_may_pull(skb, length)) |
171 | goto discard; | 171 | goto discard_sess; |
172 | 172 | ||
173 | /* Point to L2TP header */ | 173 | /* Point to L2TP header */ |
174 | optr = ptr = skb->data; | 174 | optr = ptr = skb->data; |
@@ -179,6 +179,8 @@ static int l2tp_ip6_recv(struct sk_buff *skb) | |||
179 | 179 | ||
180 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, | 180 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, |
181 | tunnel->recv_payload_hook); | 181 | tunnel->recv_payload_hook); |
182 | l2tp_session_dec_refcount(session); | ||
183 | |||
182 | return 0; | 184 | return 0; |
183 | 185 | ||
184 | pass_up: | 186 | pass_up: |
@@ -191,9 +193,10 @@ pass_up: | |||
191 | 193 | ||
192 | tunnel_id = ntohl(*(__be32 *) &skb->data[4]); | 194 | tunnel_id = ntohl(*(__be32 *) &skb->data[4]); |
193 | tunnel = l2tp_tunnel_find(net, tunnel_id); | 195 | tunnel = l2tp_tunnel_find(net, tunnel_id); |
194 | if (tunnel != NULL) | 196 | if (tunnel) { |
195 | sk = tunnel->sock; | 197 | sk = tunnel->sock; |
196 | else { | 198 | sock_hold(sk); |
199 | } else { | ||
197 | struct ipv6hdr *iph = ipv6_hdr(skb); | 200 | struct ipv6hdr *iph = ipv6_hdr(skb); |
198 | 201 | ||
199 | read_lock_bh(&l2tp_ip6_lock); | 202 | read_lock_bh(&l2tp_ip6_lock); |
@@ -215,6 +218,12 @@ pass_up: | |||
215 | 218 | ||
216 | return sk_receive_skb(sk, skb, 1); | 219 | return sk_receive_skb(sk, skb, 1); |
217 | 220 | ||
221 | discard_sess: | ||
222 | if (session->deref) | ||
223 | session->deref(session); | ||
224 | l2tp_session_dec_refcount(session); | ||
225 | goto discard; | ||
226 | |||
218 | discard_put: | 227 | discard_put: |
219 | sock_put(sk); | 228 | sock_put(sk); |
220 | 229 | ||
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 3620fba31786..7e3e669baac4 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c | |||
@@ -48,7 +48,8 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, | |||
48 | /* Accessed under genl lock */ | 48 | /* Accessed under genl lock */ |
49 | static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX]; | 49 | static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX]; |
50 | 50 | ||
51 | static struct l2tp_session *l2tp_nl_session_find(struct genl_info *info) | 51 | static struct l2tp_session *l2tp_nl_session_get(struct genl_info *info, |
52 | bool do_ref) | ||
52 | { | 53 | { |
53 | u32 tunnel_id; | 54 | u32 tunnel_id; |
54 | u32 session_id; | 55 | u32 session_id; |
@@ -59,14 +60,15 @@ static struct l2tp_session *l2tp_nl_session_find(struct genl_info *info) | |||
59 | 60 | ||
60 | if (info->attrs[L2TP_ATTR_IFNAME]) { | 61 | if (info->attrs[L2TP_ATTR_IFNAME]) { |
61 | ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]); | 62 | ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]); |
62 | session = l2tp_session_find_by_ifname(net, ifname); | 63 | session = l2tp_session_get_by_ifname(net, ifname, do_ref); |
63 | } else if ((info->attrs[L2TP_ATTR_SESSION_ID]) && | 64 | } else if ((info->attrs[L2TP_ATTR_SESSION_ID]) && |
64 | (info->attrs[L2TP_ATTR_CONN_ID])) { | 65 | (info->attrs[L2TP_ATTR_CONN_ID])) { |
65 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | 66 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); |
66 | session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]); | 67 | session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]); |
67 | tunnel = l2tp_tunnel_find(net, tunnel_id); | 68 | tunnel = l2tp_tunnel_find(net, tunnel_id); |
68 | if (tunnel) | 69 | if (tunnel) |
69 | session = l2tp_session_find(net, tunnel, session_id); | 70 | session = l2tp_session_get(net, tunnel, session_id, |
71 | do_ref); | ||
70 | } | 72 | } |
71 | 73 | ||
72 | return session; | 74 | return session; |
@@ -642,10 +644,12 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
642 | session_id, peer_session_id, &cfg); | 644 | session_id, peer_session_id, &cfg); |
643 | 645 | ||
644 | if (ret >= 0) { | 646 | if (ret >= 0) { |
645 | session = l2tp_session_find(net, tunnel, session_id); | 647 | session = l2tp_session_get(net, tunnel, session_id, false); |
646 | if (session) | 648 | if (session) { |
647 | ret = l2tp_session_notify(&l2tp_nl_family, info, session, | 649 | ret = l2tp_session_notify(&l2tp_nl_family, info, session, |
648 | L2TP_CMD_SESSION_CREATE); | 650 | L2TP_CMD_SESSION_CREATE); |
651 | l2tp_session_dec_refcount(session); | ||
652 | } | ||
649 | } | 653 | } |
650 | 654 | ||
651 | out: | 655 | out: |
@@ -658,7 +662,7 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf | |||
658 | struct l2tp_session *session; | 662 | struct l2tp_session *session; |
659 | u16 pw_type; | 663 | u16 pw_type; |
660 | 664 | ||
661 | session = l2tp_nl_session_find(info); | 665 | session = l2tp_nl_session_get(info, true); |
662 | if (session == NULL) { | 666 | if (session == NULL) { |
663 | ret = -ENODEV; | 667 | ret = -ENODEV; |
664 | goto out; | 668 | goto out; |
@@ -672,6 +676,10 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf | |||
672 | if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete) | 676 | if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete) |
673 | ret = (*l2tp_nl_cmd_ops[pw_type]->session_delete)(session); | 677 | ret = (*l2tp_nl_cmd_ops[pw_type]->session_delete)(session); |
674 | 678 | ||
679 | if (session->deref) | ||
680 | session->deref(session); | ||
681 | l2tp_session_dec_refcount(session); | ||
682 | |||
675 | out: | 683 | out: |
676 | return ret; | 684 | return ret; |
677 | } | 685 | } |
@@ -681,7 +689,7 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf | |||
681 | int ret = 0; | 689 | int ret = 0; |
682 | struct l2tp_session *session; | 690 | struct l2tp_session *session; |
683 | 691 | ||
684 | session = l2tp_nl_session_find(info); | 692 | session = l2tp_nl_session_get(info, false); |
685 | if (session == NULL) { | 693 | if (session == NULL) { |
686 | ret = -ENODEV; | 694 | ret = -ENODEV; |
687 | goto out; | 695 | goto out; |
@@ -716,6 +724,8 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf | |||
716 | ret = l2tp_session_notify(&l2tp_nl_family, info, | 724 | ret = l2tp_session_notify(&l2tp_nl_family, info, |
717 | session, L2TP_CMD_SESSION_MODIFY); | 725 | session, L2TP_CMD_SESSION_MODIFY); |
718 | 726 | ||
727 | l2tp_session_dec_refcount(session); | ||
728 | |||
719 | out: | 729 | out: |
720 | return ret; | 730 | return ret; |
721 | } | 731 | } |
@@ -811,29 +821,34 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info) | |||
811 | struct sk_buff *msg; | 821 | struct sk_buff *msg; |
812 | int ret; | 822 | int ret; |
813 | 823 | ||
814 | session = l2tp_nl_session_find(info); | 824 | session = l2tp_nl_session_get(info, false); |
815 | if (session == NULL) { | 825 | if (session == NULL) { |
816 | ret = -ENODEV; | 826 | ret = -ENODEV; |
817 | goto out; | 827 | goto err; |
818 | } | 828 | } |
819 | 829 | ||
820 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 830 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
821 | if (!msg) { | 831 | if (!msg) { |
822 | ret = -ENOMEM; | 832 | ret = -ENOMEM; |
823 | goto out; | 833 | goto err_ref; |
824 | } | 834 | } |
825 | 835 | ||
826 | ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq, | 836 | ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq, |
827 | 0, session, L2TP_CMD_SESSION_GET); | 837 | 0, session, L2TP_CMD_SESSION_GET); |
828 | if (ret < 0) | 838 | if (ret < 0) |
829 | goto err_out; | 839 | goto err_ref_msg; |
830 | 840 | ||
831 | return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid); | 841 | ret = genlmsg_unicast(genl_info_net(info), msg, info->snd_portid); |
832 | 842 | ||
833 | err_out: | 843 | l2tp_session_dec_refcount(session); |
834 | nlmsg_free(msg); | ||
835 | 844 | ||
836 | out: | 845 | return ret; |
846 | |||
847 | err_ref_msg: | ||
848 | nlmsg_free(msg); | ||
849 | err_ref: | ||
850 | l2tp_session_dec_refcount(session); | ||
851 | err: | ||
837 | return ret; | 852 | return ret; |
838 | } | 853 | } |
839 | 854 | ||
@@ -852,7 +867,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback | |||
852 | goto out; | 867 | goto out; |
853 | } | 868 | } |
854 | 869 | ||
855 | session = l2tp_session_find_nth(tunnel, si); | 870 | session = l2tp_session_get_nth(tunnel, si, false); |
856 | if (session == NULL) { | 871 | if (session == NULL) { |
857 | ti++; | 872 | ti++; |
858 | tunnel = NULL; | 873 | tunnel = NULL; |
@@ -862,8 +877,11 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback | |||
862 | 877 | ||
863 | if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid, | 878 | if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid, |
864 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 879 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
865 | session, L2TP_CMD_SESSION_GET) < 0) | 880 | session, L2TP_CMD_SESSION_GET) < 0) { |
881 | l2tp_session_dec_refcount(session); | ||
866 | break; | 882 | break; |
883 | } | ||
884 | l2tp_session_dec_refcount(session); | ||
867 | 885 | ||
868 | si++; | 886 | si++; |
869 | } | 887 | } |
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 36cc56fd0418..861b255a2d51 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c | |||
@@ -450,6 +450,10 @@ static void pppol2tp_session_close(struct l2tp_session *session) | |||
450 | static void pppol2tp_session_destruct(struct sock *sk) | 450 | static void pppol2tp_session_destruct(struct sock *sk) |
451 | { | 451 | { |
452 | struct l2tp_session *session = sk->sk_user_data; | 452 | struct l2tp_session *session = sk->sk_user_data; |
453 | |||
454 | skb_queue_purge(&sk->sk_receive_queue); | ||
455 | skb_queue_purge(&sk->sk_write_queue); | ||
456 | |||
453 | if (session) { | 457 | if (session) { |
454 | sk->sk_user_data = NULL; | 458 | sk->sk_user_data = NULL; |
455 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); | 459 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); |
@@ -488,9 +492,6 @@ static int pppol2tp_release(struct socket *sock) | |||
488 | l2tp_session_queue_purge(session); | 492 | l2tp_session_queue_purge(session); |
489 | sock_put(sk); | 493 | sock_put(sk); |
490 | } | 494 | } |
491 | skb_queue_purge(&sk->sk_receive_queue); | ||
492 | skb_queue_purge(&sk->sk_write_queue); | ||
493 | |||
494 | release_sock(sk); | 495 | release_sock(sk); |
495 | 496 | ||
496 | /* This will delete the session context via | 497 | /* This will delete the session context via |
@@ -582,6 +583,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
582 | int error = 0; | 583 | int error = 0; |
583 | u32 tunnel_id, peer_tunnel_id; | 584 | u32 tunnel_id, peer_tunnel_id; |
584 | u32 session_id, peer_session_id; | 585 | u32 session_id, peer_session_id; |
586 | bool drop_refcnt = false; | ||
585 | int ver = 2; | 587 | int ver = 2; |
586 | int fd; | 588 | int fd; |
587 | 589 | ||
@@ -683,36 +685,36 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
683 | if (tunnel->peer_tunnel_id == 0) | 685 | if (tunnel->peer_tunnel_id == 0) |
684 | tunnel->peer_tunnel_id = peer_tunnel_id; | 686 | tunnel->peer_tunnel_id = peer_tunnel_id; |
685 | 687 | ||
686 | /* Create session if it doesn't already exist. We handle the | 688 | session = l2tp_session_get(sock_net(sk), tunnel, session_id, false); |
687 | * case where a session was previously created by the netlink | 689 | if (session) { |
688 | * interface by checking that the session doesn't already have | 690 | drop_refcnt = true; |
689 | * a socket and its tunnel socket are what we expect. If any | 691 | ps = l2tp_session_priv(session); |
690 | * of those checks fail, return EEXIST to the caller. | 692 | |
691 | */ | 693 | /* Using a pre-existing session is fine as long as it hasn't |
692 | session = l2tp_session_find(sock_net(sk), tunnel, session_id); | 694 | * been connected yet. |
693 | if (session == NULL) { | ||
694 | /* Default MTU must allow space for UDP/L2TP/PPP | ||
695 | * headers. | ||
696 | */ | 695 | */ |
697 | cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; | 696 | if (ps->sock) { |
697 | error = -EEXIST; | ||
698 | goto end; | ||
699 | } | ||
698 | 700 | ||
699 | /* Allocate and initialize a new session context. */ | 701 | /* consistency checks */ |
700 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | 702 | if (ps->tunnel_sock != tunnel->sock) { |
701 | tunnel, session_id, | 703 | error = -EEXIST; |
702 | peer_session_id, &cfg); | ||
703 | if (session == NULL) { | ||
704 | error = -ENOMEM; | ||
705 | goto end; | 704 | goto end; |
706 | } | 705 | } |
707 | } else { | 706 | } else { |
708 | ps = l2tp_session_priv(session); | 707 | /* Default MTU must allow space for UDP/L2TP/PPP headers */ |
709 | error = -EEXIST; | 708 | cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; |
710 | if (ps->sock != NULL) | 709 | cfg.mru = cfg.mtu; |
711 | goto end; | ||
712 | 710 | ||
713 | /* consistency checks */ | 711 | session = l2tp_session_create(sizeof(struct pppol2tp_session), |
714 | if (ps->tunnel_sock != tunnel->sock) | 712 | tunnel, session_id, |
713 | peer_session_id, &cfg); | ||
714 | if (IS_ERR(session)) { | ||
715 | error = PTR_ERR(session); | ||
715 | goto end; | 716 | goto end; |
717 | } | ||
716 | } | 718 | } |
717 | 719 | ||
718 | /* Associate session with its PPPoL2TP socket */ | 720 | /* Associate session with its PPPoL2TP socket */ |
@@ -777,6 +779,8 @@ out_no_ppp: | |||
777 | session->name); | 779 | session->name); |
778 | 780 | ||
779 | end: | 781 | end: |
782 | if (drop_refcnt) | ||
783 | l2tp_session_dec_refcount(session); | ||
780 | release_sock(sk); | 784 | release_sock(sk); |
781 | 785 | ||
782 | return error; | 786 | return error; |
@@ -804,12 +808,6 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i | |||
804 | if (tunnel->sock == NULL) | 808 | if (tunnel->sock == NULL) |
805 | goto out; | 809 | goto out; |
806 | 810 | ||
807 | /* Check that this session doesn't already exist */ | ||
808 | error = -EEXIST; | ||
809 | session = l2tp_session_find(net, tunnel, session_id); | ||
810 | if (session != NULL) | ||
811 | goto out; | ||
812 | |||
813 | /* Default MTU values. */ | 811 | /* Default MTU values. */ |
814 | if (cfg->mtu == 0) | 812 | if (cfg->mtu == 0) |
815 | cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; | 813 | cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; |
@@ -817,12 +815,13 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i | |||
817 | cfg->mru = cfg->mtu; | 815 | cfg->mru = cfg->mtu; |
818 | 816 | ||
819 | /* Allocate and initialize a new session context. */ | 817 | /* Allocate and initialize a new session context. */ |
820 | error = -ENOMEM; | ||
821 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | 818 | session = l2tp_session_create(sizeof(struct pppol2tp_session), |
822 | tunnel, session_id, | 819 | tunnel, session_id, |
823 | peer_session_id, cfg); | 820 | peer_session_id, cfg); |
824 | if (session == NULL) | 821 | if (IS_ERR(session)) { |
822 | error = PTR_ERR(session); | ||
825 | goto out; | 823 | goto out; |
824 | } | ||
826 | 825 | ||
827 | ps = l2tp_session_priv(session); | 826 | ps = l2tp_session_priv(session); |
828 | ps->tunnel_sock = tunnel->sock; | 827 | ps->tunnel_sock = tunnel->sock; |
@@ -1140,11 +1139,18 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel, | |||
1140 | if (stats.session_id != 0) { | 1139 | if (stats.session_id != 0) { |
1141 | /* resend to session ioctl handler */ | 1140 | /* resend to session ioctl handler */ |
1142 | struct l2tp_session *session = | 1141 | struct l2tp_session *session = |
1143 | l2tp_session_find(sock_net(sk), tunnel, stats.session_id); | 1142 | l2tp_session_get(sock_net(sk), tunnel, |
1144 | if (session != NULL) | 1143 | stats.session_id, true); |
1145 | err = pppol2tp_session_ioctl(session, cmd, arg); | 1144 | |
1146 | else | 1145 | if (session) { |
1146 | err = pppol2tp_session_ioctl(session, cmd, | ||
1147 | arg); | ||
1148 | if (session->deref) | ||
1149 | session->deref(session); | ||
1150 | l2tp_session_dec_refcount(session); | ||
1151 | } else { | ||
1147 | err = -EBADR; | 1152 | err = -EBADR; |
1153 | } | ||
1148 | break; | 1154 | break; |
1149 | } | 1155 | } |
1150 | #ifdef CONFIG_XFRM | 1156 | #ifdef CONFIG_XFRM |
@@ -1554,7 +1560,7 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd) | |||
1554 | 1560 | ||
1555 | static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) | 1561 | static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) |
1556 | { | 1562 | { |
1557 | pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); | 1563 | pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); |
1558 | pd->session_idx++; | 1564 | pd->session_idx++; |
1559 | 1565 | ||
1560 | if (pd->session == NULL) { | 1566 | if (pd->session == NULL) { |
@@ -1681,10 +1687,14 @@ static int pppol2tp_seq_show(struct seq_file *m, void *v) | |||
1681 | 1687 | ||
1682 | /* Show the tunnel or session context. | 1688 | /* Show the tunnel or session context. |
1683 | */ | 1689 | */ |
1684 | if (pd->session == NULL) | 1690 | if (!pd->session) { |
1685 | pppol2tp_seq_tunnel_show(m, pd->tunnel); | 1691 | pppol2tp_seq_tunnel_show(m, pd->tunnel); |
1686 | else | 1692 | } else { |
1687 | pppol2tp_seq_session_show(m, pd->session); | 1693 | pppol2tp_seq_session_show(m, pd->session); |
1694 | if (pd->session->deref) | ||
1695 | pd->session->deref(pd->session); | ||
1696 | l2tp_session_dec_refcount(pd->session); | ||
1697 | } | ||
1688 | 1698 | ||
1689 | out: | 1699 | out: |
1690 | return 0; | 1700 | return 0; |
@@ -1843,4 +1853,4 @@ MODULE_DESCRIPTION("PPP over L2TP over UDP"); | |||
1843 | MODULE_LICENSE("GPL"); | 1853 | MODULE_LICENSE("GPL"); |
1844 | MODULE_VERSION(PPPOL2TP_DRV_VERSION); | 1854 | MODULE_VERSION(PPPOL2TP_DRV_VERSION); |
1845 | MODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_OL2TP); | 1855 | MODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_OL2TP); |
1846 | MODULE_ALIAS_L2TP_PWTYPE(11); | 1856 | MODULE_ALIAS_L2TP_PWTYPE(7); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 40813dd3301c..5bb0c5012819 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -718,7 +718,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
718 | ieee80211_recalc_ps(local); | 718 | ieee80211_recalc_ps(local); |
719 | 719 | ||
720 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | 720 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || |
721 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | 721 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
722 | local->ops->wake_tx_queue) { | ||
722 | /* XXX: for AP_VLAN, actually track AP queues */ | 723 | /* XXX: for AP_VLAN, actually track AP queues */ |
723 | netif_tx_start_all_queues(dev); | 724 | netif_tx_start_all_queues(dev); |
724 | } else if (dev) { | 725 | } else if (dev) { |
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index da9df2d56e66..22fc32143e9c 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c | |||
@@ -290,6 +290,7 @@ void nf_conntrack_unregister_notifier(struct net *net, | |||
290 | BUG_ON(notify != new); | 290 | BUG_ON(notify != new); |
291 | RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL); | 291 | RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL); |
292 | mutex_unlock(&nf_ct_ecache_mutex); | 292 | mutex_unlock(&nf_ct_ecache_mutex); |
293 | /* synchronize_rcu() is called from ctnetlink_exit. */ | ||
293 | } | 294 | } |
294 | EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); | 295 | EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); |
295 | 296 | ||
@@ -326,6 +327,7 @@ void nf_ct_expect_unregister_notifier(struct net *net, | |||
326 | BUG_ON(notify != new); | 327 | BUG_ON(notify != new); |
327 | RCU_INIT_POINTER(net->ct.nf_expect_event_cb, NULL); | 328 | RCU_INIT_POINTER(net->ct.nf_expect_event_cb, NULL); |
328 | mutex_unlock(&nf_ct_ecache_mutex); | 329 | mutex_unlock(&nf_ct_ecache_mutex); |
330 | /* synchronize_rcu() is called from ctnetlink_exit. */ | ||
329 | } | 331 | } |
330 | EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); | 332 | EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); |
331 | 333 | ||
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 02bcf00c2492..008299b7f78f 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c | |||
@@ -53,7 +53,11 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, | |||
53 | 53 | ||
54 | rcu_read_lock(); | 54 | rcu_read_lock(); |
55 | t = rcu_dereference(nf_ct_ext_types[id]); | 55 | t = rcu_dereference(nf_ct_ext_types[id]); |
56 | BUG_ON(t == NULL); | 56 | if (!t) { |
57 | rcu_read_unlock(); | ||
58 | return NULL; | ||
59 | } | ||
60 | |||
57 | off = ALIGN(sizeof(struct nf_ct_ext), t->align); | 61 | off = ALIGN(sizeof(struct nf_ct_ext), t->align); |
58 | len = off + t->len + var_alloc_len; | 62 | len = off + t->len + var_alloc_len; |
59 | alloc_size = t->alloc_size + var_alloc_len; | 63 | alloc_size = t->alloc_size + var_alloc_len; |
@@ -88,7 +92,10 @@ void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id, | |||
88 | 92 | ||
89 | rcu_read_lock(); | 93 | rcu_read_lock(); |
90 | t = rcu_dereference(nf_ct_ext_types[id]); | 94 | t = rcu_dereference(nf_ct_ext_types[id]); |
91 | BUG_ON(t == NULL); | 95 | if (!t) { |
96 | rcu_read_unlock(); | ||
97 | return NULL; | ||
98 | } | ||
92 | 99 | ||
93 | newoff = ALIGN(old->len, t->align); | 100 | newoff = ALIGN(old->len, t->align); |
94 | newlen = newoff + t->len + var_alloc_len; | 101 | newlen = newoff + t->len + var_alloc_len; |
@@ -175,6 +182,6 @@ void nf_ct_extend_unregister(struct nf_ct_ext_type *type) | |||
175 | RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL); | 182 | RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL); |
176 | update_alloc_size(type); | 183 | update_alloc_size(type); |
177 | mutex_unlock(&nf_ct_ext_type_mutex); | 184 | mutex_unlock(&nf_ct_ext_type_mutex); |
178 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 185 | synchronize_rcu(); |
179 | } | 186 | } |
180 | EXPORT_SYMBOL_GPL(nf_ct_extend_unregister); | 187 | EXPORT_SYMBOL_GPL(nf_ct_extend_unregister); |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 6806b5e73567..908d858034e4 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -3442,6 +3442,7 @@ static void __exit ctnetlink_exit(void) | |||
3442 | #ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT | 3442 | #ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT |
3443 | RCU_INIT_POINTER(nfnl_ct_hook, NULL); | 3443 | RCU_INIT_POINTER(nfnl_ct_hook, NULL); |
3444 | #endif | 3444 | #endif |
3445 | synchronize_rcu(); | ||
3445 | } | 3446 | } |
3446 | 3447 | ||
3447 | module_init(ctnetlink_init); | 3448 | module_init(ctnetlink_init); |
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 94b14c5a8b17..82802e4a6640 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c | |||
@@ -903,6 +903,8 @@ static void __exit nf_nat_cleanup(void) | |||
903 | #ifdef CONFIG_XFRM | 903 | #ifdef CONFIG_XFRM |
904 | RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); | 904 | RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); |
905 | #endif | 905 | #endif |
906 | synchronize_rcu(); | ||
907 | |||
906 | for (i = 0; i < NFPROTO_NUMPROTO; i++) | 908 | for (i = 0; i < NFPROTO_NUMPROTO; i++) |
907 | kfree(nf_nat_l4protos[i]); | 909 | kfree(nf_nat_l4protos[i]); |
908 | 910 | ||
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index de8782345c86..d45558178da5 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c | |||
@@ -32,6 +32,13 @@ MODULE_LICENSE("GPL"); | |||
32 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | 32 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); |
33 | MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers"); | 33 | MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers"); |
34 | 34 | ||
35 | struct nfnl_cthelper { | ||
36 | struct list_head list; | ||
37 | struct nf_conntrack_helper helper; | ||
38 | }; | ||
39 | |||
40 | static LIST_HEAD(nfnl_cthelper_list); | ||
41 | |||
35 | static int | 42 | static int |
36 | nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff, | 43 | nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff, |
37 | struct nf_conn *ct, enum ip_conntrack_info ctinfo) | 44 | struct nf_conn *ct, enum ip_conntrack_info ctinfo) |
@@ -161,6 +168,7 @@ nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper, | |||
161 | int i, ret; | 168 | int i, ret; |
162 | struct nf_conntrack_expect_policy *expect_policy; | 169 | struct nf_conntrack_expect_policy *expect_policy; |
163 | struct nlattr *tb[NFCTH_POLICY_SET_MAX+1]; | 170 | struct nlattr *tb[NFCTH_POLICY_SET_MAX+1]; |
171 | unsigned int class_max; | ||
164 | 172 | ||
165 | ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr, | 173 | ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr, |
166 | nfnl_cthelper_expect_policy_set); | 174 | nfnl_cthelper_expect_policy_set); |
@@ -170,19 +178,18 @@ nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper, | |||
170 | if (!tb[NFCTH_POLICY_SET_NUM]) | 178 | if (!tb[NFCTH_POLICY_SET_NUM]) |
171 | return -EINVAL; | 179 | return -EINVAL; |
172 | 180 | ||
173 | helper->expect_class_max = | 181 | class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM])); |
174 | ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM])); | 182 | if (class_max == 0) |
175 | 183 | return -EINVAL; | |
176 | if (helper->expect_class_max != 0 && | 184 | if (class_max > NF_CT_MAX_EXPECT_CLASSES) |
177 | helper->expect_class_max > NF_CT_MAX_EXPECT_CLASSES) | ||
178 | return -EOVERFLOW; | 185 | return -EOVERFLOW; |
179 | 186 | ||
180 | expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) * | 187 | expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) * |
181 | helper->expect_class_max, GFP_KERNEL); | 188 | class_max, GFP_KERNEL); |
182 | if (expect_policy == NULL) | 189 | if (expect_policy == NULL) |
183 | return -ENOMEM; | 190 | return -ENOMEM; |
184 | 191 | ||
185 | for (i=0; i<helper->expect_class_max; i++) { | 192 | for (i = 0; i < class_max; i++) { |
186 | if (!tb[NFCTH_POLICY_SET+i]) | 193 | if (!tb[NFCTH_POLICY_SET+i]) |
187 | goto err; | 194 | goto err; |
188 | 195 | ||
@@ -191,6 +198,8 @@ nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper, | |||
191 | if (ret < 0) | 198 | if (ret < 0) |
192 | goto err; | 199 | goto err; |
193 | } | 200 | } |
201 | |||
202 | helper->expect_class_max = class_max - 1; | ||
194 | helper->expect_policy = expect_policy; | 203 | helper->expect_policy = expect_policy; |
195 | return 0; | 204 | return 0; |
196 | err: | 205 | err: |
@@ -203,18 +212,20 @@ nfnl_cthelper_create(const struct nlattr * const tb[], | |||
203 | struct nf_conntrack_tuple *tuple) | 212 | struct nf_conntrack_tuple *tuple) |
204 | { | 213 | { |
205 | struct nf_conntrack_helper *helper; | 214 | struct nf_conntrack_helper *helper; |
215 | struct nfnl_cthelper *nfcth; | ||
206 | int ret; | 216 | int ret; |
207 | 217 | ||
208 | if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN]) | 218 | if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN]) |
209 | return -EINVAL; | 219 | return -EINVAL; |
210 | 220 | ||
211 | helper = kzalloc(sizeof(struct nf_conntrack_helper), GFP_KERNEL); | 221 | nfcth = kzalloc(sizeof(*nfcth), GFP_KERNEL); |
212 | if (helper == NULL) | 222 | if (nfcth == NULL) |
213 | return -ENOMEM; | 223 | return -ENOMEM; |
224 | helper = &nfcth->helper; | ||
214 | 225 | ||
215 | ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]); | 226 | ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]); |
216 | if (ret < 0) | 227 | if (ret < 0) |
217 | goto err; | 228 | goto err1; |
218 | 229 | ||
219 | strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN); | 230 | strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN); |
220 | helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN])); | 231 | helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN])); |
@@ -245,15 +256,101 @@ nfnl_cthelper_create(const struct nlattr * const tb[], | |||
245 | 256 | ||
246 | ret = nf_conntrack_helper_register(helper); | 257 | ret = nf_conntrack_helper_register(helper); |
247 | if (ret < 0) | 258 | if (ret < 0) |
248 | goto err; | 259 | goto err2; |
249 | 260 | ||
261 | list_add_tail(&nfcth->list, &nfnl_cthelper_list); | ||
250 | return 0; | 262 | return 0; |
251 | err: | 263 | err2: |
252 | kfree(helper); | 264 | kfree(helper->expect_policy); |
265 | err1: | ||
266 | kfree(nfcth); | ||
253 | return ret; | 267 | return ret; |
254 | } | 268 | } |
255 | 269 | ||
256 | static int | 270 | static int |
271 | nfnl_cthelper_update_policy_one(const struct nf_conntrack_expect_policy *policy, | ||
272 | struct nf_conntrack_expect_policy *new_policy, | ||
273 | const struct nlattr *attr) | ||
274 | { | ||
275 | struct nlattr *tb[NFCTH_POLICY_MAX + 1]; | ||
276 | int err; | ||
277 | |||
278 | err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr, | ||
279 | nfnl_cthelper_expect_pol); | ||
280 | if (err < 0) | ||
281 | return err; | ||
282 | |||
283 | if (!tb[NFCTH_POLICY_NAME] || | ||
284 | !tb[NFCTH_POLICY_EXPECT_MAX] || | ||
285 | !tb[NFCTH_POLICY_EXPECT_TIMEOUT]) | ||
286 | return -EINVAL; | ||
287 | |||
288 | if (nla_strcmp(tb[NFCTH_POLICY_NAME], policy->name)) | ||
289 | return -EBUSY; | ||
290 | |||
291 | new_policy->max_expected = | ||
292 | ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX])); | ||
293 | new_policy->timeout = | ||
294 | ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT])); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int nfnl_cthelper_update_policy_all(struct nlattr *tb[], | ||
300 | struct nf_conntrack_helper *helper) | ||
301 | { | ||
302 | struct nf_conntrack_expect_policy new_policy[helper->expect_class_max + 1]; | ||
303 | struct nf_conntrack_expect_policy *policy; | ||
304 | int i, err; | ||
305 | |||
306 | /* Check first that all policy attributes are well-formed, so we don't | ||
307 | * leave things in inconsistent state on errors. | ||
308 | */ | ||
309 | for (i = 0; i < helper->expect_class_max + 1; i++) { | ||
310 | |||
311 | if (!tb[NFCTH_POLICY_SET + i]) | ||
312 | return -EINVAL; | ||
313 | |||
314 | err = nfnl_cthelper_update_policy_one(&helper->expect_policy[i], | ||
315 | &new_policy[i], | ||
316 | tb[NFCTH_POLICY_SET + i]); | ||
317 | if (err < 0) | ||
318 | return err; | ||
319 | } | ||
320 | /* Now we can safely update them. */ | ||
321 | for (i = 0; i < helper->expect_class_max + 1; i++) { | ||
322 | policy = (struct nf_conntrack_expect_policy *) | ||
323 | &helper->expect_policy[i]; | ||
324 | policy->max_expected = new_policy->max_expected; | ||
325 | policy->timeout = new_policy->timeout; | ||
326 | } | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int nfnl_cthelper_update_policy(struct nf_conntrack_helper *helper, | ||
332 | const struct nlattr *attr) | ||
333 | { | ||
334 | struct nlattr *tb[NFCTH_POLICY_SET_MAX + 1]; | ||
335 | unsigned int class_max; | ||
336 | int err; | ||
337 | |||
338 | err = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr, | ||
339 | nfnl_cthelper_expect_policy_set); | ||
340 | if (err < 0) | ||
341 | return err; | ||
342 | |||
343 | if (!tb[NFCTH_POLICY_SET_NUM]) | ||
344 | return -EINVAL; | ||
345 | |||
346 | class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM])); | ||
347 | if (helper->expect_class_max + 1 != class_max) | ||
348 | return -EBUSY; | ||
349 | |||
350 | return nfnl_cthelper_update_policy_all(tb, helper); | ||
351 | } | ||
352 | |||
353 | static int | ||
257 | nfnl_cthelper_update(const struct nlattr * const tb[], | 354 | nfnl_cthelper_update(const struct nlattr * const tb[], |
258 | struct nf_conntrack_helper *helper) | 355 | struct nf_conntrack_helper *helper) |
259 | { | 356 | { |
@@ -263,8 +360,7 @@ nfnl_cthelper_update(const struct nlattr * const tb[], | |||
263 | return -EBUSY; | 360 | return -EBUSY; |
264 | 361 | ||
265 | if (tb[NFCTH_POLICY]) { | 362 | if (tb[NFCTH_POLICY]) { |
266 | ret = nfnl_cthelper_parse_expect_policy(helper, | 363 | ret = nfnl_cthelper_update_policy(helper, tb[NFCTH_POLICY]); |
267 | tb[NFCTH_POLICY]); | ||
268 | if (ret < 0) | 364 | if (ret < 0) |
269 | return ret; | 365 | return ret; |
270 | } | 366 | } |
@@ -293,7 +389,8 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, | |||
293 | const char *helper_name; | 389 | const char *helper_name; |
294 | struct nf_conntrack_helper *cur, *helper = NULL; | 390 | struct nf_conntrack_helper *cur, *helper = NULL; |
295 | struct nf_conntrack_tuple tuple; | 391 | struct nf_conntrack_tuple tuple; |
296 | int ret = 0, i; | 392 | struct nfnl_cthelper *nlcth; |
393 | int ret = 0; | ||
297 | 394 | ||
298 | if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE]) | 395 | if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE]) |
299 | return -EINVAL; | 396 | return -EINVAL; |
@@ -304,31 +401,22 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, | |||
304 | if (ret < 0) | 401 | if (ret < 0) |
305 | return ret; | 402 | return ret; |
306 | 403 | ||
307 | rcu_read_lock(); | 404 | list_for_each_entry(nlcth, &nfnl_cthelper_list, list) { |
308 | for (i = 0; i < nf_ct_helper_hsize && !helper; i++) { | 405 | cur = &nlcth->helper; |
309 | hlist_for_each_entry_rcu(cur, &nf_ct_helper_hash[i], hnode) { | ||
310 | 406 | ||
311 | /* skip non-userspace conntrack helpers. */ | 407 | if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN)) |
312 | if (!(cur->flags & NF_CT_HELPER_F_USERSPACE)) | 408 | continue; |
313 | continue; | ||
314 | 409 | ||
315 | if (strncmp(cur->name, helper_name, | 410 | if ((tuple.src.l3num != cur->tuple.src.l3num || |
316 | NF_CT_HELPER_NAME_LEN) != 0) | 411 | tuple.dst.protonum != cur->tuple.dst.protonum)) |
317 | continue; | 412 | continue; |
318 | 413 | ||
319 | if ((tuple.src.l3num != cur->tuple.src.l3num || | 414 | if (nlh->nlmsg_flags & NLM_F_EXCL) |
320 | tuple.dst.protonum != cur->tuple.dst.protonum)) | 415 | return -EEXIST; |
321 | continue; | ||
322 | 416 | ||
323 | if (nlh->nlmsg_flags & NLM_F_EXCL) { | 417 | helper = cur; |
324 | ret = -EEXIST; | 418 | break; |
325 | goto err; | ||
326 | } | ||
327 | helper = cur; | ||
328 | break; | ||
329 | } | ||
330 | } | 419 | } |
331 | rcu_read_unlock(); | ||
332 | 420 | ||
333 | if (helper == NULL) | 421 | if (helper == NULL) |
334 | ret = nfnl_cthelper_create(tb, &tuple); | 422 | ret = nfnl_cthelper_create(tb, &tuple); |
@@ -336,9 +424,6 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, | |||
336 | ret = nfnl_cthelper_update(tb, helper); | 424 | ret = nfnl_cthelper_update(tb, helper); |
337 | 425 | ||
338 | return ret; | 426 | return ret; |
339 | err: | ||
340 | rcu_read_unlock(); | ||
341 | return ret; | ||
342 | } | 427 | } |
343 | 428 | ||
344 | static int | 429 | static int |
@@ -377,10 +462,10 @@ nfnl_cthelper_dump_policy(struct sk_buff *skb, | |||
377 | goto nla_put_failure; | 462 | goto nla_put_failure; |
378 | 463 | ||
379 | if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM, | 464 | if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM, |
380 | htonl(helper->expect_class_max))) | 465 | htonl(helper->expect_class_max + 1))) |
381 | goto nla_put_failure; | 466 | goto nla_put_failure; |
382 | 467 | ||
383 | for (i=0; i<helper->expect_class_max; i++) { | 468 | for (i = 0; i < helper->expect_class_max + 1; i++) { |
384 | nest_parms2 = nla_nest_start(skb, | 469 | nest_parms2 = nla_nest_start(skb, |
385 | (NFCTH_POLICY_SET+i) | NLA_F_NESTED); | 470 | (NFCTH_POLICY_SET+i) | NLA_F_NESTED); |
386 | if (nest_parms2 == NULL) | 471 | if (nest_parms2 == NULL) |
@@ -502,11 +587,12 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, | |||
502 | struct sk_buff *skb, const struct nlmsghdr *nlh, | 587 | struct sk_buff *skb, const struct nlmsghdr *nlh, |
503 | const struct nlattr * const tb[]) | 588 | const struct nlattr * const tb[]) |
504 | { | 589 | { |
505 | int ret = -ENOENT, i; | 590 | int ret = -ENOENT; |
506 | struct nf_conntrack_helper *cur; | 591 | struct nf_conntrack_helper *cur; |
507 | struct sk_buff *skb2; | 592 | struct sk_buff *skb2; |
508 | char *helper_name = NULL; | 593 | char *helper_name = NULL; |
509 | struct nf_conntrack_tuple tuple; | 594 | struct nf_conntrack_tuple tuple; |
595 | struct nfnl_cthelper *nlcth; | ||
510 | bool tuple_set = false; | 596 | bool tuple_set = false; |
511 | 597 | ||
512 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 598 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
@@ -527,45 +613,39 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, | |||
527 | tuple_set = true; | 613 | tuple_set = true; |
528 | } | 614 | } |
529 | 615 | ||
530 | for (i = 0; i < nf_ct_helper_hsize; i++) { | 616 | list_for_each_entry(nlcth, &nfnl_cthelper_list, list) { |
531 | hlist_for_each_entry_rcu(cur, &nf_ct_helper_hash[i], hnode) { | 617 | cur = &nlcth->helper; |
618 | if (helper_name && | ||
619 | strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN)) | ||
620 | continue; | ||
532 | 621 | ||
533 | /* skip non-userspace conntrack helpers. */ | 622 | if (tuple_set && |
534 | if (!(cur->flags & NF_CT_HELPER_F_USERSPACE)) | 623 | (tuple.src.l3num != cur->tuple.src.l3num || |
535 | continue; | 624 | tuple.dst.protonum != cur->tuple.dst.protonum)) |
625 | continue; | ||
536 | 626 | ||
537 | if (helper_name && strncmp(cur->name, helper_name, | 627 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
538 | NF_CT_HELPER_NAME_LEN) != 0) { | 628 | if (skb2 == NULL) { |
539 | continue; | 629 | ret = -ENOMEM; |
540 | } | 630 | break; |
541 | if (tuple_set && | 631 | } |
542 | (tuple.src.l3num != cur->tuple.src.l3num || | ||
543 | tuple.dst.protonum != cur->tuple.dst.protonum)) | ||
544 | continue; | ||
545 | |||
546 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
547 | if (skb2 == NULL) { | ||
548 | ret = -ENOMEM; | ||
549 | break; | ||
550 | } | ||
551 | 632 | ||
552 | ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid, | 633 | ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid, |
553 | nlh->nlmsg_seq, | 634 | nlh->nlmsg_seq, |
554 | NFNL_MSG_TYPE(nlh->nlmsg_type), | 635 | NFNL_MSG_TYPE(nlh->nlmsg_type), |
555 | NFNL_MSG_CTHELPER_NEW, cur); | 636 | NFNL_MSG_CTHELPER_NEW, cur); |
556 | if (ret <= 0) { | 637 | if (ret <= 0) { |
557 | kfree_skb(skb2); | 638 | kfree_skb(skb2); |
558 | break; | 639 | break; |
559 | } | 640 | } |
560 | 641 | ||
561 | ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, | 642 | ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, |
562 | MSG_DONTWAIT); | 643 | MSG_DONTWAIT); |
563 | if (ret > 0) | 644 | if (ret > 0) |
564 | ret = 0; | 645 | ret = 0; |
565 | 646 | ||
566 | /* this avoids a loop in nfnetlink. */ | 647 | /* this avoids a loop in nfnetlink. */ |
567 | return ret == -EAGAIN ? -ENOBUFS : ret; | 648 | return ret == -EAGAIN ? -ENOBUFS : ret; |
568 | } | ||
569 | } | 649 | } |
570 | return ret; | 650 | return ret; |
571 | } | 651 | } |
@@ -576,10 +656,10 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, | |||
576 | { | 656 | { |
577 | char *helper_name = NULL; | 657 | char *helper_name = NULL; |
578 | struct nf_conntrack_helper *cur; | 658 | struct nf_conntrack_helper *cur; |
579 | struct hlist_node *tmp; | ||
580 | struct nf_conntrack_tuple tuple; | 659 | struct nf_conntrack_tuple tuple; |
581 | bool tuple_set = false, found = false; | 660 | bool tuple_set = false, found = false; |
582 | int i, j = 0, ret; | 661 | struct nfnl_cthelper *nlcth, *n; |
662 | int j = 0, ret; | ||
583 | 663 | ||
584 | if (tb[NFCTH_NAME]) | 664 | if (tb[NFCTH_NAME]) |
585 | helper_name = nla_data(tb[NFCTH_NAME]); | 665 | helper_name = nla_data(tb[NFCTH_NAME]); |
@@ -592,28 +672,27 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, | |||
592 | tuple_set = true; | 672 | tuple_set = true; |
593 | } | 673 | } |
594 | 674 | ||
595 | for (i = 0; i < nf_ct_helper_hsize; i++) { | 675 | list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) { |
596 | hlist_for_each_entry_safe(cur, tmp, &nf_ct_helper_hash[i], | 676 | cur = &nlcth->helper; |
597 | hnode) { | 677 | j++; |
598 | /* skip non-userspace conntrack helpers. */ | ||
599 | if (!(cur->flags & NF_CT_HELPER_F_USERSPACE)) | ||
600 | continue; | ||
601 | 678 | ||
602 | j++; | 679 | if (helper_name && |
680 | strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN)) | ||
681 | continue; | ||
603 | 682 | ||
604 | if (helper_name && strncmp(cur->name, helper_name, | 683 | if (tuple_set && |
605 | NF_CT_HELPER_NAME_LEN) != 0) { | 684 | (tuple.src.l3num != cur->tuple.src.l3num || |
606 | continue; | 685 | tuple.dst.protonum != cur->tuple.dst.protonum)) |
607 | } | 686 | continue; |
608 | if (tuple_set && | ||
609 | (tuple.src.l3num != cur->tuple.src.l3num || | ||
610 | tuple.dst.protonum != cur->tuple.dst.protonum)) | ||
611 | continue; | ||
612 | 687 | ||
613 | found = true; | 688 | found = true; |
614 | nf_conntrack_helper_unregister(cur); | 689 | nf_conntrack_helper_unregister(cur); |
615 | } | 690 | kfree(cur->expect_policy); |
691 | |||
692 | list_del(&nlcth->list); | ||
693 | kfree(nlcth); | ||
616 | } | 694 | } |
695 | |||
617 | /* Make sure we return success if we flush and there is no helpers */ | 696 | /* Make sure we return success if we flush and there is no helpers */ |
618 | return (found || j == 0) ? 0 : -ENOENT; | 697 | return (found || j == 0) ? 0 : -ENOENT; |
619 | } | 698 | } |
@@ -662,20 +741,16 @@ err_out: | |||
662 | static void __exit nfnl_cthelper_exit(void) | 741 | static void __exit nfnl_cthelper_exit(void) |
663 | { | 742 | { |
664 | struct nf_conntrack_helper *cur; | 743 | struct nf_conntrack_helper *cur; |
665 | struct hlist_node *tmp; | 744 | struct nfnl_cthelper *nlcth, *n; |
666 | int i; | ||
667 | 745 | ||
668 | nfnetlink_subsys_unregister(&nfnl_cthelper_subsys); | 746 | nfnetlink_subsys_unregister(&nfnl_cthelper_subsys); |
669 | 747 | ||
670 | for (i=0; i<nf_ct_helper_hsize; i++) { | 748 | list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) { |
671 | hlist_for_each_entry_safe(cur, tmp, &nf_ct_helper_hash[i], | 749 | cur = &nlcth->helper; |
672 | hnode) { | ||
673 | /* skip non-userspace conntrack helpers. */ | ||
674 | if (!(cur->flags & NF_CT_HELPER_F_USERSPACE)) | ||
675 | continue; | ||
676 | 750 | ||
677 | nf_conntrack_helper_unregister(cur); | 751 | nf_conntrack_helper_unregister(cur); |
678 | } | 752 | kfree(cur->expect_policy); |
753 | kfree(nlcth); | ||
679 | } | 754 | } |
680 | } | 755 | } |
681 | 756 | ||
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index 139e0867e56e..47d6656c9119 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c | |||
@@ -646,8 +646,8 @@ static void __exit cttimeout_exit(void) | |||
646 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 646 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
647 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); | 647 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); |
648 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); | 648 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); |
649 | synchronize_rcu(); | ||
649 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 650 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
650 | rcu_barrier(); | ||
651 | } | 651 | } |
652 | 652 | ||
653 | module_init(cttimeout_init); | 653 | module_init(cttimeout_init); |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 3ee0b8a000a4..933509ebf3d3 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -443,7 +443,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
443 | skb = alloc_skb(size, GFP_ATOMIC); | 443 | skb = alloc_skb(size, GFP_ATOMIC); |
444 | if (!skb) { | 444 | if (!skb) { |
445 | skb_tx_error(entskb); | 445 | skb_tx_error(entskb); |
446 | return NULL; | 446 | goto nlmsg_failure; |
447 | } | 447 | } |
448 | 448 | ||
449 | nlh = nlmsg_put(skb, 0, 0, | 449 | nlh = nlmsg_put(skb, 0, 0, |
@@ -452,7 +452,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
452 | if (!nlh) { | 452 | if (!nlh) { |
453 | skb_tx_error(entskb); | 453 | skb_tx_error(entskb); |
454 | kfree_skb(skb); | 454 | kfree_skb(skb); |
455 | return NULL; | 455 | goto nlmsg_failure; |
456 | } | 456 | } |
457 | nfmsg = nlmsg_data(nlh); | 457 | nfmsg = nlmsg_data(nlh); |
458 | nfmsg->nfgen_family = entry->state.pf; | 458 | nfmsg->nfgen_family = entry->state.pf; |
@@ -598,12 +598,17 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
598 | } | 598 | } |
599 | 599 | ||
600 | nlh->nlmsg_len = skb->len; | 600 | nlh->nlmsg_len = skb->len; |
601 | if (seclen) | ||
602 | security_release_secctx(secdata, seclen); | ||
601 | return skb; | 603 | return skb; |
602 | 604 | ||
603 | nla_put_failure: | 605 | nla_put_failure: |
604 | skb_tx_error(entskb); | 606 | skb_tx_error(entskb); |
605 | kfree_skb(skb); | 607 | kfree_skb(skb); |
606 | net_err_ratelimited("nf_queue: error creating packet message\n"); | 608 | net_err_ratelimited("nf_queue: error creating packet message\n"); |
609 | nlmsg_failure: | ||
610 | if (seclen) | ||
611 | security_release_secctx(secdata, seclen); | ||
607 | return NULL; | 612 | return NULL; |
608 | } | 613 | } |
609 | 614 | ||
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index e0a87776a010..7b2c2fce408a 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c | |||
@@ -643,8 +643,8 @@ static bool skb_nfct_cached(struct net *net, | |||
643 | */ | 643 | */ |
644 | if (nf_ct_is_confirmed(ct)) | 644 | if (nf_ct_is_confirmed(ct)) |
645 | nf_ct_delete(ct, 0, 0); | 645 | nf_ct_delete(ct, 0, 0); |
646 | else | 646 | |
647 | nf_conntrack_put(&ct->ct_general); | 647 | nf_conntrack_put(&ct->ct_general); |
648 | nf_ct_set(skb, NULL, 0); | 648 | nf_ct_set(skb, NULL, 0); |
649 | return false; | 649 | return false; |
650 | } | 650 | } |
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 9d4bb8eb63f2..3f76cb765e5b 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
@@ -527,7 +527,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
527 | 527 | ||
528 | /* Link layer. */ | 528 | /* Link layer. */ |
529 | clear_vlan(key); | 529 | clear_vlan(key); |
530 | if (key->mac_proto == MAC_PROTO_NONE) { | 530 | if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) { |
531 | if (unlikely(eth_type_vlan(skb->protocol))) | 531 | if (unlikely(eth_type_vlan(skb->protocol))) |
532 | return -EINVAL; | 532 | return -EINVAL; |
533 | 533 | ||
@@ -745,7 +745,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
745 | 745 | ||
746 | int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) | 746 | int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) |
747 | { | 747 | { |
748 | return key_extract(skb, key); | 748 | int res; |
749 | |||
750 | res = key_extract(skb, key); | ||
751 | if (!res) | ||
752 | key->mac_proto &= ~SW_FLOW_KEY_INVALID; | ||
753 | |||
754 | return res; | ||
749 | } | 755 | } |
750 | 756 | ||
751 | static int key_extract_mac_proto(struct sk_buff *skb) | 757 | static int key_extract_mac_proto(struct sk_buff *skb) |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a0dbe7ca8f72..8489beff5c25 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -3665,6 +3665,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
3665 | return -EBUSY; | 3665 | return -EBUSY; |
3666 | if (copy_from_user(&val, optval, sizeof(val))) | 3666 | if (copy_from_user(&val, optval, sizeof(val))) |
3667 | return -EFAULT; | 3667 | return -EFAULT; |
3668 | if (val > INT_MAX) | ||
3669 | return -EINVAL; | ||
3668 | po->tp_reserve = val; | 3670 | po->tp_reserve = val; |
3669 | return 0; | 3671 | return 0; |
3670 | } | 3672 | } |
@@ -4193,8 +4195,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, | |||
4193 | if (unlikely(!PAGE_ALIGNED(req->tp_block_size))) | 4195 | if (unlikely(!PAGE_ALIGNED(req->tp_block_size))) |
4194 | goto out; | 4196 | goto out; |
4195 | if (po->tp_version >= TPACKET_V3 && | 4197 | if (po->tp_version >= TPACKET_V3 && |
4196 | (int)(req->tp_block_size - | 4198 | req->tp_block_size <= |
4197 | BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0) | 4199 | BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv)) |
4198 | goto out; | 4200 | goto out; |
4199 | if (unlikely(req->tp_frame_size < po->tp_hdrlen + | 4201 | if (unlikely(req->tp_frame_size < po->tp_hdrlen + |
4200 | po->tp_reserve)) | 4202 | po->tp_reserve)) |
@@ -4205,6 +4207,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, | |||
4205 | rb->frames_per_block = req->tp_block_size / req->tp_frame_size; | 4207 | rb->frames_per_block = req->tp_block_size / req->tp_frame_size; |
4206 | if (unlikely(rb->frames_per_block == 0)) | 4208 | if (unlikely(rb->frames_per_block == 0)) |
4207 | goto out; | 4209 | goto out; |
4210 | if (unlikely(req->tp_block_size > UINT_MAX / req->tp_block_nr)) | ||
4211 | goto out; | ||
4208 | if (unlikely((rb->frames_per_block * req->tp_block_nr) != | 4212 | if (unlikely((rb->frames_per_block * req->tp_block_nr) != |
4209 | req->tp_frame_nr)) | 4213 | req->tp_frame_nr)) |
4210 | goto out; | 4214 | goto out; |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 0439a1a68367..a9708da28eb5 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -246,6 +246,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
246 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) | 246 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) |
247 | goto fail_init; | 247 | goto fail_init; |
248 | 248 | ||
249 | if (sctp_stream_new(asoc, gfp)) | ||
250 | goto fail_init; | ||
251 | |||
249 | /* Assume that peer would support both address types unless we are | 252 | /* Assume that peer would support both address types unless we are |
250 | * told otherwise. | 253 | * told otherwise. |
251 | */ | 254 | */ |
@@ -264,7 +267,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
264 | /* AUTH related initializations */ | 267 | /* AUTH related initializations */ |
265 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); | 268 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); |
266 | if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp)) | 269 | if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp)) |
267 | goto fail_init; | 270 | goto stream_free; |
268 | 271 | ||
269 | asoc->active_key_id = ep->active_key_id; | 272 | asoc->active_key_id = ep->active_key_id; |
270 | asoc->prsctp_enable = ep->prsctp_enable; | 273 | asoc->prsctp_enable = ep->prsctp_enable; |
@@ -287,6 +290,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
287 | 290 | ||
288 | return asoc; | 291 | return asoc; |
289 | 292 | ||
293 | stream_free: | ||
294 | sctp_stream_free(asoc->stream); | ||
290 | fail_init: | 295 | fail_init: |
291 | sock_put(asoc->base.sk); | 296 | sock_put(asoc->base.sk); |
292 | sctp_endpoint_put(asoc->ep); | 297 | sctp_endpoint_put(asoc->ep); |
@@ -1407,7 +1412,7 @@ sctp_assoc_choose_alter_transport(struct sctp_association *asoc, | |||
1407 | /* Update the association's pmtu and frag_point by going through all the | 1412 | /* Update the association's pmtu and frag_point by going through all the |
1408 | * transports. This routine is called when a transport's PMTU has changed. | 1413 | * transports. This routine is called when a transport's PMTU has changed. |
1409 | */ | 1414 | */ |
1410 | void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | 1415 | void sctp_assoc_sync_pmtu(struct sctp_association *asoc) |
1411 | { | 1416 | { |
1412 | struct sctp_transport *t; | 1417 | struct sctp_transport *t; |
1413 | __u32 pmtu = 0; | 1418 | __u32 pmtu = 0; |
@@ -1419,8 +1424,8 @@ void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | |||
1419 | list_for_each_entry(t, &asoc->peer.transport_addr_list, | 1424 | list_for_each_entry(t, &asoc->peer.transport_addr_list, |
1420 | transports) { | 1425 | transports) { |
1421 | if (t->pmtu_pending && t->dst) { | 1426 | if (t->pmtu_pending && t->dst) { |
1422 | sctp_transport_update_pmtu(sk, t, | 1427 | sctp_transport_update_pmtu( |
1423 | SCTP_TRUNC4(dst_mtu(t->dst))); | 1428 | t, SCTP_TRUNC4(dst_mtu(t->dst))); |
1424 | t->pmtu_pending = 0; | 1429 | t->pmtu_pending = 0; |
1425 | } | 1430 | } |
1426 | if (!pmtu || (t->pathmtu < pmtu)) | 1431 | if (!pmtu || (t->pathmtu < pmtu)) |
diff --git a/net/sctp/input.c b/net/sctp/input.c index 2a28ab20487f..0e06a278d2a9 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -401,10 +401,10 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, | |||
401 | 401 | ||
402 | if (t->param_flags & SPP_PMTUD_ENABLE) { | 402 | if (t->param_flags & SPP_PMTUD_ENABLE) { |
403 | /* Update transports view of the MTU */ | 403 | /* Update transports view of the MTU */ |
404 | sctp_transport_update_pmtu(sk, t, pmtu); | 404 | sctp_transport_update_pmtu(t, pmtu); |
405 | 405 | ||
406 | /* Update association pmtu. */ | 406 | /* Update association pmtu. */ |
407 | sctp_assoc_sync_pmtu(sk, asoc); | 407 | sctp_assoc_sync_pmtu(asoc); |
408 | } | 408 | } |
409 | 409 | ||
410 | /* Retransmit with the new pmtu setting. | 410 | /* Retransmit with the new pmtu setting. |
diff --git a/net/sctp/output.c b/net/sctp/output.c index 1224421036b3..1409a875ad8e 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
@@ -86,43 +86,53 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag, | |||
86 | { | 86 | { |
87 | struct sctp_transport *tp = packet->transport; | 87 | struct sctp_transport *tp = packet->transport; |
88 | struct sctp_association *asoc = tp->asoc; | 88 | struct sctp_association *asoc = tp->asoc; |
89 | struct sock *sk; | ||
89 | 90 | ||
90 | pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); | 91 | pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); |
91 | |||
92 | packet->vtag = vtag; | 92 | packet->vtag = vtag; |
93 | 93 | ||
94 | if (asoc && tp->dst) { | 94 | /* do the following jobs only once for a flush schedule */ |
95 | struct sock *sk = asoc->base.sk; | 95 | if (!sctp_packet_empty(packet)) |
96 | 96 | return; | |
97 | rcu_read_lock(); | ||
98 | if (__sk_dst_get(sk) != tp->dst) { | ||
99 | dst_hold(tp->dst); | ||
100 | sk_setup_caps(sk, tp->dst); | ||
101 | } | ||
102 | |||
103 | if (sk_can_gso(sk)) { | ||
104 | struct net_device *dev = tp->dst->dev; | ||
105 | 97 | ||
106 | packet->max_size = dev->gso_max_size; | 98 | /* set packet max_size with pathmtu */ |
107 | } else { | 99 | packet->max_size = tp->pathmtu; |
108 | packet->max_size = asoc->pathmtu; | 100 | if (!asoc) |
109 | } | 101 | return; |
110 | rcu_read_unlock(); | ||
111 | 102 | ||
112 | } else { | 103 | /* update dst or transport pathmtu if in need */ |
113 | packet->max_size = tp->pathmtu; | 104 | sk = asoc->base.sk; |
105 | if (!sctp_transport_dst_check(tp)) { | ||
106 | sctp_transport_route(tp, NULL, sctp_sk(sk)); | ||
107 | if (asoc->param_flags & SPP_PMTUD_ENABLE) | ||
108 | sctp_assoc_sync_pmtu(asoc); | ||
109 | } else if (!sctp_transport_pmtu_check(tp)) { | ||
110 | if (asoc->param_flags & SPP_PMTUD_ENABLE) | ||
111 | sctp_assoc_sync_pmtu(asoc); | ||
114 | } | 112 | } |
115 | 113 | ||
116 | if (ecn_capable && sctp_packet_empty(packet)) { | 114 | /* If there a is a prepend chunk stick it on the list before |
117 | struct sctp_chunk *chunk; | 115 | * any other chunks get appended. |
116 | */ | ||
117 | if (ecn_capable) { | ||
118 | struct sctp_chunk *chunk = sctp_get_ecne_prepend(asoc); | ||
118 | 119 | ||
119 | /* If there a is a prepend chunk stick it on the list before | ||
120 | * any other chunks get appended. | ||
121 | */ | ||
122 | chunk = sctp_get_ecne_prepend(asoc); | ||
123 | if (chunk) | 120 | if (chunk) |
124 | sctp_packet_append_chunk(packet, chunk); | 121 | sctp_packet_append_chunk(packet, chunk); |
125 | } | 122 | } |
123 | |||
124 | if (!tp->dst) | ||
125 | return; | ||
126 | |||
127 | /* set packet max_size with gso_max_size if gso is enabled*/ | ||
128 | rcu_read_lock(); | ||
129 | if (__sk_dst_get(sk) != tp->dst) { | ||
130 | dst_hold(tp->dst); | ||
131 | sk_setup_caps(sk, tp->dst); | ||
132 | } | ||
133 | packet->max_size = sk_can_gso(sk) ? tp->dst->dev->gso_max_size | ||
134 | : asoc->pathmtu; | ||
135 | rcu_read_unlock(); | ||
126 | } | 136 | } |
127 | 137 | ||
128 | /* Initialize the packet structure. */ | 138 | /* Initialize the packet structure. */ |
@@ -582,12 +592,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) | |||
582 | sh->vtag = htonl(packet->vtag); | 592 | sh->vtag = htonl(packet->vtag); |
583 | sh->checksum = 0; | 593 | sh->checksum = 0; |
584 | 594 | ||
585 | /* update dst if in need */ | 595 | /* drop packet if no dst */ |
586 | if (!sctp_transport_dst_check(tp)) { | ||
587 | sctp_transport_route(tp, NULL, sctp_sk(sk)); | ||
588 | if (asoc && asoc->param_flags & SPP_PMTUD_ENABLE) | ||
589 | sctp_assoc_sync_pmtu(sk, asoc); | ||
590 | } | ||
591 | dst = dst_clone(tp->dst); | 596 | dst = dst_clone(tp->dst); |
592 | if (!dst) { | 597 | if (!dst) { |
593 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 598 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
@@ -704,7 +709,7 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | |||
704 | */ | 709 | */ |
705 | 710 | ||
706 | if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && | 711 | if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && |
707 | !chunk->msg->force_delay) | 712 | !asoc->force_delay) |
708 | /* Nothing unacked */ | 713 | /* Nothing unacked */ |
709 | return SCTP_XMIT_OK; | 714 | return SCTP_XMIT_OK; |
710 | 715 | ||
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 025ccff67072..8081476ed313 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -1026,8 +1026,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
1026 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid | 1026 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid |
1027 | * stream identifier. | 1027 | * stream identifier. |
1028 | */ | 1028 | */ |
1029 | if (chunk->sinfo.sinfo_stream >= | 1029 | if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) { |
1030 | asoc->c.sinit_num_ostreams) { | ||
1031 | 1030 | ||
1032 | /* Mark as failed send. */ | 1031 | /* Mark as failed send. */ |
1033 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); | 1032 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); |
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 206377fe91ec..a0b29d43627f 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
@@ -361,8 +361,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | |||
361 | sctp_seq_dump_remote_addrs(seq, assoc); | 361 | sctp_seq_dump_remote_addrs(seq, assoc); |
362 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " | 362 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " |
363 | "%8d %8d %8d %8d", | 363 | "%8d %8d %8d %8d", |
364 | assoc->hbinterval, assoc->c.sinit_max_instreams, | 364 | assoc->hbinterval, assoc->stream->incnt, |
365 | assoc->c.sinit_num_ostreams, assoc->max_retrans, | 365 | assoc->stream->outcnt, assoc->max_retrans, |
366 | assoc->init_retries, assoc->shutdown_retries, | 366 | assoc->init_retries, assoc->shutdown_retries, |
367 | assoc->rtx_data_chunks, | 367 | assoc->rtx_data_chunks, |
368 | atomic_read(&sk->sk_wmem_alloc), | 368 | atomic_read(&sk->sk_wmem_alloc), |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 969a30c7bb54..118faff6a332 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -2460,15 +2460,10 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, | |||
2460 | * association. | 2460 | * association. |
2461 | */ | 2461 | */ |
2462 | if (!asoc->temp) { | 2462 | if (!asoc->temp) { |
2463 | int error; | 2463 | if (sctp_stream_init(asoc, gfp)) |
2464 | |||
2465 | asoc->stream = sctp_stream_new(asoc->c.sinit_max_instreams, | ||
2466 | asoc->c.sinit_num_ostreams, gfp); | ||
2467 | if (!asoc->stream) | ||
2468 | goto clean_up; | 2464 | goto clean_up; |
2469 | 2465 | ||
2470 | error = sctp_assoc_set_id(asoc, gfp); | 2466 | if (sctp_assoc_set_id(asoc, gfp)) |
2471 | if (error) | ||
2472 | goto clean_up; | 2467 | goto clean_up; |
2473 | } | 2468 | } |
2474 | 2469 | ||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index e03bb1aab4d0..24c6ccce7539 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -3946,7 +3946,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(struct net *net, | |||
3946 | 3946 | ||
3947 | /* Silently discard the chunk if stream-id is not valid */ | 3947 | /* Silently discard the chunk if stream-id is not valid */ |
3948 | sctp_walk_fwdtsn(skip, chunk) { | 3948 | sctp_walk_fwdtsn(skip, chunk) { |
3949 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | 3949 | if (ntohs(skip->stream) >= asoc->stream->incnt) |
3950 | goto discard_noforce; | 3950 | goto discard_noforce; |
3951 | } | 3951 | } |
3952 | 3952 | ||
@@ -4017,7 +4017,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( | |||
4017 | 4017 | ||
4018 | /* Silently discard the chunk if stream-id is not valid */ | 4018 | /* Silently discard the chunk if stream-id is not valid */ |
4019 | sctp_walk_fwdtsn(skip, chunk) { | 4019 | sctp_walk_fwdtsn(skip, chunk) { |
4020 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | 4020 | if (ntohs(skip->stream) >= asoc->stream->incnt) |
4021 | goto gen_shutdown; | 4021 | goto gen_shutdown; |
4022 | } | 4022 | } |
4023 | 4023 | ||
@@ -6353,7 +6353,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6353 | * and discard the DATA chunk. | 6353 | * and discard the DATA chunk. |
6354 | */ | 6354 | */ |
6355 | sid = ntohs(data_hdr->stream); | 6355 | sid = ntohs(data_hdr->stream); |
6356 | if (sid >= asoc->c.sinit_max_instreams) { | 6356 | if (sid >= asoc->stream->incnt) { |
6357 | /* Mark tsn as received even though we drop it */ | 6357 | /* Mark tsn as received even though we drop it */ |
6358 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); | 6358 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); |
6359 | 6359 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0f378ea2ae38..c1401f43d40f 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -1907,7 +1907,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
1907 | } | 1907 | } |
1908 | 1908 | ||
1909 | if (asoc->pmtu_pending) | 1909 | if (asoc->pmtu_pending) |
1910 | sctp_assoc_pending_pmtu(sk, asoc); | 1910 | sctp_assoc_pending_pmtu(asoc); |
1911 | 1911 | ||
1912 | /* If fragmentation is disabled and the message length exceeds the | 1912 | /* If fragmentation is disabled and the message length exceeds the |
1913 | * association fragmentation point, return EMSGSIZE. The I-D | 1913 | * association fragmentation point, return EMSGSIZE. The I-D |
@@ -1920,7 +1920,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
1920 | } | 1920 | } |
1921 | 1921 | ||
1922 | /* Check for invalid stream. */ | 1922 | /* Check for invalid stream. */ |
1923 | if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { | 1923 | if (sinfo->sinfo_stream >= asoc->stream->outcnt) { |
1924 | err = -EINVAL; | 1924 | err = -EINVAL; |
1925 | goto out_free; | 1925 | goto out_free; |
1926 | } | 1926 | } |
@@ -1965,7 +1965,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
1965 | err = PTR_ERR(datamsg); | 1965 | err = PTR_ERR(datamsg); |
1966 | goto out_free; | 1966 | goto out_free; |
1967 | } | 1967 | } |
1968 | datamsg->force_delay = !!(msg->msg_flags & MSG_MORE); | 1968 | asoc->force_delay = !!(msg->msg_flags & MSG_MORE); |
1969 | 1969 | ||
1970 | /* Now send the (possibly) fragmented message. */ | 1970 | /* Now send the (possibly) fragmented message. */ |
1971 | list_for_each_entry(chunk, &datamsg->chunks, frag_list) { | 1971 | list_for_each_entry(chunk, &datamsg->chunks, frag_list) { |
@@ -2435,7 +2435,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
2435 | if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { | 2435 | if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { |
2436 | if (trans) { | 2436 | if (trans) { |
2437 | trans->pathmtu = params->spp_pathmtu; | 2437 | trans->pathmtu = params->spp_pathmtu; |
2438 | sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); | 2438 | sctp_assoc_sync_pmtu(asoc); |
2439 | } else if (asoc) { | 2439 | } else if (asoc) { |
2440 | asoc->pathmtu = params->spp_pathmtu; | 2440 | asoc->pathmtu = params->spp_pathmtu; |
2441 | } else { | 2441 | } else { |
@@ -2451,7 +2451,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
2451 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; | 2451 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; |
2452 | if (update) { | 2452 | if (update) { |
2453 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); | 2453 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); |
2454 | sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); | 2454 | sctp_assoc_sync_pmtu(asoc); |
2455 | } | 2455 | } |
2456 | } else if (asoc) { | 2456 | } else if (asoc) { |
2457 | asoc->param_flags = | 2457 | asoc->param_flags = |
@@ -4461,8 +4461,8 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, | |||
4461 | info->sctpi_rwnd = asoc->a_rwnd; | 4461 | info->sctpi_rwnd = asoc->a_rwnd; |
4462 | info->sctpi_unackdata = asoc->unack_data; | 4462 | info->sctpi_unackdata = asoc->unack_data; |
4463 | info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); | 4463 | info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); |
4464 | info->sctpi_instrms = asoc->c.sinit_max_instreams; | 4464 | info->sctpi_instrms = asoc->stream->incnt; |
4465 | info->sctpi_outstrms = asoc->c.sinit_num_ostreams; | 4465 | info->sctpi_outstrms = asoc->stream->outcnt; |
4466 | list_for_each(pos, &asoc->base.inqueue.in_chunk_list) | 4466 | list_for_each(pos, &asoc->base.inqueue.in_chunk_list) |
4467 | info->sctpi_inqueue++; | 4467 | info->sctpi_inqueue++; |
4468 | list_for_each(pos, &asoc->outqueue.out_chunk_list) | 4468 | list_for_each(pos, &asoc->outqueue.out_chunk_list) |
@@ -4691,8 +4691,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, | |||
4691 | status.sstat_unackdata = asoc->unack_data; | 4691 | status.sstat_unackdata = asoc->unack_data; |
4692 | 4692 | ||
4693 | status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); | 4693 | status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); |
4694 | status.sstat_instrms = asoc->c.sinit_max_instreams; | 4694 | status.sstat_instrms = asoc->stream->incnt; |
4695 | status.sstat_outstrms = asoc->c.sinit_num_ostreams; | 4695 | status.sstat_outstrms = asoc->stream->outcnt; |
4696 | status.sstat_fragmentation_point = asoc->frag_point; | 4696 | status.sstat_fragmentation_point = asoc->frag_point; |
4697 | status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); | 4697 | status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); |
4698 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, | 4698 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, |
diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 1c6cc04fa3a4..bbed997e1c5f 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c | |||
@@ -35,33 +35,60 @@ | |||
35 | #include <net/sctp/sctp.h> | 35 | #include <net/sctp/sctp.h> |
36 | #include <net/sctp/sm.h> | 36 | #include <net/sctp/sm.h> |
37 | 37 | ||
38 | struct sctp_stream *sctp_stream_new(__u16 incnt, __u16 outcnt, gfp_t gfp) | 38 | int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp) |
39 | { | 39 | { |
40 | struct sctp_stream *stream; | 40 | struct sctp_stream *stream; |
41 | int i; | 41 | int i; |
42 | 42 | ||
43 | stream = kzalloc(sizeof(*stream), gfp); | 43 | stream = kzalloc(sizeof(*stream), gfp); |
44 | if (!stream) | 44 | if (!stream) |
45 | return NULL; | 45 | return -ENOMEM; |
46 | 46 | ||
47 | stream->outcnt = outcnt; | 47 | stream->outcnt = asoc->c.sinit_num_ostreams; |
48 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); | 48 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); |
49 | if (!stream->out) { | 49 | if (!stream->out) { |
50 | kfree(stream); | 50 | kfree(stream); |
51 | return NULL; | 51 | return -ENOMEM; |
52 | } | 52 | } |
53 | for (i = 0; i < stream->outcnt; i++) | 53 | for (i = 0; i < stream->outcnt; i++) |
54 | stream->out[i].state = SCTP_STREAM_OPEN; | 54 | stream->out[i].state = SCTP_STREAM_OPEN; |
55 | 55 | ||
56 | stream->incnt = incnt; | 56 | asoc->stream = stream; |
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp) | ||
62 | { | ||
63 | struct sctp_stream *stream = asoc->stream; | ||
64 | int i; | ||
65 | |||
66 | /* Initial stream->out size may be very big, so free it and alloc | ||
67 | * a new one with new outcnt to save memory. | ||
68 | */ | ||
69 | kfree(stream->out); | ||
70 | stream->outcnt = asoc->c.sinit_num_ostreams; | ||
71 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); | ||
72 | if (!stream->out) | ||
73 | goto nomem; | ||
74 | |||
75 | for (i = 0; i < stream->outcnt; i++) | ||
76 | stream->out[i].state = SCTP_STREAM_OPEN; | ||
77 | |||
78 | stream->incnt = asoc->c.sinit_max_instreams; | ||
57 | stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp); | 79 | stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp); |
58 | if (!stream->in) { | 80 | if (!stream->in) { |
59 | kfree(stream->out); | 81 | kfree(stream->out); |
60 | kfree(stream); | 82 | goto nomem; |
61 | return NULL; | ||
62 | } | 83 | } |
63 | 84 | ||
64 | return stream; | 85 | return 0; |
86 | |||
87 | nomem: | ||
88 | asoc->stream = NULL; | ||
89 | kfree(stream); | ||
90 | |||
91 | return -ENOMEM; | ||
65 | } | 92 | } |
66 | 93 | ||
67 | void sctp_stream_free(struct sctp_stream *stream) | 94 | void sctp_stream_free(struct sctp_stream *stream) |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 3379668af368..721eeebfcd8a 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -251,14 +251,13 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) | |||
251 | transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; | 251 | transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; |
252 | } | 252 | } |
253 | 253 | ||
254 | void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 pmtu) | 254 | void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) |
255 | { | 255 | { |
256 | struct dst_entry *dst; | 256 | struct dst_entry *dst = sctp_transport_dst_check(t); |
257 | 257 | ||
258 | if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { | 258 | if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { |
259 | pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n", | 259 | pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n", |
260 | __func__, pmtu, | 260 | __func__, pmtu, SCTP_DEFAULT_MINSEGMENT); |
261 | SCTP_DEFAULT_MINSEGMENT); | ||
262 | /* Use default minimum segment size and disable | 261 | /* Use default minimum segment size and disable |
263 | * pmtu discovery on this transport. | 262 | * pmtu discovery on this transport. |
264 | */ | 263 | */ |
@@ -267,17 +266,13 @@ void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 p | |||
267 | t->pathmtu = pmtu; | 266 | t->pathmtu = pmtu; |
268 | } | 267 | } |
269 | 268 | ||
270 | dst = sctp_transport_dst_check(t); | ||
271 | if (!dst) | ||
272 | t->af_specific->get_dst(t, &t->saddr, &t->fl, sk); | ||
273 | |||
274 | if (dst) { | 269 | if (dst) { |
275 | dst->ops->update_pmtu(dst, sk, NULL, pmtu); | 270 | dst->ops->update_pmtu(dst, t->asoc->base.sk, NULL, pmtu); |
276 | |||
277 | dst = sctp_transport_dst_check(t); | 271 | dst = sctp_transport_dst_check(t); |
278 | if (!dst) | ||
279 | t->af_specific->get_dst(t, &t->saddr, &t->fl, sk); | ||
280 | } | 272 | } |
273 | |||
274 | if (!dst) | ||
275 | t->af_specific->get_dst(t, &t->saddr, &t->fl, t->asoc->base.sk); | ||
281 | } | 276 | } |
282 | 277 | ||
283 | /* Caches the dst entry and source address for a transport's destination | 278 | /* Caches the dst entry and source address for a transport's destination |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 16b6b5988be9..570a2b67ca10 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -132,12 +132,10 @@ static int wiphy_resume(struct device *dev) | |||
132 | /* Age scan results with time spent in suspend */ | 132 | /* Age scan results with time spent in suspend */ |
133 | cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); | 133 | cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); |
134 | 134 | ||
135 | if (rdev->ops->resume) { | 135 | rtnl_lock(); |
136 | rtnl_lock(); | 136 | if (rdev->wiphy.registered && rdev->ops->resume) |
137 | if (rdev->wiphy.registered) | 137 | ret = rdev_resume(rdev); |
138 | ret = rdev_resume(rdev); | 138 | rtnl_unlock(); |
139 | rtnl_unlock(); | ||
140 | } | ||
141 | 139 | ||
142 | return ret; | 140 | return ret; |
143 | } | 141 | } |
diff --git a/tools/include/linux/filter.h b/tools/include/linux/filter.h index 122153b16ea4..390d7c9685fd 100644 --- a/tools/include/linux/filter.h +++ b/tools/include/linux/filter.h | |||
@@ -168,6 +168,16 @@ | |||
168 | .off = OFF, \ | 168 | .off = OFF, \ |
169 | .imm = 0 }) | 169 | .imm = 0 }) |
170 | 170 | ||
171 | /* Atomic memory add, *(uint *)(dst_reg + off16) += src_reg */ | ||
172 | |||
173 | #define BPF_STX_XADD(SIZE, DST, SRC, OFF) \ | ||
174 | ((struct bpf_insn) { \ | ||
175 | .code = BPF_STX | BPF_SIZE(SIZE) | BPF_XADD, \ | ||
176 | .dst_reg = DST, \ | ||
177 | .src_reg = SRC, \ | ||
178 | .off = OFF, \ | ||
179 | .imm = 0 }) | ||
180 | |||
171 | /* Memory store, *(uint *) (dst_reg + off16) = imm32 */ | 181 | /* Memory store, *(uint *) (dst_reg + off16) = imm32 */ |
172 | 182 | ||
173 | #define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ | 183 | #define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ |
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 6a1ad58cb66f..9af09e8099c0 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile | |||
@@ -1,7 +1,14 @@ | |||
1 | LIBDIR := ../../../lib | 1 | LIBDIR := ../../../lib |
2 | BPFDIR := $(LIBDIR)/bpf | 2 | BPFDIR := $(LIBDIR)/bpf |
3 | APIDIR := ../../../include/uapi | ||
4 | GENDIR := ../../../../include/generated | ||
5 | GENHDR := $(GENDIR)/autoconf.h | ||
3 | 6 | ||
4 | CFLAGS += -Wall -O2 -I../../../include/uapi -I$(LIBDIR) | 7 | ifneq ($(wildcard $(GENHDR)),) |
8 | GENFLAGS := -DHAVE_GENHDR | ||
9 | endif | ||
10 | |||
11 | CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) | ||
5 | LDLIBS += -lcap | 12 | LDLIBS += -lcap |
6 | 13 | ||
7 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map | 14 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index d1555e4240c0..c848e90b6421 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -30,6 +30,14 @@ | |||
30 | 30 | ||
31 | #include <bpf/bpf.h> | 31 | #include <bpf/bpf.h> |
32 | 32 | ||
33 | #ifdef HAVE_GENHDR | ||
34 | # include "autoconf.h" | ||
35 | #else | ||
36 | # if defined(__i386) || defined(__x86_64) || defined(__s390x__) || defined(__aarch64__) | ||
37 | # define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 | ||
38 | # endif | ||
39 | #endif | ||
40 | |||
33 | #include "../../../include/linux/filter.h" | 41 | #include "../../../include/linux/filter.h" |
34 | 42 | ||
35 | #ifndef ARRAY_SIZE | 43 | #ifndef ARRAY_SIZE |
@@ -39,6 +47,8 @@ | |||
39 | #define MAX_INSNS 512 | 47 | #define MAX_INSNS 512 |
40 | #define MAX_FIXUPS 8 | 48 | #define MAX_FIXUPS 8 |
41 | 49 | ||
50 | #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) | ||
51 | |||
42 | struct bpf_test { | 52 | struct bpf_test { |
43 | const char *descr; | 53 | const char *descr; |
44 | struct bpf_insn insns[MAX_INSNS]; | 54 | struct bpf_insn insns[MAX_INSNS]; |
@@ -53,6 +63,7 @@ struct bpf_test { | |||
53 | REJECT | 63 | REJECT |
54 | } result, result_unpriv; | 64 | } result, result_unpriv; |
55 | enum bpf_prog_type prog_type; | 65 | enum bpf_prog_type prog_type; |
66 | uint8_t flags; | ||
56 | }; | 67 | }; |
57 | 68 | ||
58 | /* Note we want this to be 64 bit aligned so that the end of our array is | 69 | /* Note we want this to be 64 bit aligned so that the end of our array is |
@@ -2432,6 +2443,30 @@ static struct bpf_test tests[] = { | |||
2432 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2443 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2433 | }, | 2444 | }, |
2434 | { | 2445 | { |
2446 | "direct packet access: test15 (spill with xadd)", | ||
2447 | .insns = { | ||
2448 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
2449 | offsetof(struct __sk_buff, data)), | ||
2450 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2451 | offsetof(struct __sk_buff, data_end)), | ||
2452 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
2453 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
2454 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 8), | ||
2455 | BPF_MOV64_IMM(BPF_REG_5, 4096), | ||
2456 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), | ||
2457 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), | ||
2458 | BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0), | ||
2459 | BPF_STX_XADD(BPF_DW, BPF_REG_4, BPF_REG_5, 0), | ||
2460 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_4, 0), | ||
2461 | BPF_STX_MEM(BPF_W, BPF_REG_2, BPF_REG_5, 0), | ||
2462 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2463 | BPF_EXIT_INSN(), | ||
2464 | }, | ||
2465 | .errstr = "R2 invalid mem access 'inv'", | ||
2466 | .result = REJECT, | ||
2467 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2468 | }, | ||
2469 | { | ||
2435 | "helper access to packet: test1, valid packet_ptr range", | 2470 | "helper access to packet: test1, valid packet_ptr range", |
2436 | .insns = { | 2471 | .insns = { |
2437 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | 2472 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, |
@@ -2934,6 +2969,7 @@ static struct bpf_test tests[] = { | |||
2934 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 2969 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
2935 | .result_unpriv = REJECT, | 2970 | .result_unpriv = REJECT, |
2936 | .result = ACCEPT, | 2971 | .result = ACCEPT, |
2972 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
2937 | }, | 2973 | }, |
2938 | { | 2974 | { |
2939 | "valid map access into an array with a variable", | 2975 | "valid map access into an array with a variable", |
@@ -2957,6 +2993,7 @@ static struct bpf_test tests[] = { | |||
2957 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 2993 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
2958 | .result_unpriv = REJECT, | 2994 | .result_unpriv = REJECT, |
2959 | .result = ACCEPT, | 2995 | .result = ACCEPT, |
2996 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
2960 | }, | 2997 | }, |
2961 | { | 2998 | { |
2962 | "valid map access into an array with a signed variable", | 2999 | "valid map access into an array with a signed variable", |
@@ -2984,6 +3021,7 @@ static struct bpf_test tests[] = { | |||
2984 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3021 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
2985 | .result_unpriv = REJECT, | 3022 | .result_unpriv = REJECT, |
2986 | .result = ACCEPT, | 3023 | .result = ACCEPT, |
3024 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
2987 | }, | 3025 | }, |
2988 | { | 3026 | { |
2989 | "invalid map access into an array with a constant", | 3027 | "invalid map access into an array with a constant", |
@@ -3025,6 +3063,7 @@ static struct bpf_test tests[] = { | |||
3025 | .errstr = "R0 min value is outside of the array range", | 3063 | .errstr = "R0 min value is outside of the array range", |
3026 | .result_unpriv = REJECT, | 3064 | .result_unpriv = REJECT, |
3027 | .result = REJECT, | 3065 | .result = REJECT, |
3066 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3028 | }, | 3067 | }, |
3029 | { | 3068 | { |
3030 | "invalid map access into an array with a variable", | 3069 | "invalid map access into an array with a variable", |
@@ -3048,6 +3087,7 @@ static struct bpf_test tests[] = { | |||
3048 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 3087 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
3049 | .result_unpriv = REJECT, | 3088 | .result_unpriv = REJECT, |
3050 | .result = REJECT, | 3089 | .result = REJECT, |
3090 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3051 | }, | 3091 | }, |
3052 | { | 3092 | { |
3053 | "invalid map access into an array with no floor check", | 3093 | "invalid map access into an array with no floor check", |
@@ -3074,6 +3114,7 @@ static struct bpf_test tests[] = { | |||
3074 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 3114 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
3075 | .result_unpriv = REJECT, | 3115 | .result_unpriv = REJECT, |
3076 | .result = REJECT, | 3116 | .result = REJECT, |
3117 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3077 | }, | 3118 | }, |
3078 | { | 3119 | { |
3079 | "invalid map access into an array with a invalid max check", | 3120 | "invalid map access into an array with a invalid max check", |
@@ -3100,6 +3141,7 @@ static struct bpf_test tests[] = { | |||
3100 | .errstr = "invalid access to map value, value_size=48 off=44 size=8", | 3141 | .errstr = "invalid access to map value, value_size=48 off=44 size=8", |
3101 | .result_unpriv = REJECT, | 3142 | .result_unpriv = REJECT, |
3102 | .result = REJECT, | 3143 | .result = REJECT, |
3144 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3103 | }, | 3145 | }, |
3104 | { | 3146 | { |
3105 | "invalid map access into an array with a invalid max check", | 3147 | "invalid map access into an array with a invalid max check", |
@@ -3129,6 +3171,7 @@ static struct bpf_test tests[] = { | |||
3129 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 3171 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
3130 | .result_unpriv = REJECT, | 3172 | .result_unpriv = REJECT, |
3131 | .result = REJECT, | 3173 | .result = REJECT, |
3174 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3132 | }, | 3175 | }, |
3133 | { | 3176 | { |
3134 | "multiple registers share map_lookup_elem result", | 3177 | "multiple registers share map_lookup_elem result", |
@@ -3252,6 +3295,7 @@ static struct bpf_test tests[] = { | |||
3252 | .result = REJECT, | 3295 | .result = REJECT, |
3253 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 3296 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
3254 | .result_unpriv = REJECT, | 3297 | .result_unpriv = REJECT, |
3298 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3255 | }, | 3299 | }, |
3256 | { | 3300 | { |
3257 | "constant register |= constant should keep constant type", | 3301 | "constant register |= constant should keep constant type", |
@@ -3418,6 +3462,26 @@ static struct bpf_test tests[] = { | |||
3418 | .prog_type = BPF_PROG_TYPE_LWT_XMIT, | 3462 | .prog_type = BPF_PROG_TYPE_LWT_XMIT, |
3419 | }, | 3463 | }, |
3420 | { | 3464 | { |
3465 | "overlapping checks for direct packet access", | ||
3466 | .insns = { | ||
3467 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
3468 | offsetof(struct __sk_buff, data)), | ||
3469 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
3470 | offsetof(struct __sk_buff, data_end)), | ||
3471 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
3472 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
3473 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 4), | ||
3474 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
3475 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6), | ||
3476 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1), | ||
3477 | BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_2, 6), | ||
3478 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
3479 | BPF_EXIT_INSN(), | ||
3480 | }, | ||
3481 | .result = ACCEPT, | ||
3482 | .prog_type = BPF_PROG_TYPE_LWT_XMIT, | ||
3483 | }, | ||
3484 | { | ||
3421 | "invalid access of tc_classid for LWT_IN", | 3485 | "invalid access of tc_classid for LWT_IN", |
3422 | .insns = { | 3486 | .insns = { |
3423 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | 3487 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
@@ -3961,7 +4025,208 @@ static struct bpf_test tests[] = { | |||
3961 | .result_unpriv = REJECT, | 4025 | .result_unpriv = REJECT, |
3962 | }, | 4026 | }, |
3963 | { | 4027 | { |
3964 | "map element value (adjusted) is preserved across register spilling", | 4028 | "map element value or null is marked on register spilling", |
4029 | .insns = { | ||
4030 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4031 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4032 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4033 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4034 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4035 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
4036 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -152), | ||
4037 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0), | ||
4038 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4039 | BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, 0), | ||
4040 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), | ||
4041 | BPF_EXIT_INSN(), | ||
4042 | }, | ||
4043 | .fixup_map2 = { 3 }, | ||
4044 | .errstr_unpriv = "R0 leaks addr", | ||
4045 | .result = ACCEPT, | ||
4046 | .result_unpriv = REJECT, | ||
4047 | }, | ||
4048 | { | ||
4049 | "map element value store of cleared call register", | ||
4050 | .insns = { | ||
4051 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4052 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4053 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4054 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4055 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4056 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
4057 | BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), | ||
4058 | BPF_EXIT_INSN(), | ||
4059 | }, | ||
4060 | .fixup_map2 = { 3 }, | ||
4061 | .errstr_unpriv = "R1 !read_ok", | ||
4062 | .errstr = "R1 !read_ok", | ||
4063 | .result = REJECT, | ||
4064 | .result_unpriv = REJECT, | ||
4065 | }, | ||
4066 | { | ||
4067 | "map element value with unaligned store", | ||
4068 | .insns = { | ||
4069 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4070 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4071 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4072 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4073 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4074 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 17), | ||
4075 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 3), | ||
4076 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 42), | ||
4077 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 2, 43), | ||
4078 | BPF_ST_MEM(BPF_DW, BPF_REG_0, -2, 44), | ||
4079 | BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), | ||
4080 | BPF_ST_MEM(BPF_DW, BPF_REG_8, 0, 32), | ||
4081 | BPF_ST_MEM(BPF_DW, BPF_REG_8, 2, 33), | ||
4082 | BPF_ST_MEM(BPF_DW, BPF_REG_8, -2, 34), | ||
4083 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 5), | ||
4084 | BPF_ST_MEM(BPF_DW, BPF_REG_8, 0, 22), | ||
4085 | BPF_ST_MEM(BPF_DW, BPF_REG_8, 4, 23), | ||
4086 | BPF_ST_MEM(BPF_DW, BPF_REG_8, -7, 24), | ||
4087 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_8), | ||
4088 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 3), | ||
4089 | BPF_ST_MEM(BPF_DW, BPF_REG_7, 0, 22), | ||
4090 | BPF_ST_MEM(BPF_DW, BPF_REG_7, 4, 23), | ||
4091 | BPF_ST_MEM(BPF_DW, BPF_REG_7, -4, 24), | ||
4092 | BPF_EXIT_INSN(), | ||
4093 | }, | ||
4094 | .fixup_map2 = { 3 }, | ||
4095 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4096 | .result = ACCEPT, | ||
4097 | .result_unpriv = REJECT, | ||
4098 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
4099 | }, | ||
4100 | { | ||
4101 | "map element value with unaligned load", | ||
4102 | .insns = { | ||
4103 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4104 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4105 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4106 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4107 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4108 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11), | ||
4109 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), | ||
4110 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, MAX_ENTRIES, 9), | ||
4111 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 3), | ||
4112 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), | ||
4113 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 2), | ||
4114 | BPF_MOV64_REG(BPF_REG_8, BPF_REG_0), | ||
4115 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_8, 0), | ||
4116 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_8, 2), | ||
4117 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 5), | ||
4118 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), | ||
4119 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 4), | ||
4120 | BPF_EXIT_INSN(), | ||
4121 | }, | ||
4122 | .fixup_map2 = { 3 }, | ||
4123 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4124 | .result = ACCEPT, | ||
4125 | .result_unpriv = REJECT, | ||
4126 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
4127 | }, | ||
4128 | { | ||
4129 | "map element value illegal alu op, 1", | ||
4130 | .insns = { | ||
4131 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4132 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4133 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4134 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4135 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4136 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4137 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 8), | ||
4138 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4139 | BPF_EXIT_INSN(), | ||
4140 | }, | ||
4141 | .fixup_map2 = { 3 }, | ||
4142 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4143 | .errstr = "invalid mem access 'inv'", | ||
4144 | .result = REJECT, | ||
4145 | .result_unpriv = REJECT, | ||
4146 | }, | ||
4147 | { | ||
4148 | "map element value illegal alu op, 2", | ||
4149 | .insns = { | ||
4150 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4151 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4152 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4153 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4154 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4155 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4156 | BPF_ALU32_IMM(BPF_ADD, BPF_REG_0, 0), | ||
4157 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4158 | BPF_EXIT_INSN(), | ||
4159 | }, | ||
4160 | .fixup_map2 = { 3 }, | ||
4161 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4162 | .errstr = "invalid mem access 'inv'", | ||
4163 | .result = REJECT, | ||
4164 | .result_unpriv = REJECT, | ||
4165 | }, | ||
4166 | { | ||
4167 | "map element value illegal alu op, 3", | ||
4168 | .insns = { | ||
4169 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4170 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4171 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4172 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4173 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4174 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4175 | BPF_ALU64_IMM(BPF_DIV, BPF_REG_0, 42), | ||
4176 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4177 | BPF_EXIT_INSN(), | ||
4178 | }, | ||
4179 | .fixup_map2 = { 3 }, | ||
4180 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4181 | .errstr = "invalid mem access 'inv'", | ||
4182 | .result = REJECT, | ||
4183 | .result_unpriv = REJECT, | ||
4184 | }, | ||
4185 | { | ||
4186 | "map element value illegal alu op, 4", | ||
4187 | .insns = { | ||
4188 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4189 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4190 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4191 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4192 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4193 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
4194 | BPF_ENDIAN(BPF_FROM_BE, BPF_REG_0, 64), | ||
4195 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4196 | BPF_EXIT_INSN(), | ||
4197 | }, | ||
4198 | .fixup_map2 = { 3 }, | ||
4199 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | ||
4200 | .errstr = "invalid mem access 'inv'", | ||
4201 | .result = REJECT, | ||
4202 | .result_unpriv = REJECT, | ||
4203 | }, | ||
4204 | { | ||
4205 | "map element value illegal alu op, 5", | ||
4206 | .insns = { | ||
4207 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4208 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4209 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | ||
4210 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4211 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
4212 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), | ||
4213 | BPF_MOV64_IMM(BPF_REG_3, 4096), | ||
4214 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4215 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4216 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), | ||
4217 | BPF_STX_XADD(BPF_DW, BPF_REG_2, BPF_REG_3, 0), | ||
4218 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0), | ||
4219 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | ||
4220 | BPF_EXIT_INSN(), | ||
4221 | }, | ||
4222 | .fixup_map2 = { 3 }, | ||
4223 | .errstr_unpriv = "R0 invalid mem access 'inv'", | ||
4224 | .errstr = "R0 invalid mem access 'inv'", | ||
4225 | .result = REJECT, | ||
4226 | .result_unpriv = REJECT, | ||
4227 | }, | ||
4228 | { | ||
4229 | "map element value is preserved across register spilling", | ||
3965 | .insns = { | 4230 | .insns = { |
3966 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | 4231 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), |
3967 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | 4232 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), |
@@ -3983,6 +4248,7 @@ static struct bpf_test tests[] = { | |||
3983 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 4248 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
3984 | .result = ACCEPT, | 4249 | .result = ACCEPT, |
3985 | .result_unpriv = REJECT, | 4250 | .result_unpriv = REJECT, |
4251 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
3986 | }, | 4252 | }, |
3987 | { | 4253 | { |
3988 | "helper access to variable memory: stack, bitwise AND + JMP, correct bounds", | 4254 | "helper access to variable memory: stack, bitwise AND + JMP, correct bounds", |
@@ -4421,6 +4687,7 @@ static struct bpf_test tests[] = { | |||
4421 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 4687 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
4422 | .result = REJECT, | 4688 | .result = REJECT, |
4423 | .result_unpriv = REJECT, | 4689 | .result_unpriv = REJECT, |
4690 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
4424 | }, | 4691 | }, |
4425 | { | 4692 | { |
4426 | "invalid range check", | 4693 | "invalid range check", |
@@ -4452,6 +4719,7 @@ static struct bpf_test tests[] = { | |||
4452 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 4719 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
4453 | .result = REJECT, | 4720 | .result = REJECT, |
4454 | .result_unpriv = REJECT, | 4721 | .result_unpriv = REJECT, |
4722 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
4455 | } | 4723 | } |
4456 | }; | 4724 | }; |
4457 | 4725 | ||
@@ -4530,11 +4798,11 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, | |||
4530 | static void do_test_single(struct bpf_test *test, bool unpriv, | 4798 | static void do_test_single(struct bpf_test *test, bool unpriv, |
4531 | int *passes, int *errors) | 4799 | int *passes, int *errors) |
4532 | { | 4800 | { |
4801 | int fd_prog, expected_ret, reject_from_alignment; | ||
4533 | struct bpf_insn *prog = test->insns; | 4802 | struct bpf_insn *prog = test->insns; |
4534 | int prog_len = probe_filter_length(prog); | 4803 | int prog_len = probe_filter_length(prog); |
4535 | int prog_type = test->prog_type; | 4804 | int prog_type = test->prog_type; |
4536 | int fd_f1 = -1, fd_f2 = -1, fd_f3 = -1; | 4805 | int fd_f1 = -1, fd_f2 = -1, fd_f3 = -1; |
4537 | int fd_prog, expected_ret; | ||
4538 | const char *expected_err; | 4806 | const char *expected_err; |
4539 | 4807 | ||
4540 | do_test_fixup(test, prog, &fd_f1, &fd_f2, &fd_f3); | 4808 | do_test_fixup(test, prog, &fd_f1, &fd_f2, &fd_f3); |
@@ -4547,8 +4815,19 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
4547 | test->result_unpriv : test->result; | 4815 | test->result_unpriv : test->result; |
4548 | expected_err = unpriv && test->errstr_unpriv ? | 4816 | expected_err = unpriv && test->errstr_unpriv ? |
4549 | test->errstr_unpriv : test->errstr; | 4817 | test->errstr_unpriv : test->errstr; |
4818 | |||
4819 | reject_from_alignment = fd_prog < 0 && | ||
4820 | (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) && | ||
4821 | strstr(bpf_vlog, "Unknown alignment."); | ||
4822 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | ||
4823 | if (reject_from_alignment) { | ||
4824 | printf("FAIL\nFailed due to alignment despite having efficient unaligned access: '%s'!\n", | ||
4825 | strerror(errno)); | ||
4826 | goto fail_log; | ||
4827 | } | ||
4828 | #endif | ||
4550 | if (expected_ret == ACCEPT) { | 4829 | if (expected_ret == ACCEPT) { |
4551 | if (fd_prog < 0) { | 4830 | if (fd_prog < 0 && !reject_from_alignment) { |
4552 | printf("FAIL\nFailed to load prog '%s'!\n", | 4831 | printf("FAIL\nFailed to load prog '%s'!\n", |
4553 | strerror(errno)); | 4832 | strerror(errno)); |
4554 | goto fail_log; | 4833 | goto fail_log; |
@@ -4558,14 +4837,15 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
4558 | printf("FAIL\nUnexpected success to load!\n"); | 4837 | printf("FAIL\nUnexpected success to load!\n"); |
4559 | goto fail_log; | 4838 | goto fail_log; |
4560 | } | 4839 | } |
4561 | if (!strstr(bpf_vlog, expected_err)) { | 4840 | if (!strstr(bpf_vlog, expected_err) && !reject_from_alignment) { |
4562 | printf("FAIL\nUnexpected error message!\n"); | 4841 | printf("FAIL\nUnexpected error message!\n"); |
4563 | goto fail_log; | 4842 | goto fail_log; |
4564 | } | 4843 | } |
4565 | } | 4844 | } |
4566 | 4845 | ||
4567 | (*passes)++; | 4846 | (*passes)++; |
4568 | printf("OK\n"); | 4847 | printf("OK%s\n", reject_from_alignment ? |
4848 | " (NOTE: reject due to unknown alignment)" : ""); | ||
4569 | close_fds: | 4849 | close_fds: |
4570 | close(fd_prog); | 4850 | close(fd_prog); |
4571 | close(fd_f1); | 4851 | close(fd_f1); |