Pull networking fixes from Paolo Abeni: "Including fixes from Bluetooth, IPsec and CAN. No known regressions at this point. Current release - regressions: - xfrm: xfrm_alloc_spi shouldn't use 0 as SPI Previous releases - regressions: - xfrm: fix offloading of cross-family tunnels - bluetooth: fix several races leading to UaFs - dsa: lantiq_gswip: fix FDB entries creation for the CPU port - eth: - tun: update napi->skb after XDP process - mlx: fix UAF in flow counter release Previous releases - always broken: - core: forbid FDB status change while nexthop is in a group - smc: fix warning in smc_rx_splice() when calling get_page() - can: provide missing ndo_change_mtu(), to prevent buffer overflow. - eth: - i40e: fix VF config validation - broadcom: fix support for PTP_EXTTS_REQUEST2 ioctl" * tag 'net-6.17-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (40 commits) octeontx2-pf: Fix potential use after free in otx2_tc_add_flow() net: dsa: lantiq_gswip: suppress -EINVAL errors for bridge FDB entries added to the CPU port net: dsa: lantiq_gswip: move gswip_add_single_port_br() call to port_setup() libie: fix string names for AQ error codes net/mlx5e: Fix missing FEC RS stats for RS_544_514_INTERLEAVED_QUAD net/mlx5: HWS, ignore flow level for multi-dest table net/mlx5: fs, fix UAF in flow counter release selftests: fib_nexthops: Add test cases for FDB status change selftests: fib_nexthops: Fix creation of non-FDB nexthops nexthop: Forbid FDB status change while nexthop is in a group net: allow alloc_skb_with_frags() to use MAX_SKB_FRAGS bnxt_en: correct offset handling for IPv6 destination address ptp: document behavior of PTP_STRICT_FLAGS broadcom: fix support for PTP_EXTTS_REQUEST2 ioctl broadcom: fix support for PTP_PEROUT_DUTY_CYCLE Bluetooth: MGMT: Fix possible UAFs Bluetooth: hci_event: Fix UAF in hci_acl_create_conn_sync Bluetooth: hci_event: Fix UAF in hci_conn_tx_dequeue Bluetooth: hci_sync: Fix hci_resume_advertising_sync Bluetooth: Fix build after header cleanup ...
Unified · Split
| @@ -312,7 +312,9 @@ config BT_HCIBCM4377 · 311 unmodified lines | ||
| 312 | 312 | |
| 313 | 313 | config BT_HCIBPA10X |
| 314 | 314 | tristate "HCI BPA10x USB driver" |
| 315 | + depends on BT_HCIUART | |
| 315 | 316 | depends on USB |
| 317 | + select BT_HCIUART_H4 | |
| 316 | 318 | help |
| 317 | 319 | Bluetooth HCI BPA10x USB driver. |
| 318 | 320 | This driver provides support for the Digianswer BPA 100/105 Bluetooth |
| @@ -437,8 +439,10 @@ config BT_MTKSDIO · 118 unmodified lines | ||
| 437 | 439 | |
| 438 | 440 | config BT_MTKUART |
| 439 | 441 | tristate "MediaTek HCI UART driver" |
| 442 | + depends on BT_HCIUART | |
| 440 | 443 | depends on SERIAL_DEV_BUS |
| 441 | 444 | depends on USB || !BT_HCIBTUSB_MTK |
| 445 | + select BT_HCIUART_H4 | |
| 442 | 446 | select BT_MTK |
| 443 | 447 | help |
| 444 | 448 | MediaTek Bluetooth HCI UART driver. |
| @@ -483,7 +487,9 @@ config BT_VIRTIO · 38 unmodified lines | ||
| 483 | 487 | |
| 484 | 488 | config BT_NXPUART |
| 485 | 489 | tristate "NXP protocol support" |
| 490 | + depends on BT_HCIUART | |
| 486 | 491 | depends on SERIAL_DEV_BUS |
| 492 | + select BT_HCIUART_H4 | |
| 487 | 493 | select CRC32 |
| 488 | 494 | select CRC8 |
| 489 | 495 | help |
| @@ -121,10 +121,6 @@ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable); · 120 unmodified lines | ||
| 121 | 121 | void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, |
| 122 | 122 | unsigned int oper_speed); |
| 123 | 123 | |
| 124 | −#ifdef CONFIG_BT_HCIUART_H4 | |
| 125 | −int h4_init(void); | |
| 126 | −int h4_deinit(void); | |
| 127 | − | |
| 128 | 124 | struct h4_recv_pkt { |
| 129 | 125 | u8 type; /* Packet type */ |
| 130 | 126 | u8 hlen; /* Header length */ |
| @@ -162,6 +158,10 @@ struct h4_recv_pkt { · 31 unmodified lines | ||
| 162 | 158 | .lsize = 2, \ |
| 163 | 159 | .maxlen = HCI_MAX_FRAME_SIZE \ |
| 164 | 160 | |
| 161 | +#ifdef CONFIG_BT_HCIUART_H4 | |
| 162 | +int h4_init(void); | |
| 163 | +int h4_deinit(void); | |
| 164 | + | |
| 165 | 165 | struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, |
| 166 | 166 | const unsigned char *buffer, int count, |
| 167 | 167 | const struct h4_recv_pkt *pkts, int pkts_count); |
| @@ -823,9 +823,6 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) · 822 unmodified lines | ||
| 823 | 823 | /* Reset Global error flags */ |
| 824 | 824 | rcar_canfd_write(gpriv->base, RCANFD_GERFL, 0x0); |
| 825 | 825 | |
| 826 | − /* Set the controller into appropriate mode */ | |
| 827 | − rcar_canfd_set_mode(gpriv); | |
| 828 | − | |
| 829 | 826 | /* Transition all Channels to reset mode */ |
| 830 | 827 | for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) { |
| 831 | 828 | rcar_canfd_clear_bit(gpriv->base, |
| @@ -844,6 +841,10 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) · 12 unmodified lines | ||
| 844 | 841 | return err; |
| 845 | 842 | } |
| 846 | 843 | } |
| 844 | + | |
| 845 | + /* Set the controller into appropriate mode */ | |
| 846 | + rcar_canfd_set_mode(gpriv); | |
| 847 | + | |
| 847 | 848 | return 0; |
| 848 | 849 | } |
| 849 | 850 | |
| @@ -545,8 +545,6 @@ static int hi3110_stop(struct net_device *net) · 544 unmodified lines | ||
| 545 | 545 | |
| 546 | 546 | priv->force_quit = 1; |
| 547 | 547 | free_irq(spi->irq, priv); |
| 548 | − destroy_workqueue(priv->wq); | |
| 549 | − priv->wq = NULL; | |
| 550 | 548 | |
| 551 | 549 | mutex_lock(&priv->hi3110_lock); |
| 552 | 550 | |
| @@ -770,34 +768,23 @@ static int hi3110_open(struct net_device *net) · 217 unmodified lines | ||
| 770 | 768 | goto out_close; |
| 771 | 769 | } |
| 772 | 770 | |
| 773 | − priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, | |
| 774 | − 0); | |
| 775 | − if (!priv->wq) { | |
| 776 | − ret = -ENOMEM; | |
| 777 | − goto out_free_irq; | |
| 778 | − } | |
| 779 | − INIT_WORK(&priv->tx_work, hi3110_tx_work_handler); | |
| 780 | − INIT_WORK(&priv->restart_work, hi3110_restart_work_handler); | |
| 781 | − | |
| 782 | 771 | ret = hi3110_hw_reset(spi); |
| 783 | 772 | if (ret) |
| 784 | − goto out_free_wq; | |
| 773 | + goto out_free_irq; | |
| 785 | 774 | |
| 786 | 775 | ret = hi3110_setup(net); |
| 787 | 776 | if (ret) |
| 788 | − goto out_free_wq; | |
| 777 | + goto out_free_irq; | |
| 789 | 778 | |
| 790 | 779 | ret = hi3110_set_normal_mode(spi); |
| 791 | 780 | if (ret) |
| 792 | − goto out_free_wq; | |
| 781 | + goto out_free_irq; | |
| 793 | 782 | |
| 794 | 783 | netif_wake_queue(net); |
| 795 | 784 | mutex_unlock(&priv->hi3110_lock); |
| 796 | 785 | |
| 797 | 786 | return 0; |
| 798 | 787 | |
| 799 | − out_free_wq: | |
| 800 | − destroy_workqueue(priv->wq); | |
| 801 | 788 | out_free_irq: |
| 802 | 789 | free_irq(spi->irq, priv); |
| 803 | 790 | hi3110_hw_sleep(spi); |
| @@ -812,6 +799,7 @@ static const struct net_device_ops hi3110_netdev_ops = { · 8 unmodified lines | ||
| 812 | 799 | .ndo_open = hi3110_open, |
| 813 | 800 | .ndo_stop = hi3110_stop, |
| 814 | 801 | .ndo_start_xmit = hi3110_hard_start_xmit, |
| 802 | + .ndo_change_mtu = can_change_mtu, | |
| 815 | 803 | }; |
| 816 | 804 | |
| 817 | 805 | static const struct ethtool_ops hi3110_ethtool_ops = { |
| @@ -908,6 +896,15 @@ static int hi3110_can_probe(struct spi_device *spi) · 90 unmodified lines | ||
| 908 | 896 | if (ret) |
| 909 | 897 | goto out_clk; |
| 910 | 898 | |
| 899 | + priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, | |
| 900 | + 0); | |
| 901 | + if (!priv->wq) { | |
| 902 | + ret = -ENOMEM; | |
| 903 | + goto out_clk; | |
| 904 | + } | |
| 905 | + INIT_WORK(&priv->tx_work, hi3110_tx_work_handler); | |
| 906 | + INIT_WORK(&priv->restart_work, hi3110_restart_work_handler); | |
| 907 | + | |
| 911 | 908 | priv->spi = spi; |
| 912 | 909 | mutex_init(&priv->hi3110_lock); |
| 913 | 910 | |
| @@ -943,6 +940,8 @@ static int hi3110_can_probe(struct spi_device *spi) · 29 unmodified lines | ||
| 943 | 940 | return 0; |
| 944 | 941 | |
| 945 | 942 | error_probe: |
| 943 | + destroy_workqueue(priv->wq); | |
| 944 | + priv->wq = NULL; | |
| 946 | 945 | hi3110_power_enable(priv->power, 0); |
| 947 | 946 | |
| 948 | 947 | out_clk: |
| @@ -963,6 +962,9 @@ static void hi3110_can_remove(struct spi_device *spi) · 14 unmodified lines | ||
| 963 | 962 | |
| 964 | 963 | hi3110_power_enable(priv->power, 0); |
| 965 | 964 | |
| 965 | + destroy_workqueue(priv->wq); | |
| 966 | + priv->wq = NULL; | |
| 967 | + | |
| 966 | 968 | clk_disable_unprepare(priv->clk); |
| 967 | 969 | |
| 968 | 970 | free_candev(net); |
| @@ -768,6 +768,7 @@ static const struct net_device_ops sun4ican_netdev_ops = { · 767 unmodified lines | ||
| 768 | 768 | .ndo_open = sun4ican_open, |
| 769 | 769 | .ndo_stop = sun4ican_close, |
| 770 | 770 | .ndo_start_xmit = sun4ican_start_xmit, |
| 771 | + .ndo_change_mtu = can_change_mtu, | |
| 771 | 772 | }; |
| 772 | 773 | |
| 773 | 774 | static const struct ethtool_ops sun4ican_ethtool_ops = { |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | * |
| 8 | 8 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
| 9 | 9 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. |
| 10 | − * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr> | |
| 10 | + * Copyright (c) 2020-2025 Vincent Mailhol <mailhol@kernel.org> | |
| 11 | 11 | */ |
| 12 | 12 | |
| 13 | 13 | #include <linux/unaligned.h> |
| @@ -1977,6 +1977,7 @@ static const struct net_device_ops es58x_netdev_ops = { · 1963 unmodified lines | ||
| 1977 | 1977 | .ndo_stop = es58x_stop, |
| 1978 | 1978 | .ndo_start_xmit = es58x_start_xmit, |
| 1979 | 1979 | .ndo_eth_ioctl = can_eth_ioctl_hwts, |
| 1980 | + .ndo_change_mtu = can_change_mtu, | |
| 1980 | 1981 | }; |
| 1981 | 1982 | |
| 1982 | 1983 | static const struct ethtool_ops es58x_ethtool_ops = { |
| @@ -761,6 +761,7 @@ static const struct net_device_ops mcba_netdev_ops = { · 760 unmodified lines | ||
| 761 | 761 | .ndo_open = mcba_usb_open, |
| 762 | 762 | .ndo_stop = mcba_usb_close, |
| 763 | 763 | .ndo_start_xmit = mcba_usb_start_xmit, |
| 764 | + .ndo_change_mtu = can_change_mtu, | |
| 764 | 765 | }; |
| 765 | 766 | |
| 766 | 767 | static const struct ethtool_ops mcba_ethtool_ops = { |
| @@ -111,7 +111,7 @@ void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now) · 110 unmodified lines | ||
| 111 | 111 | u32 delta_ts = time_ref->ts_dev_2 - time_ref->ts_dev_1; |
| 112 | 112 | |
| 113 | 113 | if (time_ref->ts_dev_2 < time_ref->ts_dev_1) |
| 114 | − delta_ts &= (1 << time_ref->adapter->ts_used_bits) - 1; | |
| 114 | + delta_ts &= (1ULL << time_ref->adapter->ts_used_bits) - 1; | |
| 115 | 115 | |
| 116 | 116 | time_ref->ts_total += delta_ts; |
| 117 | 117 | } |
| @@ -685,18 +685,27 @@ static int gswip_add_single_port_br(struct gswip_priv *priv, int port, bool add) · 684 unmodified lines | ||
| 685 | 685 | return 0; |
| 686 | 686 | } |
| 687 | 687 | |
| 688 | −static int gswip_port_enable(struct dsa_switch *ds, int port, | |
| 689 | − struct phy_device *phydev) | |
| 688 | +static int gswip_port_setup(struct dsa_switch *ds, int port) | |
| 690 | 689 | { |
| 691 | 690 | struct gswip_priv *priv = ds->priv; |
| 692 | 691 | int err; |
| 693 | 692 | |
| 694 | 693 | if (!dsa_is_cpu_port(ds, port)) { |
| 695 | − u32 mdio_phy = 0; | |
| 696 | − | |
| 697 | 694 | err = gswip_add_single_port_br(priv, port, true); |
| 698 | 695 | if (err) |
| 699 | 696 | return err; |
| 697 | + } | |
| 698 | + | |
| 699 | + return 0; | |
| 700 | +} | |
| 701 | + | |
| 702 | +static int gswip_port_enable(struct dsa_switch *ds, int port, | |
| 703 | + struct phy_device *phydev) | |
| 704 | +{ | |
| 705 | + struct gswip_priv *priv = ds->priv; | |
| 706 | + | |
| 707 | + if (!dsa_is_cpu_port(ds, port)) { | |
| 708 | + u32 mdio_phy = 0; | |
| 700 | 709 | |
| 701 | 710 | if (phydev) |
| 702 | 711 | mdio_phy = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK; |
| @@ -1359,8 +1368,9 @@ static int gswip_port_fdb(struct dsa_switch *ds, int port, · 656 unmodified lines | ||
| 1359 | 1368 | int i; |
| 1360 | 1369 | int err; |
| 1361 | 1370 | |
| 1371 | + /* Operation not supported on the CPU port, don't throw errors */ | |
| 1362 | 1372 | if (!bridge) |
| 1363 | − return -EINVAL; | |
| 1373 | + return 0; | |
| 1364 | 1374 | |
| 1365 | 1375 | for (i = max_ports; i < ARRAY_SIZE(priv->vlans); i++) { |
| 1366 | 1376 | if (priv->vlans[i].bridge == bridge) { |
| @@ -1829,6 +1839,7 @@ static const struct phylink_mac_ops gswip_phylink_mac_ops = { · 462 unmodified lines | ||
| 1829 | 1839 | static const struct dsa_switch_ops gswip_xrx200_switch_ops = { |
| 1830 | 1840 | .get_tag_protocol = gswip_get_tag_protocol, |
| 1831 | 1841 | .setup = gswip_setup, |
| 1842 | + .port_setup = gswip_port_setup, | |
| 1832 | 1843 | .port_enable = gswip_port_enable, |
| 1833 | 1844 | .port_disable = gswip_port_disable, |
| 1834 | 1845 | .port_bridge_join = gswip_port_bridge_join, |
| @@ -244,7 +244,7 @@ bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions, · 243 unmodified lines | ||
| 244 | 244 | offset < offset_of_ip6_daddr + 16) { |
| 245 | 245 | actions->nat.src_xlate = false; |
| 246 | 246 | idx = (offset - offset_of_ip6_daddr) / 4; |
| 247 | − actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val); | |
| 247 | + actions->nat.l3.ipv6.daddr.s6_addr32[idx] = htonl(val); | |
| 248 | 248 | } else { |
| 249 | 249 | netdev_err(bp->dev, |
| 250 | 250 | "%s: IPv6_hdr: Invalid pedit field\n", |
| @@ -1278,7 +1278,8 @@ struct i40e_mac_filter *i40e_add_mac_filter(struct i40e_vsi *vsi, · 1277 unmodified lines | ||
| 1278 | 1278 | const u8 *macaddr); |
| 1279 | 1279 | int i40e_del_mac_filter(struct i40e_vsi *vsi, const u8 *macaddr); |
| 1280 | 1280 | bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi); |
| 1281 | −int i40e_count_filters(struct i40e_vsi *vsi); | |
| 1281 | +int i40e_count_all_filters(struct i40e_vsi *vsi); | |
| 1282 | +int i40e_count_active_filters(struct i40e_vsi *vsi); | |
| 1282 | 1283 | struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr); |
| 1283 | 1284 | void i40e_vlan_stripping_enable(struct i40e_vsi *vsi); |
| 1284 | 1285 | static inline bool i40e_is_sw_dcb(struct i40e_pf *pf) |
| @@ -1243,12 +1243,30 @@ void i40e_update_stats(struct i40e_vsi *vsi) · 1242 unmodified lines | ||
| 1243 | 1243 | } |
| 1244 | 1244 | |
| 1245 | 1245 | /** |
| 1246 | − * i40e_count_filters - counts VSI mac filters | |
| 1246 | + * i40e_count_all_filters - counts VSI MAC filters | |
| 1247 | 1247 | * @vsi: the VSI to be searched |
| 1248 | 1248 | * |
| 1249 | − * Returns count of mac filters | |
| 1250 | − **/ | |
| 1251 | −int i40e_count_filters(struct i40e_vsi *vsi) | |
| 1249 | + * Return: count of MAC filters in any state. | |
| 1250 | + */ | |
| 1251 | +int i40e_count_all_filters(struct i40e_vsi *vsi) | |
| 1252 | +{ | |
| 1253 | + struct i40e_mac_filter *f; | |
| 1254 | + struct hlist_node *h; | |
| 1255 | + int bkt, cnt = 0; | |
| 1256 | + | |
| 1257 | + hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) | |
| 1258 | + cnt++; | |
| 1259 | + | |
| 1260 | + return cnt; | |
| 1261 | +} | |
| 1262 | + | |
| 1263 | +/** | |
| 1264 | + * i40e_count_active_filters - counts VSI MAC filters | |
| 1265 | + * @vsi: the VSI to be searched | |
| 1266 | + * | |
| 1267 | + * Return: count of active MAC filters. | |
| 1268 | + */ | |
| 1269 | +int i40e_count_active_filters(struct i40e_vsi *vsi) | |
| 1252 | 1270 | { |
| 1253 | 1271 | struct i40e_mac_filter *f; |
| 1254 | 1272 | struct hlist_node *h; |
| @@ -448,7 +448,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, · 447 unmodified lines | ||
| 448 | 448 | (qtype << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | |
| 449 | 449 | (pf_queue_id << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | |
| 450 | 450 | BIT(I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) | |
| 451 | − (itr_idx << I40E_QINT_RQCTL_ITR_INDX_SHIFT); | |
| 451 | + FIELD_PREP(I40E_QINT_RQCTL_ITR_INDX_MASK, itr_idx); | |
| 452 | 452 | wr32(hw, reg_idx, reg); |
| 453 | 453 | } |
| 454 | 454 | |
| @@ -653,6 +653,13 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id, · 198 unmodified lines | ||
| 653 | 653 | |
| 654 | 654 | /* only set the required fields */ |
| 655 | 655 | tx_ctx.base = info->dma_ring_addr / 128; |
| 656 | + | |
| 657 | + /* ring_len has to be multiple of 8 */ | |
| 658 | + if (!IS_ALIGNED(info->ring_len, 8) || | |
| 659 | + info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) { | |
| 660 | + ret = -EINVAL; | |
| 661 | + goto error_context; | |
| 662 | + } | |
| 656 | 663 | tx_ctx.qlen = info->ring_len; |
| 657 | 664 | tx_ctx.rdylist = le16_to_cpu(vsi->info.qs_handle[0]); |
| 658 | 665 | tx_ctx.rdylist_act = 0; |
| @@ -716,6 +723,13 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id, · 57 unmodified lines | ||
| 716 | 723 | |
| 717 | 724 | /* only set the required fields */ |
| 718 | 725 | rx_ctx.base = info->dma_ring_addr / 128; |
| 726 | + | |
| 727 | + /* ring_len has to be multiple of 32 */ | |
| 728 | + if (!IS_ALIGNED(info->ring_len, 32) || | |
| 729 | + info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) { | |
| 730 | + ret = -EINVAL; | |
| 731 | + goto error_param; | |
| 732 | + } | |
| 719 | 733 | rx_ctx.qlen = info->ring_len; |
| 720 | 734 | |
| 721 | 735 | if (info->splithdr_enabled) { |
| @@ -1450,6 +1464,7 @@ static void i40e_trigger_vf_reset(struct i40e_vf *vf, bool flr) · 728 unmodified lines | ||
| 1450 | 1464 | * functions that may still be running at this point. |
| 1451 | 1465 | */ |
| 1452 | 1466 | clear_bit(I40E_VF_STATE_INIT, &vf->vf_states); |
| 1467 | + clear_bit(I40E_VF_STATE_RESOURCES_LOADED, &vf->vf_states); | |
| 1453 | 1468 | |
| 1454 | 1469 | /* In the case of a VFLR, the HW has already reset the VF and we |
| 1455 | 1470 | * just need to clean up, so don't hit the VFRTRIG register. |
| @@ -2116,7 +2131,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) · 660 unmodified lines | ||
| 2116 | 2131 | size_t len = 0; |
| 2117 | 2132 | int ret; |
| 2118 | 2133 | |
| 2119 | − if (!i40e_sync_vf_state(vf, I40E_VF_STATE_INIT)) { | |
| 2134 | + i40e_sync_vf_state(vf, I40E_VF_STATE_INIT); | |
| 2135 | + | |
| 2136 | + if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states) || | |
| 2137 | + test_bit(I40E_VF_STATE_RESOURCES_LOADED, &vf->vf_states)) { | |
| 2120 | 2138 | aq_ret = -EINVAL; |
| 2121 | 2139 | goto err; |
| 2122 | 2140 | } |
| @@ -2219,6 +2237,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) · 96 unmodified lines | ||
| 2219 | 2237 | vf->default_lan_addr.addr); |
| 2220 | 2238 | } |
| 2221 | 2239 | set_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states); |
| 2240 | + set_bit(I40E_VF_STATE_RESOURCES_LOADED, &vf->vf_states); | |
| 2222 | 2241 | |
| 2223 | 2242 | err: |
| 2224 | 2243 | /* send the response back to the VF */ |
| @@ -2381,7 +2400,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg) · 156 unmodified lines | ||
| 2381 | 2400 | } |
| 2382 | 2401 | |
| 2383 | 2402 | if (vf->adq_enabled) { |
| 2384 | − if (idx >= ARRAY_SIZE(vf->ch)) { | |
| 2403 | + if (idx >= vf->num_tc) { | |
| 2385 | 2404 | aq_ret = -ENODEV; |
| 2386 | 2405 | goto error_param; |
| 2387 | 2406 | } |
| @@ -2402,7 +2421,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg) · 14 unmodified lines | ||
| 2402 | 2421 | * to its appropriate VSIs based on TC mapping |
| 2403 | 2422 | */ |
| 2404 | 2423 | if (vf->adq_enabled) { |
| 2405 | − if (idx >= ARRAY_SIZE(vf->ch)) { | |
| 2424 | + if (idx >= vf->num_tc) { | |
| 2406 | 2425 | aq_ret = -ENODEV; |
| 2407 | 2426 | goto error_param; |
| 2408 | 2427 | } |
| @@ -2452,8 +2471,10 @@ static int i40e_validate_queue_map(struct i40e_vf *vf, u16 vsi_id, · 43 unmodified lines | ||
| 2452 | 2471 | u16 vsi_queue_id, queue_id; |
| 2453 | 2472 | |
| 2454 | 2473 | for_each_set_bit(vsi_queue_id, &queuemap, I40E_MAX_VSI_QP) { |
| 2455 | − if (vf->adq_enabled) { | |
| 2456 | − vsi_id = vf->ch[vsi_queue_id / I40E_MAX_VF_VSI].vsi_id; | |
| 2474 | + u16 idx = vsi_queue_id / I40E_MAX_VF_VSI; | |
| 2475 | + | |
| 2476 | + if (vf->adq_enabled && idx < vf->num_tc) { | |
| 2477 | + vsi_id = vf->ch[idx].vsi_id; | |
| 2457 | 2478 | queue_id = (vsi_queue_id % I40E_DEFAULT_QUEUES_PER_VF); |
| 2458 | 2479 | } else { |
| 2459 | 2480 | queue_id = vsi_queue_id; |
| @@ -2841,24 +2862,6 @@ error_param: · 381 unmodified lines | ||
| 2841 | 2862 | (u8 *)&stats, sizeof(stats)); |
| 2842 | 2863 | } |
| 2843 | 2864 | |
| 2844 | −/** | |
| 2845 | − * i40e_can_vf_change_mac | |
| 2846 | − * @vf: pointer to the VF info | |
| 2847 | − * | |
| 2848 | − * Return true if the VF is allowed to change its MAC filters, false otherwise | |
| 2849 | − */ | |
| 2850 | −static bool i40e_can_vf_change_mac(struct i40e_vf *vf) | |
| 2851 | −{ | |
| 2852 | − /* If the VF MAC address has been set administratively (via the | |
| 2853 | − * ndo_set_vf_mac command), then deny permission to the VF to | |
| 2854 | − * add/delete unicast MAC addresses, unless the VF is trusted | |
| 2855 | − */ | |
| 2856 | − if (vf->pf_set_mac && !vf->trusted) | |
| 2857 | − return false; | |
| 2858 | − | |
| 2859 | − return true; | |
| 2860 | −} | |
| 2861 | − | |
| 2862 | 2865 | #define I40E_MAX_MACVLAN_PER_HW 3072 |
| 2863 | 2866 | #define I40E_MAX_MACVLAN_PER_PF(num_ports) (I40E_MAX_MACVLAN_PER_HW / \ |
| 2864 | 2867 | (num_ports)) |
| @@ -2897,8 +2900,10 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, · 32 unmodified lines | ||
| 2897 | 2900 | struct i40e_pf *pf = vf->pf; |
| 2898 | 2901 | struct i40e_vsi *vsi = pf->vsi[vf->lan_vsi_idx]; |
| 2899 | 2902 | struct i40e_hw *hw = &pf->hw; |
| 2900 | − int mac2add_cnt = 0; | |
| 2901 | − int i; | |
| 2903 | + int i, mac_add_max, mac_add_cnt = 0; | |
| 2904 | + bool vf_trusted; | |
| 2905 | + | |
| 2906 | + vf_trusted = test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps); | |
| 2902 | 2907 | |
| 2903 | 2908 | for (i = 0; i < al->num_elements; i++) { |
| 2904 | 2909 | struct i40e_mac_filter *f; |
| @@ -2918,9 +2923,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, · 13 unmodified lines | ||
| 2918 | 2923 | * The VF may request to set the MAC address filter already |
| 2919 | 2924 | * assigned to it so do not return an error in that case. |
| 2920 | 2925 | */ |
| 2921 | − if (!i40e_can_vf_change_mac(vf) && | |
| 2922 | − !is_multicast_ether_addr(addr) && | |
| 2923 | − !ether_addr_equal(addr, vf->default_lan_addr.addr)) { | |
| 2926 | + if (!vf_trusted && !is_multicast_ether_addr(addr) && | |
| 2927 | + vf->pf_set_mac && !ether_addr_equal(addr, vf->default_lan_addr.addr)) { | |
| 2924 | 2928 | dev_err(&pf->pdev->dev, |
| 2925 | 2929 | "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n"); |
| 2926 | 2930 | return -EPERM; |
| @@ -2929,29 +2933,33 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, · 2 unmodified lines | ||
| 2929 | 2933 | /*count filters that really will be added*/ |
| 2930 | 2934 | f = i40e_find_mac(vsi, addr); |
| 2931 | 2935 | if (!f) |
| 2932 | − ++mac2add_cnt; | |
| 2936 | + ++mac_add_cnt; | |
| 2933 | 2937 | } |
| 2934 | 2938 | |
| 2935 | 2939 | /* If this VF is not privileged, then we can't add more than a limited |
| 2936 | − * number of addresses. Check to make sure that the additions do not | |
| 2937 | − * push us over the limit. | |
| 2938 | − */ | |
| 2939 | − if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) { | |
| 2940 | − if ((i40e_count_filters(vsi) + mac2add_cnt) > | |
| 2941 | − I40E_VC_MAX_MAC_ADDR_PER_VF) { | |
| 2942 | − dev_err(&pf->pdev->dev, | |
| 2943 | − "Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n"); | |
| 2944 | − return -EPERM; | |
| 2945 | − } | |
| 2946 | − /* If this VF is trusted, it can use more resources than untrusted. | |
| 2940 | + * number of addresses. | |
| 2941 | + * | |
| 2942 | + * If this VF is trusted, it can use more resources than untrusted. | |
| 2947 | 2943 | * However to ensure that every trusted VF has appropriate number of |
| 2948 | 2944 | * resources, divide whole pool of resources per port and then across |
| 2949 | 2945 | * all VFs. |
| 2950 | 2946 | */ |
| 2951 | − } else { | |
| 2952 | − if ((i40e_count_filters(vsi) + mac2add_cnt) > | |
| 2953 | − I40E_VC_MAX_MACVLAN_PER_TRUSTED_VF(pf->num_alloc_vfs, | |
| 2954 | − hw->num_ports)) { | |
| 2947 | + if (!vf_trusted) | |
| 2948 | + mac_add_max = I40E_VC_MAX_MAC_ADDR_PER_VF; | |
| 2949 | + else | |
| 2950 | + mac_add_max = I40E_VC_MAX_MACVLAN_PER_TRUSTED_VF(pf->num_alloc_vfs, hw->num_ports); | |
| 2951 | + | |
| 2952 | + /* VF can replace all its filters in one step, in this case mac_add_max | |
| 2953 | + * will be added as active and another mac_add_max will be in | |
| 2954 | + * a to-be-removed state. Account for that. | |
| 2955 | + */ | |
| 2956 | + if ((i40e_count_active_filters(vsi) + mac_add_cnt) > mac_add_max || | |
| 2957 | + (i40e_count_all_filters(vsi) + mac_add_cnt) > 2 * mac_add_max) { | |
| 2958 | + if (!vf_trusted) { | |
| 2959 | + dev_err(&pf->pdev->dev, | |
| 2960 | + "Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n"); | |
| 2961 | + return -EPERM; | |
| 2962 | + } else { | |
| 2955 | 2963 | dev_err(&pf->pdev->dev, |
| 2956 | 2964 | "Cannot add more MAC addresses, trusted VF exhausted it's resources\n"); |
| 2957 | 2965 | return -EPERM; |
| @@ -3587,7 +3595,7 @@ static int i40e_validate_cloud_filter(struct i40e_vf *vf, · 629 unmodified lines | ||
| 3587 | 3595 | |
| 3588 | 3596 | /* action_meta is TC number here to which the filter is applied */ |
| 3589 | 3597 | if (!tc_filter->action_meta || |
| 3590 | − tc_filter->action_meta > vf->num_tc) { | |
| 3598 | + tc_filter->action_meta >= vf->num_tc) { | |
| 3591 | 3599 | dev_info(&pf->pdev->dev, "VF %d: Invalid TC number %u\n", |
| 3592 | 3600 | vf->vf_id, tc_filter->action_meta); |
| 3593 | 3601 | goto err; |
| @@ -3884,6 +3892,8 @@ err: · 290 unmodified lines | ||
| 3884 | 3892 | aq_ret); |
| 3885 | 3893 | } |
| 3886 | 3894 | |
| 3895 | +#define I40E_MAX_VF_CLOUD_FILTER 0xFF00 | |
| 3896 | + | |
| 3887 | 3897 | /** |
| 3888 | 3898 | * i40e_vc_add_cloud_filter |
| 3889 | 3899 | * @vf: pointer to the VF info |
| @@ -3923,6 +3933,14 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg) · 33 unmodified lines | ||
| 3923 | 3933 | goto err_out; |
| 3924 | 3934 | } |
| 3925 | 3935 | |
| 3936 | + if (vf->num_cloud_filters >= I40E_MAX_VF_CLOUD_FILTER) { | |
| 3937 | + dev_warn(&pf->pdev->dev, | |
| 3938 | + "VF %d: Max number of filters reached, can't apply cloud filter\n", | |
| 3939 | + vf->vf_id); | |
| 3940 | + aq_ret = -ENOSPC; | |
| 3941 | + goto err_out; | |
| 3942 | + } | |
| 3943 | + | |
| 3926 | 3944 | cfilter = kzalloc(sizeof(*cfilter), GFP_KERNEL); |
| 3927 | 3945 | if (!cfilter) { |
| 3928 | 3946 | aq_ret = -ENOMEM; |
| @@ -41,7 +41,8 @@ enum i40e_vf_states { · 40 unmodified lines | ||
| 41 | 41 | I40E_VF_STATE_MC_PROMISC, |
| 42 | 42 | I40E_VF_STATE_UC_PROMISC, |
| 43 | 43 | I40E_VF_STATE_PRE_ENABLE, |
| 44 | − I40E_VF_STATE_RESETTING | |
| 44 | + I40E_VF_STATE_RESETTING, | |
| 45 | + I40E_VF_STATE_RESOURCES_LOADED, | |
| 45 | 46 | }; |
| 46 | 47 | |
| 47 | 48 | /* VF capabilities */ |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | static const char * const libie_aq_str_arr[] = { |
| 8 | 8 | #define LIBIE_AQ_STR(x) \ |
| 9 | − [LIBIE_AQ_RC_##x] = "LIBIE_AQ_RC" #x | |
| 9 | + [LIBIE_AQ_RC_##x] = "LIBIE_AQ_RC_" #x | |
| 10 | 10 | LIBIE_AQ_STR(OK), |
| 11 | 11 | LIBIE_AQ_STR(EPERM), |
| 12 | 12 | LIBIE_AQ_STR(ENOENT), |
| @@ -21,8 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include "rvu.h" |
| 22 | 22 | #include "lmac_common.h" |
| 23 | 23 | |
| 24 | −#define DRV_NAME "Marvell-CGX/RPM" | |
| 25 | −#define DRV_STRING "Marvell CGX/RPM Driver" | |
| 24 | +#define DRV_NAME "Marvell-CGX-RPM" | |
| 26 | 25 | |
| 27 | 26 | #define CGX_RX_STAT_GLOBAL_INDEX 9 |
| 28 | 27 | |
| @@ -1326,7 +1326,6 @@ static int otx2_tc_add_flow(struct otx2_nic *nic, · 1325 unmodified lines | ||
| 1326 | 1326 | |
| 1327 | 1327 | free_leaf: |
| 1328 | 1328 | otx2_tc_del_from_flow_list(flow_cfg, new_node); |
| 1329 | − kfree_rcu(new_node, rcu); | |
| 1330 | 1329 | if (new_node->is_act_police) { |
| 1331 | 1330 | mutex_lock(&nic->mbox.lock); |
| 1332 | 1331 | |
| @@ -1346,6 +1345,7 @@ free_leaf: · 13 unmodified lines | ||
| 1346 | 1345 | |
| 1347 | 1346 | mutex_unlock(&nic->mbox.lock); |
| 1348 | 1347 | } |
| 1348 | + kfree_rcu(new_node, rcu); | |
| 1349 | 1349 | |
| 1350 | 1350 | return rc; |
| 1351 | 1351 | } |
| @@ -1466,6 +1466,7 @@ static void fec_set_block_stats(struct mlx5e_priv *priv, · 1465 unmodified lines | ||
| 1466 | 1466 | case MLX5E_FEC_RS_528_514: |
| 1467 | 1467 | case MLX5E_FEC_RS_544_514: |
| 1468 | 1468 | case MLX5E_FEC_LLRS_272_257_1: |
| 1469 | + case MLX5E_FEC_RS_544_514_INTERLEAVED_QUAD: | |
| 1469 | 1470 | fec_set_rs_stats(fec_stats, out); |
| 1470 | 1471 | return; |
| 1471 | 1472 | case MLX5E_FEC_FIRECODE: |
| @@ -663,7 +663,7 @@ static void del_sw_hw_rule(struct fs_node *node) · 662 unmodified lines | ||
| 663 | 663 | BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_ACTION) | |
| 664 | 664 | BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_FLOW_COUNTERS); |
| 665 | 665 | fte->act_dests.action.action &= ~MLX5_FLOW_CONTEXT_ACTION_COUNT; |
| 666 | − mlx5_fc_local_destroy(rule->dest_attr.counter); | |
| 666 | + mlx5_fc_local_put(rule->dest_attr.counter); | |
| 667 | 667 | goto out; |
| 668 | 668 | } |
| 669 | 669 | |
| @@ -343,6 +343,7 @@ struct mlx5_fc { · 342 unmodified lines | ||
| 343 | 343 | enum mlx5_fc_type type; |
| 344 | 344 | struct mlx5_fc_bulk *bulk; |
| 345 | 345 | struct mlx5_fc_cache cache; |
| 346 | + refcount_t fc_local_refcount; | |
| 346 | 347 | /* last{packets,bytes} are used for calculating deltas since last reading. */ |
| 347 | 348 | u64 lastpackets; |
| 348 | 349 | u64 lastbytes; |
| @@ -562,17 +562,36 @@ mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size) · 561 unmodified lines | ||
| 562 | 562 | counter->id = counter_id; |
| 563 | 563 | fc_bulk->base_id = counter_id - offset; |
| 564 | 564 | fc_bulk->fs_bulk.bulk_len = bulk_size; |
| 565 | + refcount_set(&fc_bulk->hws_data.hws_action_refcount, 0); | |
| 566 | + mutex_init(&fc_bulk->hws_data.lock); | |
| 565 | 567 | counter->bulk = fc_bulk; |
| 568 | + refcount_set(&counter->fc_local_refcount, 1); | |
| 566 | 569 | return counter; |
| 567 | 570 | } |
| 568 | 571 | EXPORT_SYMBOL(mlx5_fc_local_create); |
| 569 | 572 | |
| 570 | 573 | void mlx5_fc_local_destroy(struct mlx5_fc *counter) |
| 571 | 574 | { |
| 572 | − if (!counter || counter->type != MLX5_FC_TYPE_LOCAL) | |
| 573 | − return; | |
| 574 | − | |
| 575 | 575 | kfree(counter->bulk); |
| 576 | 576 | kfree(counter); |
| 577 | 577 | } |
| 578 | 578 | EXPORT_SYMBOL(mlx5_fc_local_destroy); |
| 579 | + | |
| 580 | +void mlx5_fc_local_get(struct mlx5_fc *counter) | |
| 581 | +{ | |
| 582 | + if (!counter || counter->type != MLX5_FC_TYPE_LOCAL) | |
| 583 | + return; | |
| 584 | + | |
| 585 | + refcount_inc(&counter->fc_local_refcount); | |
| 586 | +} | |
| 587 | + | |
| 588 | +void mlx5_fc_local_put(struct mlx5_fc *counter) | |
| 589 | +{ | |
| 590 | + if (!counter || counter->type != MLX5_FC_TYPE_LOCAL) | |
| 591 | + return; | |
| 592 | + | |
| 593 | + if (!refcount_dec_and_test(&counter->fc_local_refcount)) | |
| 594 | + return; | |
| 595 | + | |
| 596 | + mlx5_fc_local_destroy(counter); | |
| 597 | +} | |
| @@ -1360,7 +1360,7 @@ free_action: · 1359 unmodified lines | ||
| 1360 | 1360 | struct mlx5hws_action * |
| 1361 | 1361 | mlx5hws_action_create_dest_array(struct mlx5hws_context *ctx, size_t num_dest, |
| 1362 | 1362 | struct mlx5hws_action_dest_attr *dests, |
| 1363 | − bool ignore_flow_level, u32 flags) | |
| 1363 | + u32 flags) | |
| 1364 | 1364 | { |
| 1365 | 1365 | struct mlx5hws_cmd_set_fte_dest *dest_list = NULL; |
| 1366 | 1366 | struct mlx5hws_cmd_ft_create_attr ft_attr = {0}; |
| @@ -1397,7 +1397,7 @@ mlx5hws_action_create_dest_array(struct mlx5hws_context *ctx, size_t num_dest, · 30 unmodified lines | ||
| 1397 | 1397 | MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; |
| 1398 | 1398 | dest_list[i].destination_id = dests[i].dest->dest_obj.obj_id; |
| 1399 | 1399 | fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; |
| 1400 | − fte_attr.ignore_flow_level = ignore_flow_level; | |
| 1400 | + fte_attr.ignore_flow_level = 1; | |
| 1401 | 1401 | if (dests[i].is_wire_ft) |
| 1402 | 1402 | last_dest_idx = i; |
| 1403 | 1403 | break; |
| @@ -572,12 +572,12 @@ static void mlx5_fs_put_dest_action_sampler(struct mlx5_fs_hws_context *fs_ctx, · 571 unmodified lines | ||
| 572 | 572 | static struct mlx5hws_action * |
| 573 | 573 | mlx5_fs_create_action_dest_array(struct mlx5hws_context *ctx, |
| 574 | 574 | struct mlx5hws_action_dest_attr *dests, |
| 575 | − u32 num_of_dests, bool ignore_flow_level) | |
| 575 | + u32 num_of_dests) | |
| 576 | 576 | { |
| 577 | 577 | u32 flags = MLX5HWS_ACTION_FLAG_HWS_FDB | MLX5HWS_ACTION_FLAG_SHARED; |
| 578 | 578 | |
| 579 | 579 | return mlx5hws_action_create_dest_array(ctx, num_of_dests, dests, |
| 580 | − ignore_flow_level, flags); | |
| 580 | + flags); | |
| 581 | 581 | } |
| 582 | 582 | |
| 583 | 583 | static struct mlx5hws_action * |
| @@ -1014,19 +1014,14 @@ static int mlx5_fs_fte_get_hws_actions(struct mlx5_flow_root_namespace *ns, · 430 unmodified lines | ||
| 1014 | 1014 | } |
| 1015 | 1015 | (*ractions)[num_actions++].action = dest_actions->dest; |
| 1016 | 1016 | } else if (num_dest_actions > 1) { |
| 1017 | − bool ignore_flow_level; | |
| 1018 | − | |
| 1019 | 1017 | if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || |
| 1020 | 1018 | num_fs_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { |
| 1021 | 1019 | err = -EOPNOTSUPP; |
| 1022 | 1020 | goto free_actions; |
| 1023 | 1021 | } |
| 1024 | − ignore_flow_level = | |
| 1025 | − !!(fte_action->flags & FLOW_ACT_IGNORE_FLOW_LEVEL); | |
| 1026 | 1022 | tmp_action = |
| 1027 | 1023 | mlx5_fs_create_action_dest_array(ctx, dest_actions, |
| 1028 | − num_dest_actions, | |
| 1029 | − ignore_flow_level); | |
| 1024 | + num_dest_actions); | |
| 1030 | 1025 | if (!tmp_action) { |
| 1031 | 1026 | err = -EOPNOTSUPP; |
| 1032 | 1027 | goto free_actions; |
| @@ -407,15 +407,21 @@ struct mlx5hws_action *mlx5_fc_get_hws_action(struct mlx5hws_context *ctx, · 406 unmodified lines | ||
| 407 | 407 | { |
| 408 | 408 | struct mlx5_fs_hws_create_action_ctx create_ctx; |
| 409 | 409 | struct mlx5_fc_bulk *fc_bulk = counter->bulk; |
| 410 | + struct mlx5hws_action *hws_action; | |
| 410 | 411 | |
| 411 | 412 | create_ctx.hws_ctx = ctx; |
| 412 | 413 | create_ctx.id = fc_bulk->base_id; |
| 413 | 414 | create_ctx.actions_type = MLX5HWS_ACTION_TYP_CTR; |
| 414 | 415 | |
| 415 | − return mlx5_fs_get_hws_action(&fc_bulk->hws_data, &create_ctx); | |
| 416 | + mlx5_fc_local_get(counter); | |
| 417 | + hws_action = mlx5_fs_get_hws_action(&fc_bulk->hws_data, &create_ctx); | |
| 418 | + if (!hws_action) | |
| 419 | + mlx5_fc_local_put(counter); | |
| 420 | + return hws_action; | |
| 416 | 421 | } |
| 417 | 422 | |
| 418 | 423 | void mlx5_fc_put_hws_action(struct mlx5_fc *counter) |
| 419 | 424 | { |
| 420 | 425 | mlx5_fs_put_hws_action(&counter->bulk->hws_data); |
| 426 | + mlx5_fc_local_put(counter); | |
| 421 | 427 | } |
| @@ -735,7 +735,6 @@ mlx5hws_action_create_push_vlan(struct mlx5hws_context *ctx, u32 flags); · 734 unmodified lines | ||
| 735 | 735 | * @num_dest: The number of dests attributes. |
| 736 | 736 | * @dests: The destination array. Each contains a destination action and can |
| 737 | 737 | * have additional actions. |
| 738 | − * @ignore_flow_level: Whether to turn on 'ignore_flow_level' for this dest. | |
| 739 | 738 | * @flags: Action creation flags (enum mlx5hws_action_flags). |
| 740 | 739 | * |
| 741 | 740 | * Return: pointer to mlx5hws_action on success NULL otherwise. |
| @@ -743,7 +742,7 @@ mlx5hws_action_create_push_vlan(struct mlx5hws_context *ctx, u32 flags); · 1 unmodified line | ||
| 743 | 742 | struct mlx5hws_action * |
| 744 | 743 | mlx5hws_action_create_dest_array(struct mlx5hws_context *ctx, size_t num_dest, |
| 745 | 744 | struct mlx5hws_action_dest_attr *dests, |
| 746 | − bool ignore_flow_level, u32 flags); | |
| 745 | + u32 flags); | |
| 747 | 746 | |
| 748 | 747 | /** |
| 749 | 748 | * mlx5hws_action_create_insert_header - Create insert header action. |
| @@ -597,10 +597,6 @@ static int bcm_ptp_perout_locked(struct bcm_ptp_private *priv, · 596 unmodified lines | ||
| 597 | 597 | |
| 598 | 598 | period = BCM_MAX_PERIOD_8NS; /* write nonzero value */ |
| 599 | 599 | |
| 600 | − /* Reject unsupported flags */ | |
| 601 | − if (req->flags & ~PTP_PEROUT_DUTY_CYCLE) | |
| 602 | − return -EOPNOTSUPP; | |
| 603 | − | |
| 604 | 600 | if (req->flags & PTP_PEROUT_DUTY_CYCLE) |
| 605 | 601 | pulse = ktime_to_ns(ktime_set(req->on.sec, req->on.nsec)); |
| 606 | 602 | else |
| @@ -741,6 +737,8 @@ static const struct ptp_clock_info bcm_ptp_clock_info = { · 134 unmodified lines | ||
| 741 | 737 | .n_pins = 1, |
| 742 | 738 | .n_per_out = 1, |
| 743 | 739 | .n_ext_ts = 1, |
| 740 | + .supported_perout_flags = PTP_PEROUT_DUTY_CYCLE, | |
| 741 | + .supported_extts_flags = PTP_STRICT_FLAGS | PTP_RISING_EDGE, | |
| 744 | 742 | }; |
| 745 | 743 | |
| 746 | 744 | static void bcm_ptp_txtstamp(struct mii_timestamper *mii_ts, |
| @@ -1875,6 +1875,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, · 1874 unmodified lines | ||
| 1875 | 1875 | local_bh_enable(); |
| 1876 | 1876 | goto unlock_frags; |
| 1877 | 1877 | } |
| 1878 | + | |
| 1879 | + if (frags && skb != tfile->napi.skb) | |
| 1880 | + tfile->napi.skb = skb; | |
| 1878 | 1881 | } |
| 1879 | 1882 | rcu_read_unlock(); |
| 1880 | 1883 | local_bh_enable(); |
| @@ -308,6 +308,8 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging); · 307 unmodified lines | ||
| 308 | 308 | void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter); |
| 309 | 309 | struct mlx5_fc *mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size); |
| 310 | 310 | void mlx5_fc_local_destroy(struct mlx5_fc *counter); |
| 311 | +void mlx5_fc_local_get(struct mlx5_fc *counter); | |
| 312 | +void mlx5_fc_local_put(struct mlx5_fc *counter); | |
| 311 | 313 | u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter); |
| 312 | 314 | void mlx5_fc_query_cached(struct mlx5_fc *counter, |
| 313 | 315 | u64 *bytes, u64 *packets, u64 *lastuse); |
| @@ -1245,6 +1245,27 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, · 1244 unmodified lines | ||
| 1245 | 1245 | return NULL; |
| 1246 | 1246 | } |
| 1247 | 1247 | |
| 1248 | +static inline struct hci_conn *hci_conn_hash_lookup_role(struct hci_dev *hdev, | |
| 1249 | + __u8 type, __u8 role, | |
| 1250 | + bdaddr_t *ba) | |
| 1251 | +{ | |
| 1252 | + struct hci_conn_hash *h = &hdev->conn_hash; | |
| 1253 | + struct hci_conn *c; | |
| 1254 | + | |
| 1255 | + rcu_read_lock(); | |
| 1256 | + | |
| 1257 | + list_for_each_entry_rcu(c, &h->list, list) { | |
| 1258 | + if (c->type == type && c->role == role && !bacmp(&c->dst, ba)) { | |
| 1259 | + rcu_read_unlock(); | |
| 1260 | + return c; | |
| 1261 | + } | |
| 1262 | + } | |
| 1263 | + | |
| 1264 | + rcu_read_unlock(); | |
| 1265 | + | |
| 1266 | + return NULL; | |
| 1267 | +} | |
| 1268 | + | |
| 1248 | 1269 | static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev, |
| 1249 | 1270 | bdaddr_t *ba, |
| 1250 | 1271 | __u8 ba_type) |
| @@ -37,6 +37,9 @@ · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | /* |
| 39 | 39 | * flag fields valid for the new PTP_EXTTS_REQUEST2 ioctl. |
| 40 | + * | |
| 41 | + * Note: PTP_STRICT_FLAGS is always enabled by the kernel for | |
| 42 | + * PTP_EXTTS_REQUEST2 regardless of whether it is set by userspace. | |
| 40 | 43 | */ |
| 41 | 44 | #define PTP_EXTTS_VALID_FLAGS (PTP_ENABLE_FEATURE | \ |
| 42 | 45 | PTP_RISING_EDGE | \ |
| @@ -3087,8 +3087,18 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, · 3086 unmodified lines | ||
| 3087 | 3087 | |
| 3088 | 3088 | hci_dev_lock(hdev); |
| 3089 | 3089 | |
| 3090 | + /* Check for existing connection: | |
| 3091 | + * | |
| 3092 | + * 1. If it doesn't exist then it must be receiver/slave role. | |
| 3093 | + * 2. If it does exist confirm that it is connecting/BT_CONNECT in case | |
| 3094 | + * of initiator/master role since there could be a collision where | |
| 3095 | + * either side is attempting to connect or something like a fuzzing | |
| 3096 | + * testing is trying to play tricks to destroy the hcon object before | |
| 3097 | + * it even attempts to connect (e.g. hcon->state == BT_OPEN). | |
| 3098 | + */ | |
| 3090 | 3099 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); |
| 3091 | − if (!conn) { | |
| 3100 | + if (!conn || | |
| 3101 | + (conn->role == HCI_ROLE_MASTER && conn->state != BT_CONNECT)) { | |
| 3092 | 3102 | /* In case of error status and there is no connection pending |
| 3093 | 3103 | * just unlock as there is nothing to cleanup. |
| 3094 | 3104 | */ |
| @@ -4391,6 +4401,8 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, · 1296 unmodified lines | ||
| 4391 | 4401 | |
| 4392 | 4402 | bt_dev_dbg(hdev, "num %d", ev->num); |
| 4393 | 4403 | |
| 4404 | + hci_dev_lock(hdev); | |
| 4405 | + | |
| 4394 | 4406 | for (i = 0; i < ev->num; i++) { |
| 4395 | 4407 | struct hci_comp_pkts_info *info = &ev->handles[i]; |
| 4396 | 4408 | struct hci_conn *conn; |
| @@ -4472,6 +4484,8 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, · 75 unmodified lines | ||
| 4472 | 4484 | } |
| 4473 | 4485 | |
| 4474 | 4486 | queue_work(hdev->workqueue, &hdev->tx_work); |
| 4487 | + | |
| 4488 | + hci_dev_unlock(hdev); | |
| 4475 | 4489 | } |
| 4476 | 4490 | |
| 4477 | 4491 | static void hci_mode_change_evt(struct hci_dev *hdev, void *data, |
| @@ -5634,8 +5648,18 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, · 1156 unmodified lines | ||
| 5634 | 5648 | */ |
| 5635 | 5649 | hci_dev_clear_flag(hdev, HCI_LE_ADV); |
| 5636 | 5650 | |
| 5637 | − conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); | |
| 5638 | − if (!conn) { | |
| 5651 | + /* Check for existing connection: | |
| 5652 | + * | |
| 5653 | + * 1. If it doesn't exist then use the role to create a new object. | |
| 5654 | + * 2. If it does exist confirm that it is connecting/BT_CONNECT in case | |
| 5655 | + * of initiator/master role since there could be a collision where | |
| 5656 | + * either side is attempting to connect or something like a fuzzing | |
| 5657 | + * testing is trying to play tricks to destroy the hcon object before | |
| 5658 | + * it even attempts to connect (e.g. hcon->state == BT_OPEN). | |
| 5659 | + */ | |
| 5660 | + conn = hci_conn_hash_lookup_role(hdev, LE_LINK, role, bdaddr); | |
| 5661 | + if (!conn || | |
| 5662 | + (conn->role == HCI_ROLE_MASTER && conn->state != BT_CONNECT)) { | |
| 5639 | 5663 | /* In case of error status and there is no connection pending |
| 5640 | 5664 | * just unlock as there is nothing to cleanup. |
| 5641 | 5665 | */ |
| @@ -2594,6 +2594,13 @@ static int hci_resume_advertising_sync(struct hci_dev *hdev) · 2593 unmodified lines | ||
| 2594 | 2594 | hci_remove_ext_adv_instance_sync(hdev, adv->instance, |
| 2595 | 2595 | NULL); |
| 2596 | 2596 | } |
| 2597 | + | |
| 2598 | + /* If current advertising instance is set to instance 0x00 | |
| 2599 | + * then we need to re-enable it. | |
| 2600 | + */ | |
| 2601 | + if (!hdev->cur_adv_instance) | |
| 2602 | + err = hci_enable_ext_advertising_sync(hdev, | |
| 2603 | + hdev->cur_adv_instance); | |
| 2597 | 2604 | } else { |
| 2598 | 2605 | /* Schedule for most recent instance to be restarted and begin |
| 2599 | 2606 | * the software rotation loop |
| @@ -1323,8 +1323,7 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err) · 1322 unmodified lines | ||
| 1323 | 1323 | struct mgmt_mode *cp; |
| 1324 | 1324 | |
| 1325 | 1325 | /* Make sure cmd still outstanding. */ |
| 1326 | − if (err == -ECANCELED || | |
| 1327 | − cmd != pending_find(MGMT_OP_SET_POWERED, hdev)) | |
| 1326 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd)) | |
| 1328 | 1327 | return; |
| 1329 | 1328 | |
| 1330 | 1329 | cp = cmd->param; |
| @@ -1351,23 +1350,29 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err) · 20 unmodified lines | ||
| 1351 | 1350 | mgmt_status(err)); |
| 1352 | 1351 | } |
| 1353 | 1352 | |
| 1354 | − mgmt_pending_remove(cmd); | |
| 1353 | + mgmt_pending_free(cmd); | |
| 1355 | 1354 | } |
| 1356 | 1355 | |
| 1357 | 1356 | static int set_powered_sync(struct hci_dev *hdev, void *data) |
| 1358 | 1357 | { |
| 1359 | 1358 | struct mgmt_pending_cmd *cmd = data; |
| 1360 | − struct mgmt_mode *cp; | |
| 1359 | + struct mgmt_mode cp; | |
| 1360 | + | |
| 1361 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 1361 | 1362 | |
| 1362 | 1363 | /* Make sure cmd still outstanding. */ |
| 1363 | − if (cmd != pending_find(MGMT_OP_SET_POWERED, hdev)) | |
| 1364 | + if (!__mgmt_pending_listed(hdev, cmd)) { | |
| 1365 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 1364 | 1366 | return -ECANCELED; |
| 1367 | + } | |
| 1365 | 1368 | |
| 1366 | − cp = cmd->param; | |
| 1369 | + memcpy(&cp, cmd->param, sizeof(cp)); | |
| 1370 | + | |
| 1371 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 1367 | 1372 | |
| 1368 | 1373 | BT_DBG("%s", hdev->name); |
| 1369 | 1374 | |
| 1370 | − return hci_set_powered_sync(hdev, cp->val); | |
| 1375 | + return hci_set_powered_sync(hdev, cp.val); | |
| 1371 | 1376 | } |
| 1372 | 1377 | |
| 1373 | 1378 | static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, |
| @@ -1516,8 +1521,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data, · 142 unmodified lines | ||
| 1516 | 1521 | bt_dev_dbg(hdev, "err %d", err); |
| 1517 | 1522 | |
| 1518 | 1523 | /* Make sure cmd still outstanding. */ |
| 1519 | − if (err == -ECANCELED || | |
| 1520 | − cmd != pending_find(MGMT_OP_SET_DISCOVERABLE, hdev)) | |
| 1524 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd)) | |
| 1521 | 1525 | return; |
| 1522 | 1526 | |
| 1523 | 1527 | hci_dev_lock(hdev); |
| @@ -1539,12 +1543,15 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data, · 15 unmodified lines | ||
| 1539 | 1543 | new_settings(hdev, cmd->sk); |
| 1540 | 1544 | |
| 1541 | 1545 | done: |
| 1542 | − mgmt_pending_remove(cmd); | |
| 1546 | + mgmt_pending_free(cmd); | |
| 1543 | 1547 | hci_dev_unlock(hdev); |
| 1544 | 1548 | } |
| 1545 | 1549 | |
| 1546 | 1550 | static int set_discoverable_sync(struct hci_dev *hdev, void *data) |
| 1547 | 1551 | { |
| 1552 | + if (!mgmt_pending_listed(hdev, data)) | |
| 1553 | + return -ECANCELED; | |
| 1554 | + | |
| 1548 | 1555 | BT_DBG("%s", hdev->name); |
| 1549 | 1556 | |
| 1550 | 1557 | return hci_update_discoverable_sync(hdev); |
| @@ -1691,8 +1698,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data, · 140 unmodified lines | ||
| 1691 | 1698 | bt_dev_dbg(hdev, "err %d", err); |
| 1692 | 1699 | |
| 1693 | 1700 | /* Make sure cmd still outstanding. */ |
| 1694 | − if (err == -ECANCELED || | |
| 1695 | − cmd != pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) | |
| 1701 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd)) | |
| 1696 | 1702 | return; |
| 1697 | 1703 | |
| 1698 | 1704 | hci_dev_lock(hdev); |
| @@ -1707,7 +1713,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data, · 8 unmodified lines | ||
| 1707 | 1713 | new_settings(hdev, cmd->sk); |
| 1708 | 1714 | |
| 1709 | 1715 | done: |
| 1710 | − mgmt_pending_remove(cmd); | |
| 1716 | + mgmt_pending_free(cmd); | |
| 1711 | 1717 | |
| 1712 | 1718 | hci_dev_unlock(hdev); |
| 1713 | 1719 | } |
| @@ -1743,6 +1749,9 @@ static int set_connectable_update_settings(struct hci_dev *hdev, · 29 unmodified lines | ||
| 1743 | 1749 | |
| 1744 | 1750 | static int set_connectable_sync(struct hci_dev *hdev, void *data) |
| 1745 | 1751 | { |
| 1752 | + if (!mgmt_pending_listed(hdev, data)) | |
| 1753 | + return -ECANCELED; | |
| 1754 | + | |
| 1746 | 1755 | BT_DBG("%s", hdev->name); |
| 1747 | 1756 | |
| 1748 | 1757 | return hci_update_connectable_sync(hdev); |
| @@ -1919,14 +1928,17 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) · 170 unmodified lines | ||
| 1919 | 1928 | { |
| 1920 | 1929 | struct cmd_lookup match = { NULL, hdev }; |
| 1921 | 1930 | struct mgmt_pending_cmd *cmd = data; |
| 1922 | − struct mgmt_mode *cp = cmd->param; | |
| 1923 | − u8 enable = cp->val; | |
| 1931 | + struct mgmt_mode *cp; | |
| 1932 | + u8 enable; | |
| 1924 | 1933 | bool changed; |
| 1925 | 1934 | |
| 1926 | 1935 | /* Make sure cmd still outstanding. */ |
| 1927 | − if (err == -ECANCELED || cmd != pending_find(MGMT_OP_SET_SSP, hdev)) | |
| 1936 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd)) | |
| 1928 | 1937 | return; |
| 1929 | 1938 | |
| 1939 | + cp = cmd->param; | |
| 1940 | + enable = cp->val; | |
| 1941 | + | |
| 1930 | 1942 | if (err) { |
| 1931 | 1943 | u8 mgmt_err = mgmt_status(err); |
| 1932 | 1944 | |
| @@ -1935,8 +1947,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) · 2 unmodified lines | ||
| 1935 | 1947 | new_settings(hdev, NULL); |
| 1936 | 1948 | } |
| 1937 | 1949 | |
| 1938 | − mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, | |
| 1939 | − cmd_status_rsp, &mgmt_err); | |
| 1950 | + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); | |
| 1940 | 1951 | return; |
| 1941 | 1952 | } |
| 1942 | 1953 | |
| @@ -1946,7 +1957,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) · 3 unmodified lines | ||
| 1946 | 1957 | changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); |
| 1947 | 1958 | } |
| 1948 | 1959 | |
| 1949 | − mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match); | |
| 1960 | + settings_rsp(cmd, &match); | |
| 1950 | 1961 | |
| 1951 | 1962 | if (changed) |
| 1952 | 1963 | new_settings(hdev, match.sk); |
| @@ -1960,14 +1971,25 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) · 7 unmodified lines | ||
| 1960 | 1971 | static int set_ssp_sync(struct hci_dev *hdev, void *data) |
| 1961 | 1972 | { |
| 1962 | 1973 | struct mgmt_pending_cmd *cmd = data; |
| 1963 | − struct mgmt_mode *cp = cmd->param; | |
| 1974 | + struct mgmt_mode cp; | |
| 1964 | 1975 | bool changed = false; |
| 1965 | 1976 | int err; |
| 1966 | 1977 | |
| 1967 | − if (cp->val) | |
| 1978 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 1979 | + | |
| 1980 | + if (!__mgmt_pending_listed(hdev, cmd)) { | |
| 1981 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 1982 | + return -ECANCELED; | |
| 1983 | + } | |
| 1984 | + | |
| 1985 | + memcpy(&cp, cmd->param, sizeof(cp)); | |
| 1986 | + | |
| 1987 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 1988 | + | |
| 1989 | + if (cp.val) | |
| 1968 | 1990 | changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); |
| 1969 | 1991 | |
| 1970 | − err = hci_write_ssp_mode_sync(hdev, cp->val); | |
| 1992 | + err = hci_write_ssp_mode_sync(hdev, cp.val); | |
| 1971 | 1993 | |
| 1972 | 1994 | if (!err && changed) |
| 1973 | 1995 | hci_dev_clear_flag(hdev, HCI_SSP_ENABLED); |
| @@ -2060,32 +2082,50 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) · 86 unmodified lines | ||
| 2060 | 2082 | |
| 2061 | 2083 | static void set_le_complete(struct hci_dev *hdev, void *data, int err) |
| 2062 | 2084 | { |
| 2085 | + struct mgmt_pending_cmd *cmd = data; | |
| 2063 | 2086 | struct cmd_lookup match = { NULL, hdev }; |
| 2064 | 2087 | u8 status = mgmt_status(err); |
| 2065 | 2088 | |
| 2066 | 2089 | bt_dev_dbg(hdev, "err %d", err); |
| 2067 | 2090 | |
| 2068 | − if (status) { | |
| 2069 | − mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp, | |
| 2070 | − &status); | |
| 2091 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, data)) | |
| 2071 | 2092 | return; |
| 2093 | + | |
| 2094 | + if (status) { | |
| 2095 | + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status); | |
| 2096 | + goto done; | |
| 2072 | 2097 | } |
| 2073 | 2098 | |
| 2074 | − mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match); | |
| 2099 | + settings_rsp(cmd, &match); | |
| 2075 | 2100 | |
| 2076 | 2101 | new_settings(hdev, match.sk); |
| 2077 | 2102 | |
| 2078 | 2103 | if (match.sk) |
| 2079 | 2104 | sock_put(match.sk); |
| 2105 | + | |
| 2106 | +done: | |
| 2107 | + mgmt_pending_free(cmd); | |
| 2080 | 2108 | } |
| 2081 | 2109 | |
| 2082 | 2110 | static int set_le_sync(struct hci_dev *hdev, void *data) |
| 2083 | 2111 | { |
| 2084 | 2112 | struct mgmt_pending_cmd *cmd = data; |
| 2085 | − struct mgmt_mode *cp = cmd->param; | |
| 2086 | − u8 val = !!cp->val; | |
| 2113 | + struct mgmt_mode cp; | |
| 2114 | + u8 val; | |
| 2087 | 2115 | int err; |
| 2088 | 2116 | |
| 2117 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 2118 | + | |
| 2119 | + if (!__mgmt_pending_listed(hdev, cmd)) { | |
| 2120 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 2121 | + return -ECANCELED; | |
| 2122 | + } | |
| 2123 | + | |
| 2124 | + memcpy(&cp, cmd->param, sizeof(cp)); | |
| 2125 | + val = !!cp.val; | |
| 2126 | + | |
| 2127 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 2128 | + | |
| 2089 | 2129 | if (!val) { |
| 2090 | 2130 | hci_clear_adv_instance_sync(hdev, NULL, 0x00, true); |
| 2091 | 2131 | |
| @@ -2127,7 +2167,12 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err) · 35 unmodified lines | ||
| 2127 | 2167 | { |
| 2128 | 2168 | struct mgmt_pending_cmd *cmd = data; |
| 2129 | 2169 | u8 status = mgmt_status(err); |
| 2130 | − struct sock *sk = cmd->sk; | |
| 2170 | + struct sock *sk; | |
| 2171 | + | |
| 2172 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd)) | |
| 2173 | + return; | |
| 2174 | + | |
| 2175 | + sk = cmd->sk; | |
| 2131 | 2176 | |
| 2132 | 2177 | if (status) { |
| 2133 | 2178 | mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true, |
| @@ -2142,24 +2187,37 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err) · 8 unmodified lines | ||
| 2142 | 2187 | static int set_mesh_sync(struct hci_dev *hdev, void *data) |
| 2143 | 2188 | { |
| 2144 | 2189 | struct mgmt_pending_cmd *cmd = data; |
| 2145 | − struct mgmt_cp_set_mesh *cp = cmd->param; | |
| 2146 | − size_t len = cmd->param_len; | |
| 2190 | + struct mgmt_cp_set_mesh cp; | |
| 2191 | + size_t len; | |
| 2192 | + | |
| 2193 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 2194 | + | |
| 2195 | + if (!__mgmt_pending_listed(hdev, cmd)) { | |
| 2196 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 2197 | + return -ECANCELED; | |
| 2198 | + } | |
| 2199 | + | |
| 2200 | + memcpy(&cp, cmd->param, sizeof(cp)); | |
| 2201 | + | |
| 2202 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 2203 | + | |
| 2204 | + len = cmd->param_len; | |
| 2147 | 2205 | |
| 2148 | 2206 | memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types)); |
| 2149 | 2207 | |
| 2150 | − if (cp->enable) | |
| 2208 | + if (cp.enable) | |
| 2151 | 2209 | hci_dev_set_flag(hdev, HCI_MESH); |
| 2152 | 2210 | else |
| 2153 | 2211 | hci_dev_clear_flag(hdev, HCI_MESH); |
| 2154 | 2212 | |
| 2155 | − hdev->le_scan_interval = __le16_to_cpu(cp->period); | |
| 2156 | − hdev->le_scan_window = __le16_to_cpu(cp->window); | |
| 2213 | + hdev->le_scan_interval = __le16_to_cpu(cp.period); | |
| 2214 | + hdev->le_scan_window = __le16_to_cpu(cp.window); | |
| 2157 | 2215 | |
| 2158 | − len -= sizeof(*cp); | |
| 2216 | + len -= sizeof(cp); | |
| 2159 | 2217 | |
| 2160 | 2218 | /* If filters don't fit, forward all adv pkts */ |
| 2161 | 2219 | if (len <= sizeof(hdev->mesh_ad_types)) |
| 2162 | − memcpy(hdev->mesh_ad_types, cp->ad_types, len); | |
| 2220 | + memcpy(hdev->mesh_ad_types, cp.ad_types, len); | |
| 2163 | 2221 | |
| 2164 | 2222 | hci_update_passive_scan_sync(hdev); |
| 2165 | 2223 | return 0; |
| @@ -3867,15 +3925,16 @@ static int name_changed_sync(struct hci_dev *hdev, void *data) · 1701 unmodified lines | ||
| 3867 | 3925 | static void set_name_complete(struct hci_dev *hdev, void *data, int err) |
| 3868 | 3926 | { |
| 3869 | 3927 | struct mgmt_pending_cmd *cmd = data; |
| 3870 | − struct mgmt_cp_set_local_name *cp = cmd->param; | |
| 3928 | + struct mgmt_cp_set_local_name *cp; | |
| 3871 | 3929 | u8 status = mgmt_status(err); |
| 3872 | 3930 | |
| 3873 | 3931 | bt_dev_dbg(hdev, "err %d", err); |
| 3874 | 3932 | |
| 3875 | − if (err == -ECANCELED || | |
| 3876 | − cmd != pending_find(MGMT_OP_SET_LOCAL_NAME, hdev)) | |
| 3933 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd)) | |
| 3877 | 3934 | return; |
| 3878 | 3935 | |
| 3936 | + cp = cmd->param; | |
| 3937 | + | |
| 3879 | 3938 | if (status) { |
| 3880 | 3939 | mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, |
| 3881 | 3940 | status); |
| @@ -3887,16 +3946,27 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err) · 5 unmodified lines | ||
| 3887 | 3946 | hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL); |
| 3888 | 3947 | } |
| 3889 | 3948 | |
| 3890 | − mgmt_pending_remove(cmd); | |
| 3949 | + mgmt_pending_free(cmd); | |
| 3891 | 3950 | } |
| 3892 | 3951 | |
| 3893 | 3952 | static int set_name_sync(struct hci_dev *hdev, void *data) |
| 3894 | 3953 | { |
| 3895 | 3954 | struct mgmt_pending_cmd *cmd = data; |
| 3896 | − struct mgmt_cp_set_local_name *cp = cmd->param; | |
| 3955 | + struct mgmt_cp_set_local_name cp; | |
| 3956 | + | |
| 3957 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 3958 | + | |
| 3959 | + if (!__mgmt_pending_listed(hdev, cmd)) { | |
| 3960 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 3961 | + return -ECANCELED; | |
| 3962 | + } | |
| 3963 | + | |
| 3964 | + memcpy(&cp, cmd->param, sizeof(cp)); | |
| 3965 | + | |
| 3966 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 3897 | 3967 | |
| 3898 | 3968 | if (lmp_bredr_capable(hdev)) { |
| 3899 | − hci_update_name_sync(hdev, cp->name); | |
| 3969 | + hci_update_name_sync(hdev, cp.name); | |
| 3900 | 3970 | hci_update_eir_sync(hdev); |
| 3901 | 3971 | } |
| 3902 | 3972 | |
| @@ -4048,12 +4118,10 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip) · 145 unmodified lines | ||
| 4048 | 4118 | static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err) |
| 4049 | 4119 | { |
| 4050 | 4120 | struct mgmt_pending_cmd *cmd = data; |
| 4051 | − struct sk_buff *skb = cmd->skb; | |
| 4121 | + struct sk_buff *skb; | |
| 4052 | 4122 | u8 status = mgmt_status(err); |
| 4053 | 4123 | |
| 4054 | − if (err == -ECANCELED || | |
| 4055 | − cmd != pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) | |
| 4056 | − return; | |
| 4124 | + skb = cmd->skb; | |
| 4057 | 4125 | |
| 4058 | 4126 | if (!status) { |
| 4059 | 4127 | if (!skb) |
| @@ -4080,7 +4148,7 @@ static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err) · 20 unmodified lines | ||
| 4080 | 4148 | if (skb && !IS_ERR(skb)) |
| 4081 | 4149 | kfree_skb(skb); |
| 4082 | 4150 | |
| 4083 | − mgmt_pending_remove(cmd); | |
| 4151 | + mgmt_pending_free(cmd); | |
| 4084 | 4152 | } |
| 4085 | 4153 | |
| 4086 | 4154 | static int set_default_phy_sync(struct hci_dev *hdev, void *data) |
| @@ -4088,7 +4156,9 @@ static int set_default_phy_sync(struct hci_dev *hdev, void *data) · 1 unmodified line | ||
| 4088 | 4156 | struct mgmt_pending_cmd *cmd = data; |
| 4089 | 4157 | struct mgmt_cp_set_phy_configuration *cp = cmd->param; |
| 4090 | 4158 | struct hci_cp_le_set_default_phy cp_phy; |
| 4091 | − u32 selected_phys = __le32_to_cpu(cp->selected_phys); | |
| 4159 | + u32 selected_phys; | |
| 4160 | + | |
| 4161 | + selected_phys = __le32_to_cpu(cp->selected_phys); | |
| 4092 | 4162 | |
| 4093 | 4163 | memset(&cp_phy, 0, sizeof(cp_phy)); |
| 4094 | 4164 | |
| @@ -4228,7 +4298,7 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev, · 133 unmodified lines | ||
| 4228 | 4298 | goto unlock; |
| 4229 | 4299 | } |
| 4230 | 4300 | |
| 4231 | − cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data, | |
| 4301 | + cmd = mgmt_pending_new(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data, | |
| 4232 | 4302 | len); |
| 4233 | 4303 | if (!cmd) |
| 4234 | 4304 | err = -ENOMEM; |
| @@ -5189,7 +5259,17 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, · 954 unmodified lines | ||
| 5189 | 5259 | { |
| 5190 | 5260 | struct mgmt_rp_add_adv_patterns_monitor rp; |
| 5191 | 5261 | struct mgmt_pending_cmd *cmd = data; |
| 5192 | − struct adv_monitor *monitor = cmd->user_data; | |
| 5262 | + struct adv_monitor *monitor; | |
| 5263 | + | |
| 5264 | + /* This is likely the result of hdev being closed and mgmt_index_removed | |
| 5265 | + * is attempting to clean up any pending command so | |
| 5266 | + * hci_adv_monitors_clear is about to be called which will take care of | |
| 5267 | + * freeing the adv_monitor instances. | |
| 5268 | + */ | |
| 5269 | + if (status == -ECANCELED && !mgmt_pending_valid(hdev, cmd)) | |
| 5270 | + return; | |
| 5271 | + | |
| 5272 | + monitor = cmd->user_data; | |
| 5193 | 5273 | |
| 5194 | 5274 | hci_dev_lock(hdev); |
| 5195 | 5275 | |
| @@ -5215,9 +5295,20 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, · 19 unmodified lines | ||
| 5215 | 5295 | static int mgmt_add_adv_patterns_monitor_sync(struct hci_dev *hdev, void *data) |
| 5216 | 5296 | { |
| 5217 | 5297 | struct mgmt_pending_cmd *cmd = data; |
| 5218 | − struct adv_monitor *monitor = cmd->user_data; | |
| 5298 | + struct adv_monitor *mon; | |
| 5299 | + | |
| 5300 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 5301 | + | |
| 5302 | + if (!__mgmt_pending_listed(hdev, cmd)) { | |
| 5303 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 5304 | + return -ECANCELED; | |
| 5305 | + } | |
| 5306 | + | |
| 5307 | + mon = cmd->user_data; | |
| 5308 | + | |
| 5309 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 5219 | 5310 | |
| 5220 | − return hci_add_adv_monitor(hdev, monitor); | |
| 5311 | + return hci_add_adv_monitor(hdev, mon); | |
| 5221 | 5312 | } |
| 5222 | 5313 | |
| 5223 | 5314 | static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, |
| @@ -5484,7 +5575,8 @@ unlock: · 260 unmodified lines | ||
| 5484 | 5575 | status); |
| 5485 | 5576 | } |
| 5486 | 5577 | |
| 5487 | −static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err) | |
| 5578 | +static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, | |
| 5579 | + int err) | |
| 5488 | 5580 | { |
| 5489 | 5581 | struct mgmt_rp_read_local_oob_data mgmt_rp; |
| 5490 | 5582 | size_t rp_size = sizeof(mgmt_rp); |
| @@ -5504,7 +5596,8 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int e · 13 unmodified lines | ||
| 5504 | 5596 | bt_dev_dbg(hdev, "status %d", status); |
| 5505 | 5597 | |
| 5506 | 5598 | if (status) { |
| 5507 | − mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status); | |
| 5599 | + mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, | |
| 5600 | + status); | |
| 5508 | 5601 | goto remove; |
| 5509 | 5602 | } |
| 5510 | 5603 | |
| @@ -5786,17 +5879,12 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err) · 275 unmodified lines | ||
| 5786 | 5879 | |
| 5787 | 5880 | bt_dev_dbg(hdev, "err %d", err); |
| 5788 | 5881 | |
| 5789 | − if (err == -ECANCELED) | |
| 5790 | − return; | |
| 5791 | − | |
| 5792 | − if (cmd != pending_find(MGMT_OP_START_DISCOVERY, hdev) && | |
| 5793 | − cmd != pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev) && | |
| 5794 | − cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev)) | |
| 5882 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd)) | |
| 5795 | 5883 | return; |
| 5796 | 5884 | |
| 5797 | 5885 | mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), |
| 5798 | 5886 | cmd->param, 1); |
| 5799 | − mgmt_pending_remove(cmd); | |
| 5887 | + mgmt_pending_free(cmd); | |
| 5800 | 5888 | |
| 5801 | 5889 | hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED: |
| 5802 | 5890 | DISCOVERY_FINDING); |
| @@ -5804,6 +5892,9 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err) · 1 unmodified line | ||
| 5804 | 5892 | |
| 5805 | 5893 | static int start_discovery_sync(struct hci_dev *hdev, void *data) |
| 5806 | 5894 | { |
| 5895 | + if (!mgmt_pending_listed(hdev, data)) | |
| 5896 | + return -ECANCELED; | |
| 5897 | + | |
| 5807 | 5898 | return hci_start_discovery_sync(hdev); |
| 5808 | 5899 | } |
| 5809 | 5900 | |
| @@ -6009,15 +6100,14 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err) · 199 unmodified lines | ||
| 6009 | 6100 | { |
| 6010 | 6101 | struct mgmt_pending_cmd *cmd = data; |
| 6011 | 6102 | |
| 6012 | − if (err == -ECANCELED || | |
| 6013 | − cmd != pending_find(MGMT_OP_STOP_DISCOVERY, hdev)) | |
| 6103 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd)) | |
| 6014 | 6104 | return; |
| 6015 | 6105 | |
| 6016 | 6106 | bt_dev_dbg(hdev, "err %d", err); |
| 6017 | 6107 | |
| 6018 | 6108 | mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), |
| 6019 | 6109 | cmd->param, 1); |
| 6020 | − mgmt_pending_remove(cmd); | |
| 6110 | + mgmt_pending_free(cmd); | |
| 6021 | 6111 | |
| 6022 | 6112 | if (!err) |
| 6023 | 6113 | hci_discovery_set_state(hdev, DISCOVERY_STOPPED); |
| @@ -6025,6 +6115,9 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err) · 1 unmodified line | ||
| 6025 | 6115 | |
| 6026 | 6116 | static int stop_discovery_sync(struct hci_dev *hdev, void *data) |
| 6027 | 6117 | { |
| 6118 | + if (!mgmt_pending_listed(hdev, data)) | |
| 6119 | + return -ECANCELED; | |
| 6120 | + | |
| 6028 | 6121 | return hci_stop_discovery_sync(hdev); |
| 6029 | 6122 | } |
| 6030 | 6123 | |
| @@ -6234,14 +6327,18 @@ static void enable_advertising_instance(struct hci_dev *hdev, int err) · 203 unmodified lines | ||
| 6234 | 6327 | |
| 6235 | 6328 | static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) |
| 6236 | 6329 | { |
| 6330 | + struct mgmt_pending_cmd *cmd = data; | |
| 6237 | 6331 | struct cmd_lookup match = { NULL, hdev }; |
| 6238 | 6332 | u8 instance; |
| 6239 | 6333 | struct adv_info *adv_instance; |
| 6240 | 6334 | u8 status = mgmt_status(err); |
| 6241 | 6335 | |
| 6336 | + if (err == -ECANCELED || !mgmt_pending_valid(hdev, data)) | |
| 6337 | + return; | |
| 6338 | + | |
| 6242 | 6339 | if (status) { |
| 6243 | − mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, | |
| 6244 | − cmd_status_rsp, &status); | |
| 6340 | + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status); | |
| 6341 | + mgmt_pending_free(cmd); | |
| 6245 | 6342 | return; |
| 6246 | 6343 | } |
| 6247 | 6344 | |
| @@ -6250,8 +6347,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) · 2 unmodified lines | ||
| 6250 | 6347 | else |
| 6251 | 6348 | hci_dev_clear_flag(hdev, HCI_ADVERTISING); |
| 6252 | 6349 | |
| 6253 | − mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp, | |
| 6254 | − &match); | |
| 6350 | + settings_rsp(cmd, &match); | |
| 6255 | 6351 | |
| 6256 | 6352 | new_settings(hdev, match.sk); |
| 6257 | 6353 | |
| @@ -6283,10 +6379,23 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) · 25 unmodified lines | ||
| 6283 | 6379 | static int set_adv_sync(struct hci_dev *hdev, void *data) |
| 6284 | 6380 | { |
| 6285 | 6381 | struct mgmt_pending_cmd *cmd = data; |
| 6286 | − struct mgmt_mode *cp = cmd->param; | |
| 6287 | − u8 val = !!cp->val; | |
| 6382 | + struct mgmt_mode cp; | |
| 6383 | + u8 val; | |
| 6288 | 6384 | |
| 6289 | − if (cp->val == 0x02) | |
| 6385 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 6386 | + | |
| 6387 | + if (!__mgmt_pending_listed(hdev, cmd)) { | |
| 6388 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 6389 | + return -ECANCELED; | |
| 6390 | + } | |
| 6391 | + | |
| 6392 | + memcpy(&cp, cmd->param, sizeof(cp)); | |
| 6393 | + | |
| 6394 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 6395 | + | |
| 6396 | + val = !!cp.val; | |
| 6397 | + | |
| 6398 | + if (cp.val == 0x02) | |
| 6290 | 6399 | hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE); |
| 6291 | 6400 | else |
| 6292 | 6401 | hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE); |
| @@ -8039,10 +8148,6 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data, · 1746 unmodified lines | ||
| 8039 | 8148 | u8 status = mgmt_status(err); |
| 8040 | 8149 | u16 eir_len; |
| 8041 | 8150 | |
| 8042 | − if (err == -ECANCELED || | |
| 8043 | − cmd != pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev)) | |
| 8044 | − return; | |
| 8045 | − | |
| 8046 | 8151 | if (!status) { |
| 8047 | 8152 | if (!skb) |
| 8048 | 8153 | status = MGMT_STATUS_FAILED; |
| @@ -8149,7 +8254,7 @@ done: · 100 unmodified lines | ||
| 8149 | 8254 | kfree_skb(skb); |
| 8150 | 8255 | |
| 8151 | 8256 | kfree(mgmt_rp); |
| 8152 | − mgmt_pending_remove(cmd); | |
| 8257 | + mgmt_pending_free(cmd); | |
| 8153 | 8258 | } |
| 8154 | 8259 | |
| 8155 | 8260 | static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk, |
| @@ -8158,7 +8263,7 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk, · 2 unmodified lines | ||
| 8158 | 8263 | struct mgmt_pending_cmd *cmd; |
| 8159 | 8264 | int err; |
| 8160 | 8265 | |
| 8161 | − cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev, | |
| 8266 | + cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev, | |
| 8162 | 8267 | cp, sizeof(*cp)); |
| 8163 | 8268 | if (!cmd) |
| 8164 | 8269 | return -ENOMEM; |
| @@ -320,6 +320,52 @@ void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) · 319 unmodified lines | ||
| 320 | 320 | mgmt_pending_free(cmd); |
| 321 | 321 | } |
| 322 | 322 | |
| 323 | +bool __mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd) | |
| 324 | +{ | |
| 325 | + struct mgmt_pending_cmd *tmp; | |
| 326 | + | |
| 327 | + lockdep_assert_held(&hdev->mgmt_pending_lock); | |
| 328 | + | |
| 329 | + if (!cmd) | |
| 330 | + return false; | |
| 331 | + | |
| 332 | + list_for_each_entry(tmp, &hdev->mgmt_pending, list) { | |
| 333 | + if (cmd == tmp) | |
| 334 | + return true; | |
| 335 | + } | |
| 336 | + | |
| 337 | + return false; | |
| 338 | +} | |
| 339 | + | |
| 340 | +bool mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd) | |
| 341 | +{ | |
| 342 | + bool listed; | |
| 343 | + | |
| 344 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 345 | + listed = __mgmt_pending_listed(hdev, cmd); | |
| 346 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 347 | + | |
| 348 | + return listed; | |
| 349 | +} | |
| 350 | + | |
| 351 | +bool mgmt_pending_valid(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd) | |
| 352 | +{ | |
| 353 | + bool listed; | |
| 354 | + | |
| 355 | + if (!cmd) | |
| 356 | + return false; | |
| 357 | + | |
| 358 | + mutex_lock(&hdev->mgmt_pending_lock); | |
| 359 | + | |
| 360 | + listed = __mgmt_pending_listed(hdev, cmd); | |
| 361 | + if (listed) | |
| 362 | + list_del(&cmd->list); | |
| 363 | + | |
| 364 | + mutex_unlock(&hdev->mgmt_pending_lock); | |
| 365 | + | |
| 366 | + return listed; | |
| 367 | +} | |
| 368 | + | |
| 323 | 369 | void mgmt_mesh_foreach(struct hci_dev *hdev, |
| 324 | 370 | void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data), |
| 325 | 371 | void *data, struct sock *sk) |
| @@ -65,6 +65,9 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, · 64 unmodified lines | ||
| 65 | 65 | void *data, u16 len); |
| 66 | 66 | void mgmt_pending_free(struct mgmt_pending_cmd *cmd); |
| 67 | 67 | void mgmt_pending_remove(struct mgmt_pending_cmd *cmd); |
| 68 | +bool __mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd); | |
| 69 | +bool mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd); | |
| 70 | +bool mgmt_pending_valid(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd); | |
| 68 | 71 | void mgmt_mesh_foreach(struct hci_dev *hdev, |
| 69 | 72 | void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data), |
| 70 | 73 | void *data, struct sock *sk); |
| @@ -6667,7 +6667,7 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len, · 6666 unmodified lines | ||
| 6667 | 6667 | return NULL; |
| 6668 | 6668 | |
| 6669 | 6669 | while (data_len) { |
| 6670 | − if (nr_frags == MAX_SKB_FRAGS - 1) | |
| 6670 | + if (nr_frags == MAX_SKB_FRAGS) | |
| 6671 | 6671 | goto failure; |
| 6672 | 6672 | while (order && PAGE_ALIGN(data_len) < (PAGE_SIZE << order)) |
| 6673 | 6673 | order--; |
| @@ -2399,6 +2399,13 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, · 2398 unmodified lines | ||
| 2399 | 2399 | return -EINVAL; |
| 2400 | 2400 | } |
| 2401 | 2401 | |
| 2402 | + if (!list_empty(&old->grp_list) && | |
| 2403 | + rtnl_dereference(new->nh_info)->fdb_nh != | |
| 2404 | + rtnl_dereference(old->nh_info)->fdb_nh) { | |
| 2405 | + NL_SET_ERR_MSG(extack, "Cannot change nexthop FDB status while in a group"); | |
| 2406 | + return -EINVAL; | |
| 2407 | + } | |
| 2408 | + | |
| 2402 | 2409 | err = call_nexthop_notifiers(net, NEXTHOP_EVENT_REPLACE, new, extack); |
| 2403 | 2410 | if (err) |
| 2404 | 2411 | return err; |
| @@ -56,6 +56,7 @@ static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb, · 55 unmodified lines | ||
| 56 | 56 | { |
| 57 | 57 | struct smc_lo_dmb_node *dmb_node, *tmp_node; |
| 58 | 58 | struct smc_lo_dev *ldev = smcd->priv; |
| 59 | + struct folio *folio; | |
| 59 | 60 | int sba_idx, rc; |
| 60 | 61 | |
| 61 | 62 | /* check space for new dmb */ |
| @@ -74,13 +75,16 @@ static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb, · 12 unmodified lines | ||
| 74 | 75 | |
| 75 | 76 | dmb_node->sba_idx = sba_idx; |
| 76 | 77 | dmb_node->len = dmb->dmb_len; |
| 77 | − dmb_node->cpu_addr = kzalloc(dmb_node->len, GFP_KERNEL | | |
| 78 | − __GFP_NOWARN | __GFP_NORETRY | | |
| 79 | − __GFP_NOMEMALLOC); | |
| 80 | − if (!dmb_node->cpu_addr) { | |
| 78 | + | |
| 79 | + /* not critical; fail under memory pressure and fallback to TCP */ | |
| 80 | + folio = folio_alloc(GFP_KERNEL | __GFP_NOWARN | __GFP_NOMEMALLOC | | |
| 81 | + __GFP_NORETRY | __GFP_ZERO, | |
| 82 | + get_order(dmb_node->len)); | |
| 83 | + if (!folio) { | |
| 81 | 84 | rc = -ENOMEM; |
| 82 | 85 | goto err_node; |
| 83 | 86 | } |
| 87 | + dmb_node->cpu_addr = folio_address(folio); | |
| 84 | 88 | dmb_node->dma_addr = SMC_DMA_ADDR_INVALID; |
| 85 | 89 | refcount_set(&dmb_node->refcnt, 1); |
| 86 | 90 | |
| @@ -122,7 +126,7 @@ static void __smc_lo_unregister_dmb(struct smc_lo_dev *ldev, · 35 unmodified lines | ||
| 122 | 126 | write_unlock_bh(&ldev->dmb_ht_lock); |
| 123 | 127 | |
| 124 | 128 | clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask); |
| 125 | − kvfree(dmb_node->cpu_addr); | |
| 129 | + folio_put(virt_to_folio(dmb_node->cpu_addr)); | |
| 126 | 130 | kfree(dmb_node); |
| 127 | 131 | |
| 128 | 132 | if (atomic_dec_and_test(&ldev->dmb_cnt)) |
| @@ -438,7 +438,7 @@ ok: · 437 unmodified lines | ||
| 438 | 438 | |
| 439 | 439 | check_tunnel_size = x->xso.type == XFRM_DEV_OFFLOAD_PACKET && |
| 440 | 440 | x->props.mode == XFRM_MODE_TUNNEL; |
| 441 | − switch (x->props.family) { | |
| 441 | + switch (x->inner_mode.family) { | |
| 442 | 442 | case AF_INET: |
| 443 | 443 | /* Check for IPv4 options */ |
| 444 | 444 | if (ip_hdr(skb)->ihl != 5) |
| @@ -2583,6 +2583,8 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high, · 2582 unmodified lines | ||
| 2583 | 2583 | |
| 2584 | 2584 | for (h = 0; h < range; h++) { |
| 2585 | 2585 | u32 spi = (low == high) ? low : get_random_u32_inclusive(low, high); |
| 2586 | + if (spi == 0) | |
| 2587 | + goto next; | |
| 2586 | 2588 | newspi = htonl(spi); |
| 2587 | 2589 | |
| 2588 | 2590 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
| @@ -2598,6 +2600,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high, · 9 unmodified lines | ||
| 2598 | 2600 | xfrm_state_put(x0); |
| 2599 | 2601 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
| 2600 | 2602 | |
| 2603 | +next: | |
| 2601 | 2604 | if (signal_pending(current)) { |
| 2602 | 2605 | err = -ERESTARTSYS; |
| 2603 | 2606 | goto unlock; |
| @@ -467,8 +467,8 @@ ipv6_fdb_grp_fcnal() · 466 unmodified lines | ||
| 467 | 467 | log_test $? 0 "Get Fdb nexthop group by id" |
| 468 | 468 | |
| 469 | 469 | # fdb nexthop group can only contain fdb nexthops |
| 470 | − run_cmd "$IP nexthop add id 63 via 2001:db8:91::4" | |
| 471 | − run_cmd "$IP nexthop add id 64 via 2001:db8:91::5" | |
| 470 | + run_cmd "$IP nexthop add id 63 via 2001:db8:91::4 dev veth1" | |
| 471 | + run_cmd "$IP nexthop add id 64 via 2001:db8:91::5 dev veth1" | |
| 472 | 472 | run_cmd "$IP nexthop add id 103 group 63/64 fdb" |
| 473 | 473 | log_test $? 2 "Fdb Nexthop group with non-fdb nexthops" |
| 474 | 474 | |
| @@ -494,6 +494,26 @@ ipv6_fdb_grp_fcnal() · 19 unmodified lines | ||
| 494 | 494 | run_cmd "$IP nexthop add id 69 encap mpls 101 via 2001:db8:91::8 dev veth1 fdb" |
| 495 | 495 | log_test $? 2 "Fdb Nexthop with encap" |
| 496 | 496 | |
| 497 | + # Replace FDB nexthop to non-FDB and vice versa | |
| 498 | + run_cmd "$IP nexthop add id 70 via 2001:db8:91::2 fdb" | |
| 499 | + run_cmd "$IP nexthop replace id 70 via 2001:db8:91::2 dev veth1" | |
| 500 | + log_test $? 0 "Replace FDB nexthop to non-FDB nexthop" | |
| 501 | + run_cmd "$IP nexthop replace id 70 via 2001:db8:91::2 fdb" | |
| 502 | + log_test $? 0 "Replace non-FDB nexthop to FDB nexthop" | |
| 503 | + | |
| 504 | + # Replace FDB nexthop address while in a group | |
| 505 | + run_cmd "$IP nexthop add id 71 group 70 fdb" | |
| 506 | + run_cmd "$IP nexthop replace id 70 via 2001:db8:91::3 fdb" | |
| 507 | + log_test $? 0 "Replace FDB nexthop address while in a group" | |
| 508 | + | |
| 509 | + # Cannot replace FDB nexthop to non-FDB and vice versa while in a group | |
| 510 | + run_cmd "$IP nexthop replace id 70 via 2001:db8:91::2 dev veth1" | |
| 511 | + log_test $? 2 "Replace FDB nexthop to non-FDB nexthop while in a group" | |
| 512 | + run_cmd "$IP nexthop add id 72 via 2001:db8:91::2 dev veth1" | |
| 513 | + run_cmd "$IP nexthop add id 73 group 72" | |
| 514 | + run_cmd "$IP nexthop replace id 72 via 2001:db8:91::2 fdb" | |
| 515 | + log_test $? 2 "Replace non-FDB nexthop to FDB nexthop while in a group" | |
| 516 | + | |
| 497 | 517 | run_cmd "$IP link add name vx10 type vxlan id 1010 local 2001:db8:91::9 remote 2001:db8:91::10 dstport 4789 nolearning noudpcsum tos inherit ttl 100" |
| 498 | 518 | run_cmd "$BRIDGE fdb add 02:02:00:00:00:13 dev vx10 nhid 102 self" |
| 499 | 519 | log_test $? 0 "Fdb mac add with nexthop group" |
| @@ -547,15 +567,15 @@ ipv4_fdb_grp_fcnal() · 47 unmodified lines | ||
| 547 | 567 | log_test $? 0 "Get Fdb nexthop group by id" |
| 548 | 568 | |
| 549 | 569 | # fdb nexthop group can only contain fdb nexthops |
| 550 | − run_cmd "$IP nexthop add id 14 via 172.16.1.2" | |
| 551 | − run_cmd "$IP nexthop add id 15 via 172.16.1.3" | |
| 570 | + run_cmd "$IP nexthop add id 14 via 172.16.1.2 dev veth1" | |
| 571 | + run_cmd "$IP nexthop add id 15 via 172.16.1.3 dev veth1" | |
| 552 | 572 | run_cmd "$IP nexthop add id 103 group 14/15 fdb" |
| 553 | 573 | log_test $? 2 "Fdb Nexthop group with non-fdb nexthops" |
| 554 | 574 | |
| 555 | 575 | # Non fdb nexthop group can not contain fdb nexthops |
| 556 | 576 | run_cmd "$IP nexthop add id 16 via 172.16.1.2 fdb" |
| 557 | 577 | run_cmd "$IP nexthop add id 17 via 172.16.1.3 fdb" |
| 558 | − run_cmd "$IP nexthop add id 104 group 14/15" | |
| 578 | + run_cmd "$IP nexthop add id 104 group 16/17" | |
| 559 | 579 | log_test $? 2 "Non-Fdb Nexthop group with fdb nexthops" |
| 560 | 580 | |
| 561 | 581 | # fdb nexthop cannot have blackhole |
| @@ -574,6 +594,26 @@ ipv4_fdb_grp_fcnal() · 12 unmodified lines | ||
| 574 | 594 | run_cmd "$IP nexthop add id 17 encap mpls 101 via 172.16.1.2 dev veth1 fdb" |
| 575 | 595 | log_test $? 2 "Fdb Nexthop with encap" |
| 576 | 596 | |
| 597 | + # Replace FDB nexthop to non-FDB and vice versa | |
| 598 | + run_cmd "$IP nexthop add id 18 via 172.16.1.2 fdb" | |
| 599 | + run_cmd "$IP nexthop replace id 18 via 172.16.1.2 dev veth1" | |
| 600 | + log_test $? 0 "Replace FDB nexthop to non-FDB nexthop" | |
| 601 | + run_cmd "$IP nexthop replace id 18 via 172.16.1.2 fdb" | |
| 602 | + log_test $? 0 "Replace non-FDB nexthop to FDB nexthop" | |
| 603 | + | |
| 604 | + # Replace FDB nexthop address while in a group | |
| 605 | + run_cmd "$IP nexthop add id 19 group 18 fdb" | |
| 606 | + run_cmd "$IP nexthop replace id 18 via 172.16.1.3 fdb" | |
| 607 | + log_test $? 0 "Replace FDB nexthop address while in a group" | |
| 608 | + | |
| 609 | + # Cannot replace FDB nexthop to non-FDB and vice versa while in a group | |
| 610 | + run_cmd "$IP nexthop replace id 18 via 172.16.1.2 dev veth1" | |
| 611 | + log_test $? 2 "Replace FDB nexthop to non-FDB nexthop while in a group" | |
| 612 | + run_cmd "$IP nexthop add id 20 via 172.16.1.2 dev veth1" | |
| 613 | + run_cmd "$IP nexthop add id 21 group 20" | |
| 614 | + run_cmd "$IP nexthop replace id 20 via 172.16.1.2 fdb" | |
| 615 | + log_test $? 2 "Replace non-FDB nexthop to FDB nexthop while in a group" | |
| 616 | + | |
| 577 | 617 | run_cmd "$IP link add name vx10 type vxlan id 1010 local 10.0.0.1 remote 10.0.0.2 dstport 4789 nolearning noudpcsum tos inherit ttl 100" |
| 578 | 618 | run_cmd "$BRIDGE fdb add 02:02:00:00:00:13 dev vx10 nhid 102 self" |
| 579 | 619 | log_test $? 0 "Fdb mac add with nexthop group" |
| @@ -582,7 +622,7 @@ ipv4_fdb_grp_fcnal() · 2 unmodified lines | ||
| 582 | 622 | run_cmd "$BRIDGE fdb add 02:02:00:00:00:14 dev vx10 nhid 12 self" |
| 583 | 623 | log_test $? 255 "Fdb mac add with nexthop" |
| 584 | 624 | |
| 585 | − run_cmd "$IP ro add 172.16.0.0/22 nhid 15" | |
| 625 | + run_cmd "$IP ro add 172.16.0.0/22 nhid 16" | |
| 586 | 626 | log_test $? 2 "Route add with fdb nexthop" |
| 587 | 627 | |
| 588 | 628 | run_cmd "$IP ro add 172.16.0.0/22 nhid 103" |