Quick follow up, nothing super urgent here. Main reason I'm sending

this out is because the IPsec and Bluetooth PRs did not make it
 yesterday. I don't want to have to send you all of this + whatever
 comes next week, for rc7. The fixes under "Previous releases -
 regressions" are for real user-reported regressions from v7.0.
 
 Previous releases - regressions:
 
  - Revert "ipv6: preserve insertion order for same-scope addresses"
 
  - xfrm: move policy_bydst RCU sync, a fix which added a sync RCU
    on netns exit got backported to stable and was causing serious
    accumulation of dying netns's for real workloads
 
  - pcs-mtk-lynxi: fix bpi-r3 serdes configuration
 
 Previous releases - always broken:
 
  - usual grab bag of race, locking and leak fixes for Bluetooth
 
  - handful of page handling fixes for IPsec
 
 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmoZ+wAACgkQMUZtbf5S
 IrtXJQ/9Gwf702wvkRaeLdqrwQ/qLsvDfx5s+3ALIE0Xsm4z9g7V0XKrZ0cfiI1h
 aWGX8HugXEQuy9QvlFt09tgGEd76159g2WdlsBbh1raqiJRUw4GJKXYvwCmBZxsT
 o8bwfVTQ8CVmUTCKhYrpzJKroT6jR8dKHIrkRn5ZyBOBPMOhK8rnDs1OdseW5haI
 b/EkQrzzvTxd7/dJETIJszMQh/nbS5XIlKpQ+f7dfzR1gtO2GOJ24VWqrimonRTo
 qvMwyt+ca2axv7Af796I8mz7X9rqLjWVWzY2uSpd7Y5zITyQwHNbeNvxzr2Ivi4g
 2BcIi+ZHeeRbgQ9EL+rzapTnnIPIw0APPXnp5NnnNDj0RRG3G6PzulW9SmcdsmGD
 o6E7axSZPQT/KnCw1/N7uMfB9cPzgb1i0h8rbE6tCvtkDtJwECtey7Dc7RU9zLqP
 e0jWDv99+MyEqGPcu2LAg2IWLfsuQiV4priy4mM1NgOTQVgS1yw7+x0GiTqiClJ0
 GcOCTOdvYKlmzhLzsLo4I+AcKZq2uJi8wNXMUEP5pmuYByVeF5j+MmoFpQspzx+L
 gdUh9IctAjd47oX/uNaRtocOriU+JJEApToE9WekMb0XYd5Qx1jnt3WqB9ZFuDf4
 smjUirtAWYcT3d4SXR4wGzB5WEa8TITH07A7sa8noozzNmQRu1E=
 =ttPc
 -----END PGP SIGNATURE-----

Merge tag 'net-7.1-rc6-2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Pull more networking fixes from Jakub Kicinski:
 "Quick follow up, nothing super urgent here. Main reason I'm sending
  this out is because the IPsec and Bluetooth PRs did not make it
  yesterday. I don't want to have to send you all of this + whatever
  comes next week, for rc7. The fixes under "Previous releases -
  regressions" are for real user-reported regressions from v7.0.

  Previous releases - regressions:

   - Revert "ipv6: preserve insertion order for same-scope addresses"

   - xfrm: move policy_bydst RCU sync, a fix which added a sync RCU on
     netns exit got backported to stable and was causing serious
     accumulation of dying netns's for real workloads

   - pcs-mtk-lynxi: fix bpi-r3 serdes configuration

  Previous releases - always broken:

   - usual grab bag of race, locking and leak fixes for Bluetooth

   - handful of page handling fixes for IPsec"

* tag 'net-7.1-rc6-2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (36 commits)
  wireguard: send: append trailer after expanding head
  Revert "ipv6: preserve insertion order for same-scope addresses"
  net: skbuff: fix pskb_carve leaking zcopy pages
  ipv6: fix possible infinite loop in fib6_select_path()
  ipv6: fix possible infinite loop in rt6_fill_node()
  bpf: sockmap: fix tail fragment offset in bpf_msg_push_data
  vsock/virtio: bind uarg before filling zerocopy skb
  Revert "esp: fix page frag reference leak on skb_to_sgvec failure"
  net: pcs: pcs-mtk-lynxi: fix bpi-r3 serdes configuration
  sctp: fix race between sctp_wait_for_connect and peeloff
  net: mana: Skip redundant detach on already-detached port
  net: mana: Add NULL guards in teardown path to prevent panic on attach failure
  Bluetooth: hci_sync: Reset device counters in hci_dev_close_sync()
  Bluetooth: hci_sync: Set HCI_CMD_DRAIN_WORKQUEUE during device close
  Bluetooth: hci_core: Rework hci_dev_do_reset() to use hci_sync functions
  Bluetooth: ISO: serialize iso_sock_clear_timer with socket lock
  Bluetooth: ISO: fix UAF in iso_recv_frame
  Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_conn_rsp
  Bluetooth: l2cap: clear chan->ident on ECRED reconfiguration success
  Bluetooth: hci_qca: Use 100 ms SSR delay for rampatch and NVM loading
  ...
master
Linus Torvalds 2026-05-29 15:46:40 -07:00
commit f3be0c984e
32 changed files with 273 additions and 154 deletions

View File

@ -3540,7 +3540,13 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
"firmware rome 0x%x build 0x%x", "firmware rome 0x%x build 0x%x",
rver_rom, rver_patch, ver_rom, ver_patch); rver_rom, rver_patch, ver_rom, ver_patch);
if (rver_rom != ver_rom || rver_patch <= ver_patch) { /* Allow rampatch when the patch version equals the firmware version.
* A firmware download may be aborted by a transient USB error (e.g.
* disconnect) after the controller updates version info but before
* completion.
* Allowing equal versions enables re-flashing during recovery.
*/
if (rver_rom != ver_rom || rver_patch < ver_patch) {
bt_dev_err(hdev, "rampatch file version did not match with firmware"); bt_dev_err(hdev, "rampatch file version did not match with firmware");
err = -EINVAL; err = -EINVAL;
goto done; goto done;

View File

@ -1680,8 +1680,8 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code)
mod_timer(&qca->tx_idle_timer, jiffies + mod_timer(&qca->tx_idle_timer, jiffies +
msecs_to_jiffies(qca->tx_idle_delay)); msecs_to_jiffies(qca->tx_idle_delay));
/* Controller reset completion time is 50ms */ /* Wait for the controller to load the rampatch and NVM. */
msleep(50); msleep(100);
clear_bit(QCA_SSR_TRIGGERED, &qca->flags); clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
clear_bit(QCA_IBS_DISABLED, &qca->flags); clear_bit(QCA_IBS_DISABLED, &qca->flags);

View File

@ -1727,6 +1727,9 @@ static void mana_fence_rqs(struct mana_port_context *apc)
struct mana_rxq *rxq; struct mana_rxq *rxq;
int err; int err;
if (!apc->rxqs)
return;
for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) {
rxq = apc->rxqs[rxq_idx]; rxq = apc->rxqs[rxq_idx];
err = mana_fence_rq(apc, rxq); err = mana_fence_rq(apc, rxq);
@ -2858,6 +2861,8 @@ static void mana_destroy_vport(struct mana_port_context *apc)
struct mana_rxq *rxq; struct mana_rxq *rxq;
u32 rxq_idx; u32 rxq_idx;
if (apc->rxqs) {
for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) {
rxq = apc->rxqs[rxq_idx]; rxq = apc->rxqs[rxq_idx];
if (!rxq) if (!rxq)
@ -2866,6 +2871,7 @@ static void mana_destroy_vport(struct mana_port_context *apc)
mana_destroy_rxq(apc, rxq, true); mana_destroy_rxq(apc, rxq, true);
apc->rxqs[rxq_idx] = NULL; apc->rxqs[rxq_idx] = NULL;
} }
}
mana_destroy_txq(apc); mana_destroy_txq(apc);
mana_uncfg_vport(apc); mana_uncfg_vport(apc);
@ -3269,6 +3275,7 @@ static int mana_dealloc_queues(struct net_device *ndev)
if (apc->port_is_up) if (apc->port_is_up)
return -EINVAL; return -EINVAL;
if (apc->rxqs)
mana_chn_setxdp(apc, NULL); mana_chn_setxdp(apc, NULL);
if (gd->gdma_context->is_pf && !apc->ac->bm_hostmode) if (gd->gdma_context->is_pf && !apc->ac->bm_hostmode)
@ -3287,6 +3294,7 @@ static int mana_dealloc_queues(struct net_device *ndev)
* number of queues. * number of queues.
*/ */
if (apc->tx_qp) {
for (i = 0; i < apc->num_queues; i++) { for (i = 0; i < apc->num_queues; i++) {
txq = &apc->tx_qp[i].txq; txq = &apc->tx_qp[i].txq;
tsleep = 1000; tsleep = 1000;
@ -3296,10 +3304,12 @@ static int mana_dealloc_queues(struct net_device *ndev)
tsleep <<= 1; tsleep <<= 1;
} }
if (atomic_read(&txq->pending_sends)) { if (atomic_read(&txq->pending_sends)) {
err = pcie_flr(to_pci_dev(gd->gdma_context->dev)); err =
pcie_flr(to_pci_dev(gd->gdma_context->dev));
if (err) { if (err) {
netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n", netdev_err(ndev, "flr failed %d with %d pkts pending in txq %u\n",
err, atomic_read(&txq->pending_sends), err,
atomic_read(&txq->pending_sends),
txq->gdma_txq_id); txq->gdma_txq_id);
} }
break; break;
@ -3314,6 +3324,8 @@ static int mana_dealloc_queues(struct net_device *ndev)
} }
atomic_set(&txq->pending_sends, 0); atomic_set(&txq->pending_sends, 0);
} }
}
/* We're 100% sure the queues can no longer be woken up, because /* We're 100% sure the queues can no longer be woken up, because
* we're sure now mana_poll_tx_cq() can't be running. * we're sure now mana_poll_tx_cq() can't be running.
*/ */
@ -3338,6 +3350,12 @@ int mana_detach(struct net_device *ndev, bool from_close)
ASSERT_RTNL(); ASSERT_RTNL();
/* If already detached (indicates detach succeeded but attach failed
* previously). Now skip mana detach and just retry mana_attach.
*/
if (!from_close && !netif_device_present(ndev))
return 0;
apc->port_st_save = apc->port_is_up; apc->port_st_save = apc->port_is_up;
apc->port_is_up = false; apc->port_is_up = false;

View File

@ -129,6 +129,9 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
unsigned int val = 0; unsigned int val = 0;
int ret; int ret;
if (!fwnode)
return 0;
if (fwnode_property_read_bool(fwnode, "mediatek,pnswap")) if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
default_pol = PHY_POL_INVERT; default_pol = PHY_POL_INVERT;

View File

@ -177,16 +177,6 @@ static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
trailer_len = padding_len + noise_encrypted_len(0); trailer_len = padding_len + noise_encrypted_len(0);
plaintext_len = skb->len + padding_len; plaintext_len = skb->len + padding_len;
/* Expand data section to have room for padding and auth tag. */
num_frags = skb_cow_data(skb, trailer_len, &trailer);
if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg)))
return false;
/* Set the padding to zeros, and make sure it and the auth tag are part
* of the skb.
*/
memset(skb_tail_pointer(trailer), 0, padding_len);
/* Expand head section to have room for our header and the network /* Expand head section to have room for our header and the network
* stack's headers. * stack's headers.
*/ */
@ -198,6 +188,16 @@ static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
skb_checksum_help(skb))) skb_checksum_help(skb)))
return false; return false;
/* Expand data section to have room for padding and auth tag. */
num_frags = skb_cow_data(skb, trailer_len, &trailer);
if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg)))
return false;
/* Set the padding to zeros, and make sure it and the auth tag are part
* of the skb.
*/
memset(skb_tail_pointer(trailer), 0, padding_len);
/* Only after checksumming can we safely add on the padding at the end /* Only after checksumming can we safely add on the padding at the end
* and the header. * and the header.
*/ */

View File

@ -715,6 +715,7 @@ struct xfrm_mgr {
const struct xfrm_migrate *m, const struct xfrm_migrate *m,
int num_bundles, int num_bundles,
const struct xfrm_kmaddress *k, const struct xfrm_kmaddress *k,
struct net *net,
const struct xfrm_encap_tmpl *encap); const struct xfrm_encap_tmpl *encap);
bool (*is_alive)(const struct km_event *c); bool (*is_alive)(const struct km_event *c);
}; };
@ -1891,7 +1892,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
#ifdef CONFIG_XFRM_MIGRATE #ifdef CONFIG_XFRM_MIGRATE
int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_bundles, const struct xfrm_migrate *m, int num_bundles,
const struct xfrm_kmaddress *k, const struct xfrm_kmaddress *k, struct net *net,
const struct xfrm_encap_tmpl *encap); const struct xfrm_encap_tmpl *encap);
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net, struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
u32 if_id); u32 if_id);

View File

@ -486,6 +486,8 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
int ret; int ret;
local_skb = skb_clone(skb, GFP_ATOMIC); local_skb = skb_clone(skb, GFP_ATOMIC);
if (!local_skb)
continue;
BT_DBG("xmit %s to %pMR type %u IP %pI6c chan %p", BT_DBG("xmit %s to %pMR type %u IP %pI6c chan %p",
netdev->name, netdev->name,

View File

@ -870,8 +870,10 @@ static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn)
d->big_sync_term = true; d->big_sync_term = true;
} }
if (!d->pa_sync_term && !d->big_sync_term) if (!d->pa_sync_term && !d->big_sync_term) {
kfree(d);
return 0; return 0;
}
ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d, ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
terminate_big_destroy); terminate_big_destroy);

View File

@ -539,46 +539,9 @@ static int hci_dev_do_reset(struct hci_dev *hdev)
hci_req_sync_lock(hdev); hci_req_sync_lock(hdev);
/* Drop queues */ ret = hci_dev_close_sync(hdev);
skb_queue_purge(&hdev->rx_q); if (!ret)
skb_queue_purge(&hdev->cmd_q); ret = hci_dev_open_sync(hdev);
/* Cancel these to avoid queueing non-chained pending work */
hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
/* Wait for
*
* if (!hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
* queue_delayed_work(&hdev->{cmd,ncmd}_timer)
*
* inside RCU section to see the flag or complete scheduling.
*/
synchronize_rcu();
/* Explicitly cancel works in case scheduled after setting the flag. */
cancel_delayed_work(&hdev->cmd_timer);
cancel_delayed_work(&hdev->ncmd_timer);
/* Avoid potential lockdep warnings from the *_flush() calls by
* ensuring the workqueue is empty up front.
*/
drain_workqueue(hdev->workqueue);
hci_dev_lock(hdev);
hci_inquiry_cache_flush(hdev);
hci_conn_hash_flush(hdev);
hci_dev_unlock(hdev);
if (hdev->flush)
hdev->flush(hdev);
hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
atomic_set(&hdev->cmd_cnt, 1);
hdev->acl_cnt = 0;
hdev->sco_cnt = 0;
hdev->le_cnt = 0;
hdev->iso_cnt = 0;
ret = hci_reset_sync(hdev);
hci_req_sync_unlock(hdev); hci_req_sync_unlock(hdev);
return ret; return ret;

View File

@ -5301,6 +5301,12 @@ int hci_dev_close_sync(struct hci_dev *hdev)
bt_dev_dbg(hdev, ""); bt_dev_dbg(hdev, "");
/* Set HCI_DRAIN_WORKQUEUE flag to prevent queuing work during
* reset/close. See hci_cmd_work() and handle_cmd_cnt_and_timer().
*/
hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
synchronize_rcu();
if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) { if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
disable_delayed_work(&hdev->power_off); disable_delayed_work(&hdev->power_off);
disable_delayed_work(&hdev->ncmd_timer); disable_delayed_work(&hdev->ncmd_timer);
@ -5324,6 +5330,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
cancel_delayed_work_sync(&hdev->cmd_timer); cancel_delayed_work_sync(&hdev->cmd_timer);
hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
return err; return err;
} }
@ -5386,6 +5393,10 @@ int hci_dev_close_sync(struct hci_dev *hdev)
/* Reset device */ /* Reset device */
skb_queue_purge(&hdev->cmd_q); skb_queue_purge(&hdev->cmd_q);
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
hdev->acl_cnt = 0;
hdev->sco_cnt = 0;
hdev->le_cnt = 0;
hdev->iso_cnt = 0;
if (hci_test_quirk(hdev, HCI_QUIRK_RESET_ON_CLOSE) && if (hci_test_quirk(hdev, HCI_QUIRK_RESET_ON_CLOSE) &&
!auto_off && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { !auto_off && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
set_bit(HCI_INIT, &hdev->flags); set_bit(HCI_INIT, &hdev->flags);
@ -5423,6 +5434,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
/* Clear flags */ /* Clear flags */
hdev->flags &= BIT(HCI_RAW); hdev->flags &= BIT(HCI_RAW);
hci_dev_clear_volatile_flags(hdev); hci_dev_clear_volatile_flags(hdev);
hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
memset(hdev->eir, 0, sizeof(hdev->eir)); memset(hdev->eir, 0, sizeof(hdev->eir));
memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
@ -6699,6 +6711,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev)
DEFINE_FLEX(struct hci_cp_le_create_cis, cmd, cis, num_cis, 0x1f); DEFINE_FLEX(struct hci_cp_le_create_cis, cmd, cis, num_cis, 0x1f);
size_t aux_num_cis = 0; size_t aux_num_cis = 0;
struct hci_conn *conn; struct hci_conn *conn;
u16 timeout = 0;
u8 cig = BT_ISO_QOS_CIG_UNSET; u8 cig = BT_ISO_QOS_CIG_UNSET;
/* The spec allows only one pending LE Create CIS command at a time. If /* The spec allows only one pending LE Create CIS command at a time. If
@ -6769,6 +6782,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev)
set_bit(HCI_CONN_CREATE_CIS, &conn->flags); set_bit(HCI_CONN_CREATE_CIS, &conn->flags);
cis->acl_handle = cpu_to_le16(conn->parent->handle); cis->acl_handle = cpu_to_le16(conn->parent->handle);
cis->cis_handle = cpu_to_le16(conn->handle); cis->cis_handle = cpu_to_le16(conn->handle);
timeout = conn->conn_timeout;
aux_num_cis++; aux_num_cis++;
if (aux_num_cis >= cmd->num_cis) if (aux_num_cis >= cmd->num_cis)
@ -6788,7 +6802,7 @@ done:
return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CREATE_CIS, return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CREATE_CIS,
struct_size(cmd, cis, cmd->num_cis), struct_size(cmd, cis, cmd->num_cis),
cmd, HCI_EVT_LE_CIS_ESTABLISHED, cmd, HCI_EVT_LE_CIS_ESTABLISHED,
conn->conn_timeout, NULL); timeout, NULL);
} }
int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle) int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle)

View File

@ -179,12 +179,21 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
{ {
struct input_dev *dev = session->input; struct input_dev *dev = session->input;
unsigned char *keys = session->keys; unsigned char *keys = session->keys;
unsigned char *udata = skb->data + 1; unsigned char *udata;
signed char *sdata = skb->data + 1; signed char *sdata;
int i, size = skb->len - 1; u8 *hdr;
int i;
switch (skb->data[0]) { hdr = skb_pull_data(skb, 1);
if (!hdr)
return;
switch (*hdr) {
case 0x01: /* Keyboard report */ case 0x01: /* Keyboard report */
udata = skb_pull_data(skb, 8);
if (!udata)
break;
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1); input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
@ -213,6 +222,10 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
break; break;
case 0x02: /* Mouse report */ case 0x02: /* Mouse report */
sdata = skb_pull_data(skb, 3);
if (!sdata)
break;
input_report_key(dev, BTN_LEFT, sdata[0] & 0x01); input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02); input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04); input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
@ -222,7 +235,7 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
input_report_rel(dev, REL_X, sdata[1]); input_report_rel(dev, REL_X, sdata[1]);
input_report_rel(dev, REL_Y, sdata[2]); input_report_rel(dev, REL_Y, sdata[2]);
if (size > 3) if (skb->len > 0)
input_report_rel(dev, REL_WHEEL, sdata[3]); input_report_rel(dev, REL_WHEEL, sdata[3]);
break; break;
} }

View File

@ -564,7 +564,7 @@ static void iso_recv_frame(struct iso_conn *conn, struct sk_buff *skb)
struct sock *sk; struct sock *sk;
iso_conn_lock(conn); iso_conn_lock(conn);
sk = conn->sk; sk = iso_sock_hold(conn);
iso_conn_unlock(conn); iso_conn_unlock(conn);
if (!sk) if (!sk)
@ -573,11 +573,15 @@ static void iso_recv_frame(struct iso_conn *conn, struct sk_buff *skb)
BT_DBG("sk %p len %d", sk, skb->len); BT_DBG("sk %p len %d", sk, skb->len);
if (sk->sk_state != BT_CONNECTED) if (sk->sk_state != BT_CONNECTED)
goto drop; goto drop_put;
if (!sock_queue_rcv_skb(sk, skb)) if (!sock_queue_rcv_skb(sk, skb)) {
sock_put(sk);
return; return;
}
drop_put:
sock_put(sk);
drop: drop:
kfree_skb(skb); kfree_skb(skb);
} }
@ -860,8 +864,8 @@ static void __iso_sock_close(struct sock *sk)
/* Must be called on unlocked socket. */ /* Must be called on unlocked socket. */
static void iso_sock_close(struct sock *sk) static void iso_sock_close(struct sock *sk)
{ {
iso_sock_clear_timer(sk);
lock_sock(sk); lock_sock(sk);
iso_sock_clear_timer(sk);
__iso_sock_close(sk); __iso_sock_close(sk);
release_sock(sk); release_sock(sk);
iso_sock_kill(sk); iso_sock_kill(sk);

View File

@ -411,8 +411,10 @@ static void l2cap_chan_timeout(struct work_struct *work)
BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
if (!conn) if (!conn) {
l2cap_chan_put(chan);
return; return;
}
mutex_lock(&conn->lock); mutex_lock(&conn->lock);
/* __set_chan_timer() calls l2cap_chan_hold(chan) while scheduling /* __set_chan_timer() calls l2cap_chan_hold(chan) while scheduling
@ -5260,6 +5262,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
cmd_len -= sizeof(*rsp); cmd_len -= sizeof(*rsp);
list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
struct l2cap_chan *orig;
u16 dcid; u16 dcid;
if (chan->ident != cmd->ident || if (chan->ident != cmd->ident ||
@ -5281,8 +5284,10 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
BT_DBG("dcid[%d] 0x%4.4x", i, dcid); BT_DBG("dcid[%d] 0x%4.4x", i, dcid);
orig = __l2cap_get_chan_by_dcid(conn, dcid);
/* Check if dcid is already in use */ /* Check if dcid is already in use */
if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) { if (dcid && orig) {
/* If a device receives a /* If a device receives a
* L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an
* already-assigned Destination CID, then both the * already-assigned Destination CID, then both the
@ -5291,10 +5296,24 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
*/ */
l2cap_chan_del(chan, ECONNREFUSED); l2cap_chan_del(chan, ECONNREFUSED);
l2cap_chan_unlock(chan); l2cap_chan_unlock(chan);
chan = __l2cap_get_chan_by_dcid(conn, dcid);
l2cap_chan_lock(chan); /* Check that the dcid channel mode is
l2cap_chan_del(chan, ECONNRESET); * L2CAP_MODE_EXT_FLOWCTL since this procedure is only
l2cap_chan_unlock(chan); * valid for that mode and shouldn't disconnect a dcid
* in other modes.
*/
if (orig->mode == L2CAP_MODE_EXT_FLOWCTL) {
l2cap_chan_lock(orig);
/* Disconnect the original channel as it may be
* considered connected since dcid has already
* been assigned; don't call l2cap_chan_close
* directly since that could lead to
* l2cap_chan_del and then removing the channel
* from the list while we're iterating over it.
*/
__set_chan_timer(orig, 0);
l2cap_chan_unlock(orig);
}
continue; continue;
} }
@ -5458,14 +5477,20 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
BT_DBG("result 0x%4.4x", result); BT_DBG("result 0x%4.4x", result);
if (!result) if (!result) {
list_for_each_entry(chan, &conn->chan_l, list) {
if (chan->ident == cmd->ident)
chan->ident = 0;
}
return 0; return 0;
}
list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
if (chan->ident != cmd->ident) if (chan->ident != cmd->ident)
continue; continue;
l2cap_chan_hold(chan); if (!l2cap_chan_hold_unless_zero(chan))
continue;
l2cap_chan_lock(chan); l2cap_chan_lock(chan);
l2cap_chan_del(chan, ECONNRESET); l2cap_chan_del(chan, ECONNRESET);

View File

@ -1499,6 +1499,10 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
* pin it (hold_unless_zero() additionally skips a chan already past * pin it (hold_unless_zero() additionally skips a chan already past
* its last reference). We then drop the sk lock before taking * its last reference). We then drop the sk lock before taking
* chan->lock, so sk and chan locks are never held together. * chan->lock, so sk and chan locks are never held together.
*
* Since we cannot call l2cap_chan_close() without conn->lock,
* schedule l2cap_chan_timeout to close the channel; it already
* acquires conn->lock -> chan->lock in the correct order.
*/ */
while ((sk = bt_accept_dequeue(parent, NULL))) { while ((sk = bt_accept_dequeue(parent, NULL))) {
struct l2cap_chan *chan; struct l2cap_chan *chan;
@ -1516,14 +1520,12 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
state_to_string(chan->state)); state_to_string(chan->state));
l2cap_chan_lock(chan); l2cap_chan_lock(chan);
__clear_chan_timer(chan); /* Since we cannot call l2cap_chan_close() without
l2cap_chan_close(chan, ECONNRESET); * conn->lock, schedule its timer to trigger the close
/* l2cap_conn_del() may already have killed this socket * and cleanup of this channel.
* (it sets SOCK_DEAD); skip the duplicate to avoid a
* double sock_put()/l2cap_chan_put().
*/ */
if (!sock_flag(sk, SOCK_DEAD)) if (chan->conn)
l2cap_sock_kill(sk); __set_chan_timer(chan, 0);
l2cap_chan_unlock(chan); l2cap_chan_unlock(chan);
l2cap_chan_put(chan); l2cap_chan_put(chan);

View File

@ -2869,7 +2869,7 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
psge->length = start - offset; psge->length = start - offset;
rsge.length -= psge->length; rsge.length -= psge->length;
rsge.offset += start; rsge.offset += start - offset;
sk_msg_iter_var_next(i); sk_msg_iter_var_next(i);
sg_unmark_end(psge); sg_unmark_end(psge);

View File

@ -6823,6 +6823,11 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,
skb_copy_from_linear_data_offset(skb, off, data, new_hlen); skb_copy_from_linear_data_offset(skb, off, data, new_hlen);
skb->len -= off; skb->len -= off;
/* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it
* while refcounting frags below.
*/
skb_zcopy_downgrade_managed(skb);
memcpy((struct skb_shared_info *)(data + size), memcpy((struct skb_shared_info *)(data + size),
skb_shinfo(skb), skb_shinfo(skb),
offsetof(struct skb_shared_info, offsetof(struct skb_shared_info,
@ -6936,6 +6941,11 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off,
return -ENOMEM; return -ENOMEM;
size = SKB_WITH_OVERHEAD(size); size = SKB_WITH_OVERHEAD(size);
/* Remove SKBFL_MANAGED_FRAG_REFS instead of trying to honour it
* while refcounting frags below.
*/
skb_zcopy_downgrade_managed(skb);
memcpy((struct skb_shared_info *)(data + size), memcpy((struct skb_shared_info *)(data + size),
skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0])); skb_shinfo(skb), offsetof(struct skb_shared_info, frags[0]));
if (skb_orphan_frags(skb, gfp_mask)) { if (skb_orphan_frags(skb, gfp_mask)) {

View File

@ -143,7 +143,7 @@ static void ah_output_done(void *data, int err)
} }
kfree(AH_SKB_CB(skb)->tmp); kfree(AH_SKB_CB(skb)->tmp);
xfrm_output_resume(skb->sk, skb, err); xfrm_output_resume(skb_to_full_sk(skb), skb, err);
} }
static int ah_output(struct xfrm_state *x, struct sk_buff *skb) static int ah_output(struct xfrm_state *x, struct sk_buff *skb)

View File

@ -419,8 +419,8 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
return err; return err;
} }
if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE || if (ALIGN(skb->data_len + tailen, L1_CACHE_BYTES) >
ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE) PAGE_SIZE)
goto cow; goto cow;
if (!skb_cloned(skb)) { if (!skb_cloned(skb)) {

View File

@ -1013,7 +1013,7 @@ ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)
list_for_each(p, &idev->addr_list) { list_for_each(p, &idev->addr_list) {
struct inet6_ifaddr *ifa struct inet6_ifaddr *ifa
= list_entry(p, struct inet6_ifaddr, if_list); = list_entry(p, struct inet6_ifaddr, if_list);
if (ifp_scope > ipv6_addr_src_scope(&ifa->addr)) if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr))
break; break;
} }

View File

@ -337,7 +337,7 @@ static void ah6_output_done(void *data, int err)
ah6_restore_hdrs(top_iph, iph_ext, extlen); ah6_restore_hdrs(top_iph, iph_ext, extlen);
kfree(AH_SKB_CB(skb)->tmp); kfree(AH_SKB_CB(skb)->tmp);
xfrm_output_resume(skb->sk, skb, err); xfrm_output_resume(skb_to_full_sk(skb), skb, err);
} }
static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)

View File

@ -448,8 +448,8 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
return err; return err;
} }
if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE || if (ALIGN(skb->data_len + tailen, L1_CACHE_BYTES) >
ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE) PAGE_SIZE)
goto cow; goto cow;
if (!skb_cloned(skb)) { if (!skb_cloned(skb)) {

View File

@ -481,6 +481,9 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
const struct fib6_nh *nh = sibling->fib6_nh; const struct fib6_nh *nh = sibling->fib6_nh;
int nh_upper_bound; int nh_upper_bound;
if (!READ_ONCE(first->fib6_nsiblings))
break;
nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound); nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound);
if (hash > nh_upper_bound) if (hash > nh_upper_bound)
continue; continue;
@ -5902,6 +5905,8 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
} }
if (!READ_ONCE(rt->fib6_nsiblings))
break;
} }
rcu_read_unlock(); rcu_read_unlock();

View File

@ -3564,7 +3564,7 @@ static int set_ipsecrequest(struct sk_buff *skb,
#ifdef CONFIG_NET_KEY_MIGRATE #ifdef CONFIG_NET_KEY_MIGRATE
static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_bundles, const struct xfrm_migrate *m, int num_bundles,
const struct xfrm_kmaddress *k, const struct xfrm_kmaddress *k, struct net *net,
const struct xfrm_encap_tmpl *encap) const struct xfrm_encap_tmpl *encap)
{ {
int i; int i;
@ -3669,7 +3669,7 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
} }
/* broadcast migrate message to sockets */ /* broadcast migrate message to sockets */
pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net); pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, net);
return 0; return 0;
@ -3680,7 +3680,7 @@ err:
#else #else
static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_bundles, const struct xfrm_migrate *m, int num_bundles,
const struct xfrm_kmaddress *k, const struct xfrm_kmaddress *k, struct net *net,
const struct xfrm_encap_tmpl *encap) const struct xfrm_encap_tmpl *encap)
{ {
return -ENOPROTOOPT; return -ENOPROTOOPT;

View File

@ -9403,6 +9403,8 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
release_sock(sk); release_sock(sk);
current_timeo = schedule_timeout(current_timeo); current_timeo = schedule_timeout(current_timeo);
lock_sock(sk); lock_sock(sk);
if (sk != asoc->base.sk)
goto do_error;
*timeo_p = current_timeo; *timeo_p = current_timeo;
} }

View File

@ -205,6 +205,7 @@ static u16 virtio_transport_get_type(struct sock *sk)
static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info, static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info,
size_t payload_len, size_t payload_len,
bool zcopy, bool zcopy,
struct ubuf_info *uarg,
u32 src_cid, u32 src_cid,
u32 src_port, u32 src_port,
u32 dst_cid, u32 dst_cid,
@ -245,6 +246,12 @@ static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *
if (info->msg && payload_len > 0) { if (info->msg && payload_len > 0) {
int err; int err;
/* Bind the zerocopy lifetime before filling frags so error
* rollback frees managed fixed-buffer pages through
* the uarg-aware path.
*/
skb_zcopy_set(skb, uarg, NULL);
err = virtio_transport_fill_skb(skb, info, payload_len, zcopy); err = virtio_transport_fill_skb(skb, info, payload_len, zcopy);
if (err) if (err)
goto out; goto out;
@ -364,6 +371,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
skb_len = min(max_skb_len, rest_len); skb_len = min(max_skb_len, rest_len);
skb = virtio_transport_alloc_skb(info, skb_len, can_zcopy, skb = virtio_transport_alloc_skb(info, skb_len, can_zcopy,
uarg,
src_cid, src_port, src_cid, src_port,
dst_cid, dst_port); dst_cid, dst_port);
if (!skb) { if (!skb) {
@ -371,8 +379,6 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
break; break;
} }
skb_zcopy_set(skb, uarg, NULL);
virtio_transport_inc_tx_pkt(vvs, skb); virtio_transport_inc_tx_pkt(vvs, skb);
ret = t_ops->send_pkt(skb, info->net); ret = t_ops->send_pkt(skb, info->net);
@ -1183,7 +1189,7 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
if (!t) if (!t)
return -ENOTCONN; return -ENOTCONN;
reply = virtio_transport_alloc_skb(&info, 0, false, reply = virtio_transport_alloc_skb(&info, 0, false, NULL,
le64_to_cpu(hdr->dst_cid), le64_to_cpu(hdr->dst_cid),
le32_to_cpu(hdr->dst_port), le32_to_cpu(hdr->dst_port),
le64_to_cpu(hdr->src_cid), le64_to_cpu(hdr->src_cid),

View File

@ -797,9 +797,12 @@ static void xfrm_trans_reinject(struct work_struct *work)
spin_unlock_bh(&trans->queue_lock); spin_unlock_bh(&trans->queue_lock);
local_bh_disable(); local_bh_disable();
while ((skb = __skb_dequeue(&queue))) while ((skb = __skb_dequeue(&queue))) {
XFRM_TRANS_SKB_CB(skb)->finish(XFRM_TRANS_SKB_CB(skb)->net, struct net *net = XFRM_TRANS_SKB_CB(skb)->net;
NULL, skb);
XFRM_TRANS_SKB_CB(skb)->finish(net, NULL, skb);
put_net(net);
}
local_bh_enable(); local_bh_enable();
} }
@ -808,6 +811,7 @@ int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb,
struct sk_buff *)) struct sk_buff *))
{ {
struct xfrm_trans_tasklet *trans; struct xfrm_trans_tasklet *trans;
struct net *hold_net;
trans = this_cpu_ptr(&xfrm_trans_tasklet); trans = this_cpu_ptr(&xfrm_trans_tasklet);
@ -816,8 +820,12 @@ int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb,
BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb)); BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb));
hold_net = maybe_get_net(net);
if (!hold_net)
return -ENODEV;
XFRM_TRANS_SKB_CB(skb)->finish = finish; XFRM_TRANS_SKB_CB(skb)->finish = finish;
XFRM_TRANS_SKB_CB(skb)->net = net; XFRM_TRANS_SKB_CB(skb)->net = hold_net;
spin_lock_bh(&trans->queue_lock); spin_lock_bh(&trans->queue_lock);
__skb_queue_tail(&trans->queue, skb); __skb_queue_tail(&trans->queue, skb);
spin_unlock_bh(&trans->queue_lock); spin_unlock_bh(&trans->queue_lock);

View File

@ -51,11 +51,15 @@ static int ipcomp_post_acomp(struct sk_buff *skb, int err, int hlen)
struct scatterlist *dsg; struct scatterlist *dsg;
int len, dlen; int len, dlen;
if (unlikely(err)) if (unlikely(!req))
goto out_free_req; return err;
extra = acomp_request_extra(req); extra = acomp_request_extra(req);
dsg = extra->sg; dsg = extra->sg;
if (unlikely(err))
goto out_free_req;
dlen = req->dlen; dlen = req->dlen;
pskb_trim_unique(skb, 0); pskb_trim_unique(skb, 0);
@ -84,10 +88,10 @@ static int ipcomp_post_acomp(struct sk_buff *skb, int err, int hlen)
skb_shinfo(skb)->nr_frags++; skb_shinfo(skb)->nr_frags++;
} while ((dlen -= len)); } while ((dlen -= len));
for (; dsg; dsg = sg_next(dsg)) out_free_req:
for (; dsg && sg_page(dsg); dsg = sg_next(dsg))
__free_page(sg_page(dsg)); __free_page(sg_page(dsg));
out_free_req:
acomp_request_free(req); acomp_request_free(req);
return err; return err;
} }

View File

@ -2650,6 +2650,7 @@ static void __iptfs_init_state(struct xfrm_state *x,
x->props.enc_hdr_len = sizeof(struct ip_iptfs_hdr); x->props.enc_hdr_len = sizeof(struct ip_iptfs_hdr);
/* Always keep a module reference when x->mode_data is set */ /* Always keep a module reference when x->mode_data is set */
if (x->mode_data != xtfs)
__module_get(x->mode_cbs->owner); __module_get(x->mode_cbs->owner);
x->mode_data = xtfs; x->mode_data = xtfs;
@ -2658,22 +2659,39 @@ static void __iptfs_init_state(struct xfrm_state *x,
static int iptfs_clone_state(struct xfrm_state *x, struct xfrm_state *orig) static int iptfs_clone_state(struct xfrm_state *x, struct xfrm_state *orig)
{ {
struct skb_wseq *w_saved = NULL;
struct xfrm_iptfs_data *xtfs; struct xfrm_iptfs_data *xtfs;
xtfs = kmemdup(orig->mode_data, sizeof(*xtfs), GFP_KERNEL); xtfs = kmemdup(orig->mode_data, sizeof(*xtfs), GFP_KERNEL);
if (!xtfs) if (!xtfs)
return -ENOMEM; return -ENOMEM;
xtfs->ra_newskb = NULL;
if (xtfs->cfg.reorder_win_size) { if (xtfs->cfg.reorder_win_size) {
xtfs->w_saved = kzalloc_objs(*xtfs->w_saved, w_saved = kzalloc_objs(*w_saved, xtfs->cfg.reorder_win_size);
xtfs->cfg.reorder_win_size); if (!w_saved) {
if (!xtfs->w_saved) {
kfree_sensitive(xtfs); kfree_sensitive(xtfs);
return -ENOMEM; return -ENOMEM;
} }
} }
xtfs->w_saved = w_saved;
__skb_queue_head_init(&xtfs->queue);
xtfs->queue_size = 0;
hrtimer_setup(&xtfs->iptfs_timer, iptfs_delay_timer, CLOCK_MONOTONIC,
IPTFS_HRTIMER_MODE);
spin_lock_init(&xtfs->drop_lock);
hrtimer_setup(&xtfs->drop_timer, iptfs_drop_timer, CLOCK_MONOTONIC,
IPTFS_HRTIMER_MODE);
xtfs->w_seq_set = false;
xtfs->w_wantseq = 0;
xtfs->w_savedlen = 0;
xtfs->ra_newskb = NULL;
xtfs->ra_wantseq = 0;
xtfs->ra_runtlen = 0;
__module_get(x->mode_cbs->owner);
x->mode_data = xtfs; x->mode_data = xtfs;
xtfs->x = x; xtfs->x = x;

View File

@ -4276,21 +4276,21 @@ out_byidx:
return -ENOMEM; return -ENOMEM;
} }
static void xfrm_policy_fini(struct net *net) static void __net_exit xfrm_net_pre_exit(struct net *net)
{ {
struct xfrm_pol_inexact_bin *b, *t;
unsigned int sz;
int dir;
disable_work_sync(&net->xfrm.policy_hthresh.work); disable_work_sync(&net->xfrm.policy_hthresh.work);
flush_work(&net->xfrm.policy_hash_work); flush_work(&net->xfrm.policy_hash_work);
#ifdef CONFIG_XFRM_SUB_POLICY #ifdef CONFIG_XFRM_SUB_POLICY
xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false); xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false);
#endif #endif
xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false); xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false);
}
synchronize_rcu(); static void xfrm_policy_fini(struct net *net)
{
struct xfrm_pol_inexact_bin *b, *t;
unsigned int sz;
int dir;
WARN_ON(!list_empty(&net->xfrm.policy_all)); WARN_ON(!list_empty(&net->xfrm.policy_all));
@ -4368,6 +4368,7 @@ static void __net_exit xfrm_net_exit(struct net *net)
static struct pernet_operations __net_initdata xfrm_net_ops = { static struct pernet_operations __net_initdata xfrm_net_ops = {
.init = xfrm_net_init, .init = xfrm_net_init,
.pre_exit = xfrm_net_pre_exit,
.exit = xfrm_net_exit, .exit = xfrm_net_exit,
}; };
@ -4703,7 +4704,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
} }
/* Stage 5 - announce */ /* Stage 5 - announce */
km_migrate(sel, dir, type, m, num_migrate, k, encap); km_migrate(sel, dir, type, m, num_migrate, k, net, encap);
xfrm_pol_put(pol); xfrm_pol_put(pol);

View File

@ -2837,7 +2837,7 @@ EXPORT_SYMBOL(km_policy_expired);
#ifdef CONFIG_XFRM_MIGRATE #ifdef CONFIG_XFRM_MIGRATE
int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_migrate, const struct xfrm_migrate *m, int num_migrate,
const struct xfrm_kmaddress *k, const struct xfrm_kmaddress *k, struct net *net,
const struct xfrm_encap_tmpl *encap) const struct xfrm_encap_tmpl *encap)
{ {
int err = -EINVAL; int err = -EINVAL;
@ -2848,7 +2848,7 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
list_for_each_entry_rcu(km, &xfrm_km_list, list) { list_for_each_entry_rcu(km, &xfrm_km_list, list) {
if (km->migrate) { if (km->migrate) {
ret = km->migrate(sel, dir, type, m, num_migrate, k, ret = km->migrate(sel, dir, type, m, num_migrate, k,
encap); net, encap);
if (!ret) if (!ret)
err = ret; err = ret;
} }
@ -3114,10 +3114,14 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
const struct xfrm_type *type = READ_ONCE(x->type); const struct xfrm_type *type = READ_ONCE(x->type);
struct crypto_aead *aead; struct crypto_aead *aead;
u32 blksize, net_adj = 0; u32 blksize, net_adj = 0;
u32 overhead, payload_mtu;
if (x->km.state != XFRM_STATE_VALID || if (x->km.state != XFRM_STATE_VALID ||
!type || type->proto != IPPROTO_ESP) !type || type->proto != IPPROTO_ESP) {
if (mtu <= x->props.header_len)
return 1;
return mtu - x->props.header_len; return mtu - x->props.header_len;
}
aead = x->data; aead = x->data;
blksize = ALIGN(crypto_aead_blocksize(aead), 4); blksize = ALIGN(crypto_aead_blocksize(aead), 4);
@ -3140,8 +3144,17 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
break; break;
} }
return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - overhead = x->props.header_len + crypto_aead_authsize(aead) + net_adj;
net_adj) & ~(blksize - 1)) + net_adj - 2; if (mtu <= overhead)
return 1;
payload_mtu = mtu - overhead;
payload_mtu &= ~(blksize - 1);
if (payload_mtu <= 2)
return 1;
return payload_mtu + net_adj - 2;
} }
EXPORT_SYMBOL_GPL(xfrm_state_mtu); EXPORT_SYMBOL_GPL(xfrm_state_mtu);

View File

@ -3271,10 +3271,9 @@ out_cancel:
static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_migrate, const struct xfrm_migrate *m, int num_migrate,
const struct xfrm_kmaddress *k, const struct xfrm_kmaddress *k, struct net *net,
const struct xfrm_encap_tmpl *encap) const struct xfrm_encap_tmpl *encap)
{ {
struct net *net = &init_net;
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
@ -3292,7 +3291,7 @@ static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
#else #else
static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_migrate, const struct xfrm_migrate *m, int num_migrate,
const struct xfrm_kmaddress *k, const struct xfrm_kmaddress *k, struct net *net,
const struct xfrm_encap_tmpl *encap) const struct xfrm_encap_tmpl *encap)
{ {
return -ENOPROTOOPT; return -ENOPROTOOPT;

View File

@ -273,8 +273,8 @@ setup()
ip -netns $ioam_node_beta link set ioam-veth-betaR name veth1 &>/dev/null ip -netns $ioam_node_beta link set ioam-veth-betaR name veth1 &>/dev/null
ip -netns $ioam_node_gamma link set ioam-veth-gamma name veth0 &>/dev/null ip -netns $ioam_node_gamma link set ioam-veth-gamma name veth0 &>/dev/null
ip -netns $ioam_node_alpha addr add 2001:db8:1::2/64 dev veth0 &>/dev/null
ip -netns $ioam_node_alpha addr add 2001:db8:1::50/64 dev veth0 &>/dev/null ip -netns $ioam_node_alpha addr add 2001:db8:1::50/64 dev veth0 &>/dev/null
ip -netns $ioam_node_alpha addr add 2001:db8:1::2/64 dev veth0 &>/dev/null
ip -netns $ioam_node_alpha link set veth0 up &>/dev/null ip -netns $ioam_node_alpha link set veth0 up &>/dev/null
ip -netns $ioam_node_alpha link set lo up &>/dev/null ip -netns $ioam_node_alpha link set lo up &>/dev/null
ip -netns $ioam_node_alpha route add 2001:db8:2::/64 \ ip -netns $ioam_node_alpha route add 2001:db8:2::/64 \