From fd567ac20cb0377ff466d3337e6e9ac5d0cb15e4 Mon Sep 17 00:00:00 2001 From: John Rutherford Date: Tue, 26 Nov 2019 13:52:55 +1100 Subject: [PATCH 01/20] tipc: fix link name length check In commit 4f07b80c9733 ("tipc: check msg->req data len in tipc_nl_compat_bearer_disable") the same patch code was copied into routines: tipc_nl_compat_bearer_disable(), tipc_nl_compat_link_stat_dump() and tipc_nl_compat_link_reset_stats(). The two link routine occurrences should have been modified to check the maximum link name length and not bearer name length. Fixes: 4f07b80c9733 ("tipc: check msg->reg data len in tipc_nl_compat_bearer_disable") Signed-off-by: John Rutherford Acked-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/netlink_compat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 17a529739f8d..0254bb7e418b 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -570,7 +570,7 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg, if (len <= 0) return -EINVAL; - len = min_t(int, len, TIPC_MAX_BEARER_NAME); + len = min_t(int, len, TIPC_MAX_LINK_NAME); if (!string_is_valid(name, len)) return -EINVAL; @@ -842,7 +842,7 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd, if (len <= 0) return -EINVAL; - len = min_t(int, len, TIPC_MAX_BEARER_NAME); + len = min_t(int, len, TIPC_MAX_LINK_NAME); if (!string_is_valid(name, len)) return -EINVAL; From ac71676c493f738ed04b0db9dc67aa03de7f2722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 25 Nov 2019 14:48:00 -0800 Subject: [PATCH 02/20] net: Fix a documentation bug wrt. ip_unprivileged_port_start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It cannot overlap with the local port range - ie. with autobind selectable ports - and not with reserved ports. Indeed 'ip_local_reserved_ports' isn't even a range, it's a (by default empty) set. Fixes: 4548b683b781 ("Introduce a sysctl that modifies the value of PROT_SOCK.") Signed-off-by: Maciej Żenczykowski Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 099a55bd1432..fd26788e8c96 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -904,8 +904,9 @@ ip_local_port_range - 2 INTEGERS Defines the local port range that is used by TCP and UDP to choose the local port. The first number is the first, the second the last local port number. - If possible, it is better these numbers have different parity. - (one even and one odd values) + If possible, it is better these numbers have different parity + (one even and one odd value). + Must be greater than or equal to ip_unprivileged_port_start. The default values are 32768 and 60999 respectively. ip_local_reserved_ports - list of comma separated ranges @@ -943,8 +944,8 @@ ip_unprivileged_port_start - INTEGER This is a per-namespace sysctl. It defines the first unprivileged port in the network namespace. Privileged ports require root or CAP_NET_BIND_SERVICE in order to bind to them. - To disable all privileged ports, set this to 0. It may not - overlap with the ip_local_reserved_ports range. + To disable all privileged ports, set this to 0. They must not + overlap with the ip_local_port_range. Default: 1024 From fb8223888e72eacd69948069f05c77a01e5a1b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 25 Nov 2019 15:09:37 -0800 Subject: [PATCH 03/20] net-sctp: replace some sock_net(sk) with just 'net' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It already existed in part of the function, but move it to a higher level and use it consistently throughout. Safe since sk is never written to. Signed-off-by: Maciej Żenczykowski Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- net/sctp/socket.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 83e4ca1fabda..e4c398db07a0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -8267,6 +8267,7 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr) struct sctp_sock *sp = sctp_sk(sk); bool reuse = (sk->sk_reuse || sp->reuse); struct sctp_bind_hashbucket *head; /* hash list */ + struct net *net = sock_net(sk); kuid_t uid = sock_i_uid(sk); struct sctp_bind_bucket *pp; unsigned short snum; @@ -8282,7 +8283,6 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr) /* Search for an available port. */ int low, high, remaining, index; unsigned int rover; - struct net *net = sock_net(sk); inet_get_local_port_range(net, &low, &high); remaining = (high - low) + 1; @@ -8294,12 +8294,12 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr) rover = low; if (inet_is_local_reserved_port(net, rover)) continue; - index = sctp_phashfn(sock_net(sk), rover); + index = sctp_phashfn(net, rover); head = &sctp_port_hashtable[index]; spin_lock(&head->lock); sctp_for_each_hentry(pp, &head->chain) if ((pp->port == rover) && - net_eq(sock_net(sk), pp->net)) + net_eq(net, pp->net)) goto next; break; next: @@ -8323,10 +8323,10 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr) * to the port number (snum) - we detect that with the * port iterator, pp being NULL. */ - head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)]; + head = &sctp_port_hashtable[sctp_phashfn(net, snum)]; spin_lock(&head->lock); sctp_for_each_hentry(pp, &head->chain) { - if ((pp->port == snum) && net_eq(pp->net, sock_net(sk))) + if ((pp->port == snum) && net_eq(pp->net, net)) goto pp_found; } } @@ -8382,7 +8382,7 @@ pp_found: pp_not_found: /* If there was a hash table miss, create a new port. */ ret = 1; - if (!pp && !(pp = sctp_bucket_create(head, sock_net(sk), snum))) + if (!pp && !(pp = sctp_bucket_create(head, net, snum))) goto fail_unlock; /* In either case (hit or miss), make sure fastreuse is 1 only From 070eca955c4af1248cb78a216463ff757a5dc511 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 25 Nov 2019 17:12:53 -0600 Subject: [PATCH 04/20] ibmvnic: Fix completion structure initialization Fix multiple calls to init_completion for device completion structures. Instead, initialize them during device probe and reinitialize them later as needed. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 0686ded7ad3a..e1ab2feeae53 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -176,7 +176,7 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, ltb->map_id = adapter->map_id; adapter->map_id++; - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); if (rc) { @@ -215,7 +215,7 @@ static int reset_long_term_buff(struct ibmvnic_adapter *adapter, memset(ltb->buff, 0, ltb->size); - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); if (rc) return rc; @@ -943,7 +943,7 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) if (adapter->vpd->buff) len = adapter->vpd->len; - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); crq.get_vpd_size.first = IBMVNIC_CRQ_CMD; crq.get_vpd_size.cmd = GET_VPD_SIZE; rc = ibmvnic_send_crq(adapter, &crq); @@ -1689,7 +1689,7 @@ static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr) crq.change_mac_addr.cmd = CHANGE_MAC_ADDR; ether_addr_copy(&crq.change_mac_addr.mac_addr[0], dev_addr); - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); rc = ibmvnic_send_crq(adapter, &crq); if (rc) { rc = -EIO; @@ -2316,7 +2316,7 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter) adapter->fallback.rx_entries = adapter->req_rx_add_entries_per_subcrq; adapter->fallback.tx_entries = adapter->req_tx_entries_per_subcrq; - init_completion(&adapter->reset_done); + reinit_completion(&adapter->reset_done); adapter->wait_for_reset = true; rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM); if (rc) @@ -2332,7 +2332,7 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter) adapter->desired.rx_entries = adapter->fallback.rx_entries; adapter->desired.tx_entries = adapter->fallback.tx_entries; - init_completion(&adapter->reset_done); + reinit_completion(&adapter->reset_done); adapter->wait_for_reset = true; rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM); if (rc) @@ -2603,7 +2603,7 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev, cpu_to_be32(sizeof(struct ibmvnic_statistics)); /* Wait for data to be written */ - init_completion(&adapter->stats_done); + reinit_completion(&adapter->stats_done); rc = ibmvnic_send_crq(adapter, &crq); if (rc) return; @@ -4408,7 +4408,7 @@ static int send_query_phys_parms(struct ibmvnic_adapter *adapter) memset(&crq, 0, sizeof(crq)); crq.query_phys_parms.first = IBMVNIC_CRQ_CMD; crq.query_phys_parms.cmd = QUERY_PHYS_PARMS; - init_completion(&adapter->fw_done); + reinit_completion(&adapter->fw_done); rc = ibmvnic_send_crq(adapter, &crq); if (rc) return rc; @@ -4960,6 +4960,9 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) INIT_LIST_HEAD(&adapter->rwi_list); spin_lock_init(&adapter->rwi_lock); init_completion(&adapter->init_done); + init_completion(&adapter->fw_done); + init_completion(&adapter->reset_done); + init_completion(&adapter->stats_done); clear_bit(0, &adapter->resetting); do { From 2147e3d09e9ba6edc54b1b4bb7d8fc3cca96776b Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 25 Nov 2019 17:12:54 -0600 Subject: [PATCH 05/20] ibmvnic: Terminate waiting device threads after loss of service If we receive a notification that the device has been deactivated or removed, force a completion of all waiting threads. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index e1ab2feeae53..dc1b88116330 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -4505,6 +4505,15 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, case IBMVNIC_CRQ_XPORT_EVENT: netif_carrier_off(netdev); adapter->crq.active = false; + /* terminate any thread waiting for a response + * from the device + */ + if (!completion_done(&adapter->fw_done)) { + adapter->fw_done_rc = -EIO; + complete(&adapter->fw_done); + } + if (!completion_done(&adapter->stats_done)) + complete(&adapter->stats_done); if (test_bit(0, &adapter->resetting)) adapter->force_reset_recovery = true; if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) { From 476d96ca9cc59ad07dc452184880b635e4e29b06 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 25 Nov 2019 17:12:55 -0600 Subject: [PATCH 06/20] ibmvnic: Bound waits for device queries Create a wrapper for wait_for_completion calls with additional driver checks to ensure that the driver does not wait on a disabled device. In those cases or if the device does not respond in an extended amount of time, this will allow the driver an opportunity to recover. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 112 +++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index dc1b88116330..4ff6a515c061 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -159,6 +159,40 @@ static long h_reg_sub_crq(unsigned long unit_address, unsigned long token, return rc; } +/** + * ibmvnic_wait_for_completion - Check device state and wait for completion + * @adapter: private device data + * @comp_done: completion structure to wait for + * @timeout: time to wait in milliseconds + * + * Wait for a completion signal or until the timeout limit is reached + * while checking that the device is still active. + */ +static int ibmvnic_wait_for_completion(struct ibmvnic_adapter *adapter, + struct completion *comp_done, + unsigned long timeout) +{ + struct net_device *netdev; + unsigned long div_timeout; + u8 retry; + + netdev = adapter->netdev; + retry = 5; + div_timeout = msecs_to_jiffies(timeout / retry); + while (true) { + if (!adapter->crq.active) { + netdev_err(netdev, "Device down!\n"); + return -ENODEV; + } + if (retry--) + break; + if (wait_for_completion_timeout(comp_done, div_timeout)) + return 0; + } + netdev_err(netdev, "Operation timed out.\n"); + return -ETIMEDOUT; +} + static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb, int size) { @@ -183,7 +217,15 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); return rc; } - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) { + dev_err(dev, + "Long term map request aborted or timed out,rc = %d\n", + rc); + dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); + return rc; + } if (adapter->fw_done_rc) { dev_err(dev, "Couldn't map long term buffer,rc = %d\n", @@ -211,6 +253,7 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter, static int reset_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb) { + struct device *dev = &adapter->vdev->dev; int rc; memset(ltb->buff, 0, ltb->size); @@ -219,10 +262,16 @@ static int reset_long_term_buff(struct ibmvnic_adapter *adapter, rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); if (rc) return rc; - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) { + dev_info(dev, + "Reset failed, long term map request timed out or aborted\n"); + return rc; + } if (adapter->fw_done_rc) { - dev_info(&adapter->vdev->dev, + dev_info(dev, "Reset failed, attempting to free and reallocate buffer\n"); free_long_term_buff(adapter, ltb); return alloc_long_term_buff(adapter, ltb, ltb->size); @@ -949,7 +998,12 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) rc = ibmvnic_send_crq(adapter, &crq); if (rc) return rc; - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) { + dev_err(dev, "Could not retrieve VPD size, rc = %d\n", rc); + return rc; + } if (!adapter->vpd->len) return -ENODATA; @@ -987,7 +1041,14 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) adapter->vpd->buff = NULL; return rc; } - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) { + dev_err(dev, "Unable to retrieve VPD, rc = %d\n", rc); + kfree(adapter->vpd->buff); + adapter->vpd->buff = NULL; + return rc; + } return 0; } @@ -1696,9 +1757,9 @@ static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr) goto err; } - wait_for_completion(&adapter->fw_done); + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); /* netdev->dev_addr is changed in handle_change_mac_rsp function */ - if (adapter->fw_done_rc) { + if (rc || adapter->fw_done_rc) { rc = -EIO; goto err; } @@ -2319,9 +2380,16 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter) reinit_completion(&adapter->reset_done); adapter->wait_for_reset = true; rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM); - if (rc) - return rc; - wait_for_completion(&adapter->reset_done); + + if (rc) { + ret = rc; + goto out; + } + rc = ibmvnic_wait_for_completion(adapter, &adapter->reset_done, 60000); + if (rc) { + ret = -ENODEV; + goto out; + } ret = 0; if (adapter->reset_done_rc) { @@ -2335,10 +2403,18 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter) reinit_completion(&adapter->reset_done); adapter->wait_for_reset = true; rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM); - if (rc) - return ret; - wait_for_completion(&adapter->reset_done); + if (rc) { + ret = rc; + goto out; + } + rc = ibmvnic_wait_for_completion(adapter, &adapter->reset_done, + 60000); + if (rc) { + ret = -ENODEV; + goto out; + } } +out: adapter->wait_for_reset = false; return ret; @@ -2607,7 +2683,9 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev, rc = ibmvnic_send_crq(adapter, &crq); if (rc) return; - wait_for_completion(&adapter->stats_done); + rc = ibmvnic_wait_for_completion(adapter, &adapter->stats_done, 10000); + if (rc) + return; for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++) data[i] = be64_to_cpu(IBMVNIC_GET_STAT(adapter, @@ -4412,7 +4490,11 @@ static int send_query_phys_parms(struct ibmvnic_adapter *adapter) rc = ibmvnic_send_crq(adapter, &crq); if (rc) return rc; - wait_for_completion(&adapter->fw_done); + + rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); + if (rc) + return rc; + return adapter->fw_done_rc ? -EIO : 0; } From ff25dcb9a1492ecbe495de936765c7ff3441b601 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 25 Nov 2019 17:12:56 -0600 Subject: [PATCH 07/20] ibmvnic: Serialize device queries Provide some serialization for device CRQ commands and queries to ensure that the shared variable used for storing return codes is properly synchronized. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 54 +++++++++++++++++++++++++++--- drivers/net/ethernet/ibm/ibmvnic.h | 2 ++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 4ff6a515c061..c90080781924 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -210,11 +210,14 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, ltb->map_id = adapter->map_id; adapter->map_id++; + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); if (rc) { dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); + mutex_unlock(&adapter->fw_lock); return rc; } @@ -224,6 +227,7 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, "Long term map request aborted or timed out,rc = %d\n", rc); dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); + mutex_unlock(&adapter->fw_lock); return rc; } @@ -231,8 +235,10 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, dev_err(dev, "Couldn't map long term buffer,rc = %d\n", adapter->fw_done_rc); dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); + mutex_unlock(&adapter->fw_lock); return -1; } + mutex_unlock(&adapter->fw_lock); return 0; } @@ -258,15 +264,21 @@ static int reset_long_term_buff(struct ibmvnic_adapter *adapter, memset(ltb->buff, 0, ltb->size); + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; + reinit_completion(&adapter->fw_done); rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); - if (rc) + if (rc) { + mutex_unlock(&adapter->fw_lock); return rc; + } rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); if (rc) { dev_info(dev, "Reset failed, long term map request timed out or aborted\n"); + mutex_unlock(&adapter->fw_lock); return rc; } @@ -274,8 +286,10 @@ static int reset_long_term_buff(struct ibmvnic_adapter *adapter, dev_info(dev, "Reset failed, attempting to free and reallocate buffer\n"); free_long_term_buff(adapter, ltb); + mutex_unlock(&adapter->fw_lock); return alloc_long_term_buff(adapter, ltb, ltb->size); } + mutex_unlock(&adapter->fw_lock); return 0; } @@ -992,18 +1006,25 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) if (adapter->vpd->buff) len = adapter->vpd->len; + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); + crq.get_vpd_size.first = IBMVNIC_CRQ_CMD; crq.get_vpd_size.cmd = GET_VPD_SIZE; rc = ibmvnic_send_crq(adapter, &crq); - if (rc) + if (rc) { + mutex_unlock(&adapter->fw_lock); return rc; + } rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); if (rc) { dev_err(dev, "Could not retrieve VPD size, rc = %d\n", rc); + mutex_unlock(&adapter->fw_lock); return rc; } + mutex_unlock(&adapter->fw_lock); if (!adapter->vpd->len) return -ENODATA; @@ -1030,7 +1051,10 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) return -ENOMEM; } + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); + crq.get_vpd.first = IBMVNIC_CRQ_CMD; crq.get_vpd.cmd = GET_VPD; crq.get_vpd.ioba = cpu_to_be32(adapter->vpd->dma_addr); @@ -1039,6 +1063,7 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) if (rc) { kfree(adapter->vpd->buff); adapter->vpd->buff = NULL; + mutex_unlock(&adapter->fw_lock); return rc; } @@ -1047,9 +1072,11 @@ static int ibmvnic_get_vpd(struct ibmvnic_adapter *adapter) dev_err(dev, "Unable to retrieve VPD, rc = %d\n", rc); kfree(adapter->vpd->buff); adapter->vpd->buff = NULL; + mutex_unlock(&adapter->fw_lock); return rc; } + mutex_unlock(&adapter->fw_lock); return 0; } @@ -1750,10 +1777,14 @@ static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr) crq.change_mac_addr.cmd = CHANGE_MAC_ADDR; ether_addr_copy(&crq.change_mac_addr.mac_addr[0], dev_addr); + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); + rc = ibmvnic_send_crq(adapter, &crq); if (rc) { rc = -EIO; + mutex_unlock(&adapter->fw_lock); goto err; } @@ -1761,9 +1792,10 @@ static int __ibmvnic_set_mac(struct net_device *netdev, u8 *dev_addr) /* netdev->dev_addr is changed in handle_change_mac_rsp function */ if (rc || adapter->fw_done_rc) { rc = -EIO; + mutex_unlock(&adapter->fw_lock); goto err; } - + mutex_unlock(&adapter->fw_lock); return 0; err: ether_addr_copy(adapter->mac_addr, netdev->dev_addr); @@ -4486,15 +4518,24 @@ static int send_query_phys_parms(struct ibmvnic_adapter *adapter) memset(&crq, 0, sizeof(crq)); crq.query_phys_parms.first = IBMVNIC_CRQ_CMD; crq.query_phys_parms.cmd = QUERY_PHYS_PARMS; + + mutex_lock(&adapter->fw_lock); + adapter->fw_done_rc = 0; reinit_completion(&adapter->fw_done); + rc = ibmvnic_send_crq(adapter, &crq); - if (rc) + if (rc) { + mutex_unlock(&adapter->fw_lock); return rc; + } rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000); - if (rc) + if (rc) { + mutex_unlock(&adapter->fw_lock); return rc; + } + mutex_unlock(&adapter->fw_lock); return adapter->fw_done_rc ? -EIO : 0; } @@ -5050,6 +5091,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) __ibmvnic_delayed_reset); INIT_LIST_HEAD(&adapter->rwi_list); spin_lock_init(&adapter->rwi_lock); + mutex_init(&adapter->fw_lock); init_completion(&adapter->init_done); init_completion(&adapter->fw_done); init_completion(&adapter->reset_done); @@ -5111,6 +5153,7 @@ ibmvnic_stats_fail: ibmvnic_init_fail: release_sub_crqs(adapter, 1); release_crq_queue(adapter); + mutex_destroy(&adapter->fw_lock); free_netdev(netdev); return rc; @@ -5135,6 +5178,7 @@ static int ibmvnic_remove(struct vio_dev *dev) adapter->state = VNIC_REMOVED; rtnl_unlock(); + mutex_destroy(&adapter->fw_lock); device_remove_file(&dev->dev, &dev_attr_failover); free_netdev(netdev); dev_set_drvdata(&dev->dev, NULL); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index ebc39248b334..60eccaf91b12 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1026,6 +1026,8 @@ struct ibmvnic_adapter { int init_done_rc; struct completion fw_done; + /* Used for serialization of device commands */ + struct mutex fw_lock; int fw_done_rc; struct completion reset_done; From 82f31ebf61bed3077c9935308e0a4b6c44842c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 25 Nov 2019 15:37:04 -0800 Subject: [PATCH 08/20] net: port < inet_prot_sock(net) --> inet_port_requires_bind_service(net, port) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note that the sysctl write accessor functions guarantee that: net->ipv4.sysctl_ip_prot_sock <= net->ipv4.ip_local_ports.range[0] invariant is maintained, and as such the max() in selinux hooks is actually spurious. ie. even though if (snum < max(inet_prot_sock(sock_net(sk)), low) || snum > high) { per logic is the same as if ((snum < inet_prot_sock(sock_net(sk)) && snum < low) || snum > high) { it is actually functionally equivalent to: if (snum < low || snum > high) { which is equivalent to: if (snum < inet_prot_sock(sock_net(sk)) || snum < low || snum > high) { even though the first clause is spurious. But we want to hold on to it in case we ever want to change what what inet_port_requires_bind_service() means (for example by changing it from a, by default, [0..1024) range to some sort of set). Test: builds, git 'grep inet_prot_sock' finds no other references Cc: Eric Dumazet Signed-off-by: Maciej Żenczykowski Signed-off-by: David S. Miller --- include/net/ip.h | 8 ++++---- net/ipv4/af_inet.c | 2 +- net/ipv6/af_inet6.c | 2 +- net/netfilter/ipvs/ip_vs_ctl.c | 2 +- net/sctp/socket.c | 4 ++-- security/selinux/hooks.c | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index cebf3e10def1..5a61bd948b18 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -351,9 +351,9 @@ static inline bool sysctl_dev_name_is_allowed(const char *name) return strcmp(name, "default") != 0 && strcmp(name, "all") != 0; } -static inline int inet_prot_sock(struct net *net) +static inline bool inet_port_requires_bind_service(struct net *net, unsigned short port) { - return net->ipv4.sysctl_ip_prot_sock; + return port < net->ipv4.sysctl_ip_prot_sock; } #else @@ -362,9 +362,9 @@ static inline bool inet_is_local_reserved_port(struct net *net, int port) return false; } -static inline int inet_prot_sock(struct net *net) +static inline bool inet_port_requires_bind_service(struct net *net, unsigned short port) { - return PROT_SOCK; + return port < PROT_SOCK; } #endif diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 53de8e00990e..2fe295432c24 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -495,7 +495,7 @@ int __inet_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, snum = ntohs(addr->sin_port); err = -EACCES; - if (snum && snum < inet_prot_sock(net) && + if (snum && inet_port_requires_bind_service(net, snum) && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) goto out; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index ef37e0574f54..60e2ff91a5b3 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -292,7 +292,7 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, return -EINVAL; snum = ntohs(addr->sin6_port); - if (snum && snum < inet_prot_sock(net) && + if (snum && inet_port_requires_bind_service(net, snum) && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) return -EACCES; diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 3be7398901e0..8d14a1acbc37 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -423,7 +423,7 @@ ip_vs_service_find(struct netns_ipvs *ipvs, int af, __u32 fwmark, __u16 protocol if (!svc && protocol == IPPROTO_TCP && atomic_read(&ipvs->ftpsvc_counter) && - (vport == FTPDATA || ntohs(vport) >= inet_prot_sock(ipvs->net))) { + (vport == FTPDATA || !inet_port_requires_bind_service(ipvs->net, ntohs(vport)))) { /* * Check if ftp service entry exists, the packet * might belong to FTP data connections. diff --git a/net/sctp/socket.c b/net/sctp/socket.c index e4c398db07a0..0b485952a71c 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -384,7 +384,7 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) } } - if (snum && snum < inet_prot_sock(net) && + if (snum && inet_port_requires_bind_service(net, snum) && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) return -EACCES; @@ -1061,7 +1061,7 @@ static int sctp_connect_new_asoc(struct sctp_endpoint *ep, if (sctp_autobind(sk)) return -EAGAIN; } else { - if (ep->base.bind_addr.port < inet_prot_sock(net) && + if (inet_port_requires_bind_service(net, ep->base.bind_addr.port) && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) return -EACCES; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9625b99e677f..753b327f4806 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4623,8 +4623,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in inet_get_local_port_range(sock_net(sk), &low, &high); - if (snum < max(inet_prot_sock(sock_net(sk)), low) || - snum > high) { + if (inet_port_requires_bind_service(sock_net(sk), snum) || + snum < low || snum > high) { err = sel_netport_sid(sk->sk_protocol, snum, &sid); if (err) From 1d4a09dadbb9ea7baaf6be897d69020c729e7440 Mon Sep 17 00:00:00 2001 From: Phong Tran Date: Tue, 26 Nov 2019 20:54:12 +0700 Subject: [PATCH 09/20] net: hso: Fix -Wcast-function-type correct usage prototype of callback in tasklet_init(). Report by https://github.com/KSPP/linux/issues/20 Signed-off-by: Phong Tran Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 74849da031fa..ca827802f291 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1214,8 +1214,9 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) * This needs to be a tasklet otherwise we will * end up recursively calling this function. */ -static void hso_unthrottle_tasklet(struct hso_serial *serial) +static void hso_unthrottle_tasklet(unsigned long data) { + struct hso_serial *serial = (struct hso_serial *)data; unsigned long flags; spin_lock_irqsave(&serial->serial_lock, flags); @@ -1265,7 +1266,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) /* Force default termio settings */ _hso_serial_set_termios(tty, NULL); tasklet_init(&serial->unthrottle_tasklet, - (void (*)(unsigned long))hso_unthrottle_tasklet, + hso_unthrottle_tasklet, (unsigned long)serial); result = hso_start_serial_device(serial->parent, GFP_KERNEL); if (result) { From 2eb1d3f4bcae6c83943214ccb26968a48360db06 Mon Sep 17 00:00:00 2001 From: Phong Tran Date: Tue, 26 Nov 2019 20:54:13 +0700 Subject: [PATCH 10/20] net: usbnet: Fix -Wcast-function-type correct usage prototype of callback in tasklet_init(). Report by https://github.com/KSPP/linux/issues/20 Signed-off-by: Phong Tran Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index dde05e2fdc3e..30e511c2c8d0 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1573,6 +1573,13 @@ static void usbnet_bh (struct timer_list *t) } } +static void usbnet_bh_tasklet(unsigned long data) +{ + struct timer_list *t = (struct timer_list *)data; + + usbnet_bh(t); +} + /*------------------------------------------------------------------------- * @@ -1700,7 +1707,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); skb_queue_head_init(&dev->rxq_pause); - dev->bh.func = (void (*)(unsigned long))usbnet_bh; + dev->bh.func = usbnet_bh_tasklet; dev->bh.data = (unsigned long)&dev->delay; INIT_WORK (&dev->kevent, usbnet_deferred_kevent); init_usb_anchor(&dev->deferred); From 7eb9d7675c08937cd11d32b0b40442d4d731c5ee Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 27 Nov 2019 00:16:44 +0200 Subject: [PATCH 11/20] net: psample: fix skb_over_panic We need to calculate the skb size correctly otherwise we risk triggering skb_over_panic[1]. The issue is that data_len is added to the skb in a nl attribute, but we don't account for its header size (nlattr 4 bytes) and alignment. We account for it when calculating the total size in the > PSAMPLE_MAX_PACKET_SIZE comparison correctly, but not when allocating after that. The fix is simple - use nla_total_size() for data_len when allocating. To reproduce: $ tc qdisc add dev eth1 clsact $ tc filter add dev eth1 egress matchall action sample rate 1 group 1 trunc 129 $ mausezahn eth1 -b bcast -a rand -c 1 -p 129 < skb_over_panic BUG(), tail is 4 bytes past skb->end > [1] Trace: [ 50.459526][ T3480] skbuff: skb_over_panic: text:(____ptrval____) len:196 put:136 head:(____ptrval____) data:(____ptrval____) tail:0xc4 end:0xc0 dev: [ 50.474339][ T3480] ------------[ cut here ]------------ [ 50.481132][ T3480] kernel BUG at net/core/skbuff.c:108! [ 50.486059][ T3480] invalid opcode: 0000 [#1] PREEMPT SMP [ 50.489463][ T3480] CPU: 3 PID: 3480 Comm: mausezahn Not tainted 5.4.0-rc7 #108 [ 50.492844][ T3480] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014 [ 50.496551][ T3480] RIP: 0010:skb_panic+0x79/0x7b [ 50.498261][ T3480] Code: bc 00 00 00 41 57 4c 89 e6 48 c7 c7 90 29 9a 83 4c 8b 8b c0 00 00 00 50 8b 83 b8 00 00 00 50 ff b3 c8 00 00 00 e8 ae ef c0 fe <0f> 0b e8 2f df c8 fe 48 8b 55 08 44 89 f6 4c 89 e7 48 c7 c1 a0 22 [ 50.504111][ T3480] RSP: 0018:ffffc90000447a10 EFLAGS: 00010282 [ 50.505835][ T3480] RAX: 0000000000000087 RBX: ffff888039317d00 RCX: 0000000000000000 [ 50.507900][ T3480] RDX: 0000000000000000 RSI: ffffffff812716e1 RDI: 00000000ffffffff [ 50.509820][ T3480] RBP: ffffc90000447a60 R08: 0000000000000001 R09: 0000000000000000 [ 50.511735][ T3480] R10: ffffffff81d4f940 R11: 0000000000000000 R12: ffffffff834a22b0 [ 50.513494][ T3480] R13: ffffffff82c10433 R14: 0000000000000088 R15: ffffffff838a8084 [ 50.515222][ T3480] FS: 00007f3536462700(0000) GS:ffff88803eac0000(0000) knlGS:0000000000000000 [ 50.517135][ T3480] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 50.518583][ T3480] CR2: 0000000000442008 CR3: 000000003b222000 CR4: 00000000000006e0 [ 50.520723][ T3480] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 50.522709][ T3480] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 50.524450][ T3480] Call Trace: [ 50.525214][ T3480] skb_put.cold+0x1b/0x1b [ 50.526171][ T3480] psample_sample_packet+0x1d3/0x340 [ 50.527307][ T3480] tcf_sample_act+0x178/0x250 [ 50.528339][ T3480] tcf_action_exec+0xb1/0x190 [ 50.529354][ T3480] mall_classify+0x67/0x90 [ 50.530332][ T3480] tcf_classify+0x72/0x160 [ 50.531286][ T3480] __dev_queue_xmit+0x3db/0xd50 [ 50.532327][ T3480] dev_queue_xmit+0x18/0x20 [ 50.533299][ T3480] packet_sendmsg+0xee7/0x2090 [ 50.534331][ T3480] sock_sendmsg+0x54/0x70 [ 50.535271][ T3480] __sys_sendto+0x148/0x1f0 [ 50.536252][ T3480] ? tomoyo_file_ioctl+0x23/0x30 [ 50.537334][ T3480] ? ksys_ioctl+0x5e/0xb0 [ 50.540068][ T3480] __x64_sys_sendto+0x2a/0x30 [ 50.542810][ T3480] do_syscall_64+0x73/0x1f0 [ 50.545383][ T3480] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 50.548477][ T3480] RIP: 0033:0x7f35357d6fb3 [ 50.551020][ T3480] Code: 48 8b 0d 18 90 20 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 83 3d f9 d3 20 00 00 75 13 49 89 ca b8 2c 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 34 c3 48 83 ec 08 e8 eb f6 ff ff 48 89 04 24 [ 50.558547][ T3480] RSP: 002b:00007ffe0c7212c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c [ 50.561870][ T3480] RAX: ffffffffffffffda RBX: 0000000001dac010 RCX: 00007f35357d6fb3 [ 50.565142][ T3480] RDX: 0000000000000082 RSI: 0000000001dac2a2 RDI: 0000000000000003 [ 50.568469][ T3480] RBP: 00007ffe0c7212f0 R08: 00007ffe0c7212d0 R09: 0000000000000014 [ 50.571731][ T3480] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000082 [ 50.574961][ T3480] R13: 0000000001dac2a2 R14: 0000000000000001 R15: 0000000000000003 [ 50.578170][ T3480] Modules linked in: sch_ingress virtio_net [ 50.580976][ T3480] ---[ end trace 61a515626a595af6 ]--- CC: Yotam Gigi CC: Jiri Pirko CC: Jamal Hadi Salim CC: Simon Horman CC: Roopa Prabhu Fixes: 6ae0a6286171 ("net: Introduce psample, a new genetlink channel for packet sampling") Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/psample/psample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/psample/psample.c b/net/psample/psample.c index a6ceb0533b5b..6f2fbc6b9eb2 100644 --- a/net/psample/psample.c +++ b/net/psample/psample.c @@ -229,7 +229,7 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN - NLA_ALIGNTO; - nl_skb = genlmsg_new(meta_len + data_len, GFP_ATOMIC); + nl_skb = genlmsg_new(meta_len + nla_total_size(data_len), GFP_ATOMIC); if (unlikely(!nl_skb)) return; From 786c4a5372e11919b5ea010a7338bac9ef08c732 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 26 Nov 2019 08:38:56 -0600 Subject: [PATCH 12/20] net: phy: dp83869: Fix return paths to return proper values Fix the return paths for all I/O operations to ensure that the I/O completed successfully. Then pass the return to the caller for further processing Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") Reported-by: Andrew Lunn Signed-off-by: Dan Murphy Signed-off-by: David S. Miller --- drivers/net/phy/dp83869.c | 49 +++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 1c7a7c57dec3..93021904c5e4 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -151,13 +151,13 @@ static int dp83869_config_port_mirroring(struct phy_device *phydev) struct dp83869_private *dp83869 = phydev->priv; if (dp83869->port_mirroring == DP83869_PORT_MIRRORING_EN) - phy_set_bits_mmd(phydev, DP83869_DEVADDR, DP83869_GEN_CFG3, - DP83869_CFG3_PORT_MIRROR_EN); + return phy_set_bits_mmd(phydev, DP83869_DEVADDR, + DP83869_GEN_CFG3, + DP83869_CFG3_PORT_MIRROR_EN); else - phy_clear_bits_mmd(phydev, DP83869_DEVADDR, DP83869_GEN_CFG3, - DP83869_CFG3_PORT_MIRROR_EN); - - return 0; + return phy_clear_bits_mmd(phydev, DP83869_DEVADDR, + DP83869_GEN_CFG3, + DP83869_CFG3_PORT_MIRROR_EN); } #ifdef CONFIG_OF_MDIO @@ -204,7 +204,7 @@ static int dp83869_of_init(struct phy_device *phydev) &dp83869->tx_fifo_depth)) dp83869->tx_fifo_depth = DP83869_PHYCR_FIFO_DEPTH_4_B_NIB; - return 0; + return ret; } #else static int dp83869_of_init(struct phy_device *phydev) @@ -216,7 +216,7 @@ static int dp83869_of_init(struct phy_device *phydev) static int dp83869_configure_rgmii(struct phy_device *phydev, struct dp83869_private *dp83869) { - int ret, val; + int ret = 0, val; if (phy_interface_is_rgmii(phydev)) { val = phy_read(phydev, MII_DP83869_PHYCTRL); @@ -233,13 +233,13 @@ static int dp83869_configure_rgmii(struct phy_device *phydev, } if (dp83869->io_impedance >= 0) - phy_modify_mmd(phydev, DP83869_DEVADDR, - DP83869_IO_MUX_CFG, - DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL, - dp83869->io_impedance & - DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL); + ret = phy_modify_mmd(phydev, DP83869_DEVADDR, + DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL, + dp83869->io_impedance & + DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL); - return 0; + return ret; } static int dp83869_configure_mode(struct phy_device *phydev, @@ -284,9 +284,11 @@ static int dp83869_configure_mode(struct phy_device *phydev, return ret; break; case DP83869_RGMII_SGMII_BRIDGE: - phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, - DP83869_SGMII_RGMII_BRIDGE, - DP83869_SGMII_RGMII_BRIDGE); + ret = phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, + DP83869_SGMII_RGMII_BRIDGE, + DP83869_SGMII_RGMII_BRIDGE); + if (ret) + return ret; ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); @@ -334,7 +336,7 @@ static int dp83869_configure_mode(struct phy_device *phydev, return -EINVAL; }; - return 0; + return ret; } static int dp83869_config_init(struct phy_device *phydev) @@ -358,12 +360,13 @@ static int dp83869_config_init(struct phy_device *phydev) /* Clock output selection if muxing property is set */ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) - phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG, - DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, - dp83869->clk_output_sel << - DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); - return 0; + return ret; } static int dp83869_probe(struct phy_device *phydev) From 4e81c0b3fa93d07653e2415fa71656b080a112fd Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 26 Nov 2019 12:55:50 +0100 Subject: [PATCH 13/20] openvswitch: fix flow command message size When user-space sets the OVS_UFID_F_OMIT_* flags, and the relevant flow has no UFID, we can exceed the computed size, as ovs_nla_put_identifier() will always dump an OVS_FLOW_ATTR_KEY attribute. Take the above in account when computing the flow command message size. Fixes: 74ed7ab9264c ("openvswitch: Add support for unique flow IDs.") Reported-by: Qi Jun Ding Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller --- net/openvswitch/datapath.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 93d4991ddc1f..293d5289c4a1 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -723,9 +723,13 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts, { size_t len = NLMSG_ALIGN(sizeof(struct ovs_header)); - /* OVS_FLOW_ATTR_UFID */ + /* OVS_FLOW_ATTR_UFID, or unmasked flow key as fallback + * see ovs_nla_put_identifier() + */ if (sfid && ovs_identifier_is_ufid(sfid)) len += nla_total_size(sfid->ufid_len); + else + len += nla_total_size(ovs_key_attr_size()); /* OVS_FLOW_ATTR_KEY */ if (!sfid || should_fill_key(sfid, ufid_flags)) From 66e2f5f7c7728862e9394769722231b9ce3d8672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 26 Nov 2019 14:44:16 -0800 Subject: [PATCH 14/20] net: inet_is_local_reserved_port() port arg should be unsigned short MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Any argument outside of that range would result in an out of bound memory access, since the accessed array is 65536 bits long. Signed-off-by: Maciej Żenczykowski Signed-off-by: David S. Miller --- include/net/ip.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 5a61bd948b18..02d68e346f67 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -339,7 +339,7 @@ static inline u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_o void inet_get_local_port_range(struct net *net, int *low, int *high); #ifdef CONFIG_SYSCTL -static inline bool inet_is_local_reserved_port(struct net *net, int port) +static inline bool inet_is_local_reserved_port(struct net *net, unsigned short port) { if (!net->ipv4.sysctl_local_reserved_ports) return false; @@ -357,7 +357,7 @@ static inline bool inet_port_requires_bind_service(struct net *net, unsigned sho } #else -static inline bool inet_is_local_reserved_port(struct net *net, int port) +static inline bool inet_is_local_reserved_port(struct net *net, unsigned short port) { return false; } From a95069ecb7092d03b2ea1c39ee04514fe9627540 Mon Sep 17 00:00:00 2001 From: Jeroen de Borst Date: Tue, 26 Nov 2019 15:36:19 -0800 Subject: [PATCH 15/20] gve: Fix the queue page list allocated pages count In gve_alloc_queue_page_list(), when a page allocation fails, qpl->num_entries will be wrong. In this case priv->num_registered_pages can underflow in gve_free_queue_page_list(), causing subsequent calls to gve_alloc_queue_page_list() to fail. Fixes: f5cedc84a30d ("gve: Add transmit and receive support") Signed-off-by: Jeroen de Borst Reviewed-by: Catherine Sullivan Signed-off-by: David S. Miller --- drivers/net/ethernet/google/gve/gve_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index aca95f64bde8..9b7a8db9860f 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -544,7 +544,7 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id, } qpl->id = id; - qpl->num_entries = pages; + qpl->num_entries = 0; qpl->pages = kvzalloc(pages * sizeof(*qpl->pages), GFP_KERNEL); /* caller handles clean up */ if (!qpl->pages) @@ -562,6 +562,7 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id, /* caller handles clean up */ if (err) return -ENOMEM; + qpl->num_entries++; } priv->num_registered_pages += pages; From fc62c0948986b7aa6b2871a450a4469e35c5f9bc Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 27 Nov 2019 15:27:56 +0800 Subject: [PATCH 16/20] net: mscc: ocelot: avoid incorrect consuming in skbs list Break the matching loop when find the matching skb for TX timestamp. This is to avoid consuming more skbs incorrectly. The timestamp ID is from 0 to 3 while the FIFO could support 128 timestamps at most. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 0e96ffab3b05..6dc9de3454ba 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -736,6 +736,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) list_del(pos); kfree(entry); + break; } /* Next ts */ From b049da1338082714262034a8c8b87022623dc106 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 27 Nov 2019 15:27:57 +0800 Subject: [PATCH 17/20] net: mscc: ocelot: use skb queue instead of skbs list Convert to use skb queue instead of the list of skbs. The skb queue could provide protection with lock. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 54 ++++++++++-------------------- include/soc/mscc/ocelot.h | 9 +---- 2 files changed, 19 insertions(+), 44 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 6dc9de3454ba..2cccadc204fd 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -583,18 +583,10 @@ int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port, if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP && ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { - struct ocelot_skb *oskb = - kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC); - - if (unlikely(!oskb)) - return -ENOMEM; - shinfo->tx_flags |= SKBTX_IN_PROGRESS; - - oskb->skb = skb; - oskb->id = ocelot_port->ts_id % 4; - - list_add_tail(&oskb->head, &ocelot_port->skbs); + /* Store timestamp ID in cb[0] of sk_buff */ + skb->cb[0] = ocelot_port->ts_id % 4; + skb_queue_tail(&ocelot_port->tx_skbs, skb); return 0; } return -ENODATA; @@ -704,12 +696,11 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) int budget = OCELOT_PTP_QUEUE_SZ; while (budget--) { + struct sk_buff *skb, *skb_tmp, *skb_match = NULL; struct skb_shared_hwtstamps shhwtstamps; - struct list_head *pos, *tmp; - struct sk_buff *skb = NULL; - struct ocelot_skb *entry; struct ocelot_port *port; struct timespec64 ts; + unsigned long flags; u32 val, id, txport; val = ocelot_read(ocelot, SYS_PTP_STATUS); @@ -727,22 +718,22 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) /* Retrieve its associated skb */ port = ocelot->ports[txport]; - list_for_each_safe(pos, tmp, &port->skbs) { - entry = list_entry(pos, struct ocelot_skb, head); - if (entry->id != id) + spin_lock_irqsave(&port->tx_skbs.lock, flags); + + skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) { + if (skb->cb[0] != id) continue; - - skb = entry->skb; - - list_del(pos); - kfree(entry); + __skb_unlink(skb, &port->tx_skbs); + skb_match = skb; break; } + spin_unlock_irqrestore(&port->tx_skbs.lock, flags); + /* Next ts */ ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT); - if (unlikely(!skb)) + if (unlikely(!skb_match)) continue; /* Get the h/w timestamp */ @@ -751,9 +742,9 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) /* Set the timestamp into the skb */ memset(&shhwtstamps, 0, sizeof(shhwtstamps)); shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); - skb_tstamp_tx(skb, &shhwtstamps); + skb_tstamp_tx(skb_match, &shhwtstamps); - dev_kfree_skb_any(skb); + dev_kfree_skb_any(skb_match); } } EXPORT_SYMBOL(ocelot_get_txtstamp); @@ -2206,7 +2197,7 @@ void ocelot_init_port(struct ocelot *ocelot, int port) { struct ocelot_port *ocelot_port = ocelot->ports[port]; - INIT_LIST_HEAD(&ocelot_port->skbs); + skb_queue_head_init(&ocelot_port->tx_skbs); /* Basic L2 initialization */ @@ -2491,9 +2482,7 @@ EXPORT_SYMBOL(ocelot_init); void ocelot_deinit(struct ocelot *ocelot) { - struct list_head *pos, *tmp; struct ocelot_port *port; - struct ocelot_skb *entry; int i; cancel_delayed_work(&ocelot->stats_work); @@ -2503,14 +2492,7 @@ void ocelot_deinit(struct ocelot *ocelot) for (i = 0; i < ocelot->num_phys_ports; i++) { port = ocelot->ports[i]; - - list_for_each_safe(pos, tmp, &port->skbs) { - entry = list_entry(pos, struct ocelot_skb, head); - - list_del(pos); - dev_kfree_skb_any(entry->skb); - kfree(entry); - } + skb_queue_purge(&port->tx_skbs); } } EXPORT_SYMBOL(ocelot_deinit); diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index e1108a5f4f17..64cbbbe74a36 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -406,13 +406,6 @@ struct ocelot_ops { int (*reset)(struct ocelot *ocelot); }; -struct ocelot_skb { - struct list_head head; - struct sk_buff *skb; - u8 id; -}; - - struct ocelot_port { struct ocelot *ocelot; @@ -425,7 +418,7 @@ struct ocelot_port { u16 vid; u8 ptp_cmd; - struct list_head skbs; + struct sk_buff_head tx_skbs; u8 ts_id; }; From b167191e2a851cb2e4c6ef8b91c83ff73ef41872 Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Wed, 27 Nov 2019 12:41:23 +0300 Subject: [PATCH 18/20] net: wireless: intel: iwlwifi: fix GRO_NORMAL packet stalling Commit 6570bc79c0df ("net: core: use listified Rx for GRO_NORMAL in napi_gro_receive()") has applied batched GRO_NORMAL packets processing to all napi_gro_receive() users, including mac80211-based drivers. However, this change has led to a regression in iwlwifi driver [1][2] as it is required for NAPI users to call napi_complete_done() or napi_complete() and the end of every polling iteration, whilst iwlwifi doesn't use NAPI scheduling at all and just calls napi_gro_flush(). In that particular case, packets which have not been already flushed from napi->rx_list stall in it until at least next Rx cycle. Fix this by adding a manual flushing of the list to iwlwifi driver right before napi_gro_flush() call to mimic napi_complete() logics. I prefer to open-code gro_normal_list() rather than exporting it for 2 reasons: * to prevent from using it and napi_gro_flush() in any new drivers, as it is the *really* bad way to use NAPI that should be avoided; * to keep gro_normal_list() static and don't lose any CC optimizations. I also don't add the "Fixes:" tag as the mentioned commit was only a trigger that only exposed an improper usage of NAPI in this particular driver. [1] https://lore.kernel.org/netdev/PSXP216MB04388962C411CD0B17A86F47804A0@PSXP216MB0438.KORP216.PROD.OUTLOOK.COM [2] https://bugzilla.kernel.org/show_bug.cgi?id=205647 Signed-off-by: Alexander Lobakin Acked-by: Luca Coelho Reported-by: Nicholas Johnson Tested-by: Nicholas Johnson Reviewed-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index a4d325fcf94a..452da44a21e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1421,6 +1421,7 @@ out_err: static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct napi_struct *napi; struct iwl_rxq *rxq; u32 r, i, count = 0; bool emergency = false; @@ -1526,8 +1527,16 @@ out: if (unlikely(emergency && count)) iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq); - if (rxq->napi.poll) - napi_gro_flush(&rxq->napi, false); + napi = &rxq->napi; + if (napi->poll) { + if (napi->rx_count) { + netif_receive_skb_list(&napi->rx_list); + INIT_LIST_HEAD(&napi->rx_list); + napi->rx_count = 0; + } + + napi_gro_flush(napi, false); + } iwl_pcie_rxq_restock(trans, rxq); } From 9aab906a9adc292f2bb7eccfd0b1c0aa862296ca Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Wed, 27 Nov 2019 18:49:08 +0530 Subject: [PATCH 19/20] net: phy: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header files related to PHY Layer for Ethernet drivers. For C header files Documentation/process/license-rules.rst mandates C-like comments (opposed to C source files where C++ style should be used). This patch also gives an explicit block comment to the SPDX License Identifier. Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46. Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Signed-off-by: David S. Miller --- drivers/net/phy/aquantia.h | 4 ++-- drivers/net/phy/bcm-phy-lib.h | 2 +- drivers/net/phy/mdio-cavium.h | 2 +- drivers/net/phy/mdio-i2c.h | 2 +- drivers/net/phy/mdio-xgene.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h index 5a16caab7b2f..c684b65c642c 100644 --- a/drivers/net/phy/aquantia.h +++ b/drivers/net/phy/aquantia.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * HWMON driver for Aquantia PHY +/* SPDX-License-Identifier: GPL-2.0 */ +/* HWMON driver for Aquantia PHY * * Author: Nikita Yushchenko * Author: Andrew Lunn diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 5ecacb4e64f0..c86fb9d1240c 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2015 Broadcom Corporation */ diff --git a/drivers/net/phy/mdio-cavium.h b/drivers/net/phy/mdio-cavium.h index b7f89ad27465..e33d3ea9a907 100644 --- a/drivers/net/phy/mdio-cavium.h +++ b/drivers/net/phy/mdio-cavium.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2009-2016 Cavium, Inc. */ diff --git a/drivers/net/phy/mdio-i2c.h b/drivers/net/phy/mdio-i2c.h index 751dab281f57..b1d27f7cd23f 100644 --- a/drivers/net/phy/mdio-i2c.h +++ b/drivers/net/phy/mdio-i2c.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MDIO I2C bridge * diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h index b1f5ccb4ad9c..8af93ada8b64 100644 --- a/drivers/net/phy/mdio-xgene.h +++ b/drivers/net/phy/mdio-xgene.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* Applied Micro X-Gene SoC MDIO Driver * * Copyright (c) 2016, Applied Micro Circuits Corporation From bac139a846697b290c74fefd6af54a9e192de315 Mon Sep 17 00:00:00 2001 From: Nishad Kamdar Date: Wed, 27 Nov 2019 19:15:52 +0530 Subject: [PATCH 20/20] net: usb: aqc111: Use the correct style for SPDX License Identifier This patch corrects the SPDX License Identifier style in header files related to drivers for USB Network devices. This patch gives an explicit block comment to the SPDX License Identifier. Changes made by using a script provided by Joe Perches here: https://lkml.org/lkml/2019/2/7/46. Suggested-by: Joe Perches Signed-off-by: Nishad Kamdar Signed-off-by: David S. Miller --- drivers/net/usb/aqc111.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h index 4d68b3a6067c..b562db4da337 100644 --- a/drivers/net/usb/aqc111.h +++ b/drivers/net/usb/aqc111.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Aquantia Corp. Aquantia AQtion USB to 5GbE Controller +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller * Copyright (C) 2003-2005 David Hollis * Copyright (C) 2005 Phil Chang * Copyright (C) 2002-2003 TiVo Inc.