mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
Merge ddec8ed2d4 ("Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma") into android-mainline
Steps on the way to 5.16-final Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I541aa09852c20c40f3d47d286f105ad985799f6c
This commit is contained in:
@@ -3769,7 +3769,8 @@ S: Supported
|
||||
F: drivers/net/wireless/broadcom/brcm80211/
|
||||
|
||||
BROADCOM BRCMSTB GPIO DRIVER
|
||||
M: Gregory Fong <gregory.0xf0@gmail.com>
|
||||
M: Doug Berger <opendmb@gmail.com>
|
||||
M: Florian Fainelli <f.fainelli@gmail.com>
|
||||
L: bcm-kernel-feedback-list@broadcom.com
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
|
||||
|
||||
@@ -395,7 +395,7 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
|
||||
reg = ioread32(bank_reg(data, bank, reg_irq_status));
|
||||
|
||||
for_each_set_bit(p, ®, 32)
|
||||
generic_handle_domain_irq(gc->irq.domain, i * 32 + p * 2);
|
||||
generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2);
|
||||
}
|
||||
|
||||
chained_irq_exit(ic, desc);
|
||||
|
||||
@@ -66,7 +66,7 @@ void ib_copy_ah_attr_to_user(struct ib_device *device,
|
||||
struct rdma_ah_attr *src = ah_attr;
|
||||
struct rdma_ah_attr conv_ah;
|
||||
|
||||
memset(&dst->grh.reserved, 0, sizeof(dst->grh.reserved));
|
||||
memset(&dst->grh, 0, sizeof(dst->grh));
|
||||
|
||||
if ((ah_attr->type == RDMA_AH_ATTR_TYPE_OPA) &&
|
||||
(rdma_ah_get_dlid(ah_attr) > be16_to_cpu(IB_LID_PERMISSIVE)) &&
|
||||
|
||||
@@ -447,6 +447,9 @@ static int uapi_finalize(struct uverbs_api *uapi)
|
||||
uapi->num_write_ex = max_write_ex + 1;
|
||||
data = kmalloc_array(uapi->num_write + uapi->num_write_ex,
|
||||
sizeof(*uapi->write_methods), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i != uapi->num_write + uapi->num_write_ex; i++)
|
||||
data[i] = &uapi->notsupp_method;
|
||||
uapi->write_methods = data;
|
||||
|
||||
@@ -664,6 +664,7 @@ struct mlx5_ib_mr {
|
||||
|
||||
/* User MR data */
|
||||
struct mlx5_cache_ent *cache_ent;
|
||||
struct ib_umem *umem;
|
||||
|
||||
/* This is zero'd when the MR is allocated */
|
||||
union {
|
||||
@@ -675,7 +676,7 @@ struct mlx5_ib_mr {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/* Used only by kernel MRs */
|
||||
/* Used only by kernel MRs (umem == NULL) */
|
||||
struct {
|
||||
void *descs;
|
||||
void *descs_alloc;
|
||||
@@ -696,9 +697,8 @@ struct mlx5_ib_mr {
|
||||
int data_length;
|
||||
};
|
||||
|
||||
/* Used only by User MRs */
|
||||
/* Used only by User MRs (umem != NULL) */
|
||||
struct {
|
||||
struct ib_umem *umem;
|
||||
unsigned int page_shift;
|
||||
/* Current access_flags */
|
||||
int access_flags;
|
||||
|
||||
@@ -1904,18 +1904,19 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
|
||||
static void
|
||||
mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
|
||||
{
|
||||
struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.device);
|
||||
int size = mr->max_descs * mr->desc_size;
|
||||
if (!mr->umem && mr->descs) {
|
||||
struct ib_device *device = mr->ibmr.device;
|
||||
int size = mr->max_descs * mr->desc_size;
|
||||
struct mlx5_ib_dev *dev = to_mdev(device);
|
||||
|
||||
if (!mr->descs)
|
||||
return;
|
||||
|
||||
dma_unmap_single(&dev->mdev->pdev->dev, mr->desc_map, size,
|
||||
DMA_TO_DEVICE);
|
||||
kfree(mr->descs_alloc);
|
||||
mr->descs = NULL;
|
||||
dma_unmap_single(&dev->mdev->pdev->dev, mr->desc_map, size,
|
||||
DMA_TO_DEVICE);
|
||||
kfree(mr->descs_alloc);
|
||||
mr->descs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
|
||||
@@ -1991,8 +1992,7 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
|
||||
if (mr->cache_ent) {
|
||||
mlx5_mr_cache_free(dev, mr);
|
||||
} else {
|
||||
if (!udata)
|
||||
mlx5_free_priv_descs(mr);
|
||||
mlx5_free_priv_descs(mr);
|
||||
kfree(mr);
|
||||
}
|
||||
return 0;
|
||||
@@ -2079,6 +2079,7 @@ static struct mlx5_ib_mr *mlx5_ib_alloc_pi_mr(struct ib_pd *pd,
|
||||
if (err)
|
||||
goto err_free_in;
|
||||
|
||||
mr->umem = NULL;
|
||||
kfree(in);
|
||||
|
||||
return mr;
|
||||
@@ -2205,6 +2206,7 @@ static struct ib_mr *__mlx5_ib_alloc_mr(struct ib_pd *pd,
|
||||
}
|
||||
|
||||
mr->ibmr.device = pd->device;
|
||||
mr->umem = NULL;
|
||||
|
||||
switch (mr_type) {
|
||||
case IB_MR_TYPE_MEM_REG:
|
||||
|
||||
@@ -135,19 +135,19 @@ static int rxe_mr_alloc(struct rxe_mr *mr, int num_buf, int both)
|
||||
|
||||
ret = rxe_mr_alloc_map_set(num_map, &mr->cur_map_set);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
return -ENOMEM;
|
||||
|
||||
if (both) {
|
||||
ret = rxe_mr_alloc_map_set(num_map, &mr->next_map_set);
|
||||
if (ret) {
|
||||
rxe_mr_free_map_set(mr->num_map, mr->cur_map_set);
|
||||
goto err_out;
|
||||
}
|
||||
if (ret)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
err_free:
|
||||
rxe_mr_free_map_set(mr->num_map, mr->cur_map_set);
|
||||
mr->cur_map_set = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
|
||||
pr_warn("%s: Unable to get virtual address\n",
|
||||
__func__);
|
||||
err = -ENOMEM;
|
||||
goto err_cleanup_map;
|
||||
goto err_release_umem;
|
||||
}
|
||||
|
||||
buf->addr = (uintptr_t)vaddr;
|
||||
@@ -237,8 +237,6 @@ int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
|
||||
|
||||
return 0;
|
||||
|
||||
err_cleanup_map:
|
||||
rxe_mr_free_map_set(mr->num_map, mr->cur_map_set);
|
||||
err_release_umem:
|
||||
ib_umem_release(umem);
|
||||
err_out:
|
||||
|
||||
@@ -1288,26 +1288,22 @@ static int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
|
||||
|
||||
static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id)
|
||||
{
|
||||
struct ena_tx_buffer *tx_info = NULL;
|
||||
struct ena_tx_buffer *tx_info;
|
||||
|
||||
if (likely(req_id < tx_ring->ring_size)) {
|
||||
tx_info = &tx_ring->tx_buffer_info[req_id];
|
||||
if (likely(tx_info->skb))
|
||||
return 0;
|
||||
}
|
||||
tx_info = &tx_ring->tx_buffer_info[req_id];
|
||||
if (likely(tx_info->skb))
|
||||
return 0;
|
||||
|
||||
return handle_invalid_req_id(tx_ring, req_id, tx_info, false);
|
||||
}
|
||||
|
||||
static int validate_xdp_req_id(struct ena_ring *xdp_ring, u16 req_id)
|
||||
{
|
||||
struct ena_tx_buffer *tx_info = NULL;
|
||||
struct ena_tx_buffer *tx_info;
|
||||
|
||||
if (likely(req_id < xdp_ring->ring_size)) {
|
||||
tx_info = &xdp_ring->tx_buffer_info[req_id];
|
||||
if (likely(tx_info->xdpf))
|
||||
return 0;
|
||||
}
|
||||
tx_info = &xdp_ring->tx_buffer_info[req_id];
|
||||
if (likely(tx_info->xdpf))
|
||||
return 0;
|
||||
|
||||
return handle_invalid_req_id(xdp_ring, req_id, tx_info, true);
|
||||
}
|
||||
@@ -1332,9 +1328,14 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
|
||||
|
||||
rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq,
|
||||
&req_id);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
if (unlikely(rc == -EINVAL))
|
||||
handle_invalid_req_id(tx_ring, req_id, NULL,
|
||||
false);
|
||||
break;
|
||||
}
|
||||
|
||||
/* validate that the request id points to a valid skb */
|
||||
rc = validate_tx_req_id(tx_ring, req_id);
|
||||
if (rc)
|
||||
break;
|
||||
@@ -1427,6 +1428,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
|
||||
u16 *next_to_clean)
|
||||
{
|
||||
struct ena_rx_buffer *rx_info;
|
||||
struct ena_adapter *adapter;
|
||||
u16 len, req_id, buf = 0;
|
||||
struct sk_buff *skb;
|
||||
void *page_addr;
|
||||
@@ -1439,8 +1441,14 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
|
||||
rx_info = &rx_ring->rx_buffer_info[req_id];
|
||||
|
||||
if (unlikely(!rx_info->page)) {
|
||||
netif_err(rx_ring->adapter, rx_err, rx_ring->netdev,
|
||||
"Page is NULL\n");
|
||||
adapter = rx_ring->adapter;
|
||||
netif_err(adapter, rx_err, rx_ring->netdev,
|
||||
"Page is NULL. qid %u req_id %u\n", rx_ring->qid, req_id);
|
||||
ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1, &rx_ring->syncp);
|
||||
adapter->reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID;
|
||||
/* Make sure reset reason is set before triggering the reset */
|
||||
smp_mb__before_atomic();
|
||||
set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1896,9 +1904,14 @@ static int ena_clean_xdp_irq(struct ena_ring *xdp_ring, u32 budget)
|
||||
|
||||
rc = ena_com_tx_comp_req_id_get(xdp_ring->ena_com_io_cq,
|
||||
&req_id);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
if (unlikely(rc == -EINVAL))
|
||||
handle_invalid_req_id(xdp_ring, req_id, NULL,
|
||||
true);
|
||||
break;
|
||||
}
|
||||
|
||||
/* validate that the request id points to a valid xdp_frame */
|
||||
rc = validate_xdp_req_id(xdp_ring, req_id);
|
||||
if (rc)
|
||||
break;
|
||||
@@ -4013,10 +4026,6 @@ static u32 ena_calc_max_io_queue_num(struct pci_dev *pdev,
|
||||
max_num_io_queues = min_t(u32, max_num_io_queues, io_tx_cq_num);
|
||||
/* 1 IRQ for mgmnt and 1 IRQs for each IO direction */
|
||||
max_num_io_queues = min_t(u32, max_num_io_queues, pci_msix_vec_count(pdev) - 1);
|
||||
if (unlikely(!max_num_io_queues)) {
|
||||
dev_err(&pdev->dev, "The device doesn't have io queues\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return max_num_io_queues;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ struct tgec_mdio_controller {
|
||||
#define MDIO_CTL_READ BIT(15)
|
||||
|
||||
#define MDIO_DATA(x) (x & 0xffff)
|
||||
#define MDIO_DATA_BSY BIT(31)
|
||||
|
||||
struct mdio_fsl_priv {
|
||||
struct tgec_mdio_controller __iomem *mdio_base;
|
||||
|
||||
@@ -99,6 +99,24 @@ MODULE_LICENSE("GPL v2");
|
||||
|
||||
static struct workqueue_struct *i40e_wq;
|
||||
|
||||
static void netdev_hw_addr_refcnt(struct i40e_mac_filter *f,
|
||||
struct net_device *netdev, int delta)
|
||||
{
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
if (!f || !netdev)
|
||||
return;
|
||||
|
||||
netdev_for_each_mc_addr(ha, netdev) {
|
||||
if (ether_addr_equal(ha->addr, f->macaddr)) {
|
||||
ha->refcount += delta;
|
||||
if (ha->refcount <= 0)
|
||||
ha->refcount = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
|
||||
* @hw: pointer to the HW structure
|
||||
@@ -2036,6 +2054,7 @@ static void i40e_undo_add_filter_entries(struct i40e_vsi *vsi,
|
||||
hlist_for_each_entry_safe(new, h, from, hlist) {
|
||||
/* We can simply free the wrapper structure */
|
||||
hlist_del(&new->hlist);
|
||||
netdev_hw_addr_refcnt(new->f, vsi->netdev, -1);
|
||||
kfree(new);
|
||||
}
|
||||
}
|
||||
@@ -2383,6 +2402,10 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
|
||||
&tmp_add_list,
|
||||
&tmp_del_list,
|
||||
vlan_filters);
|
||||
|
||||
hlist_for_each_entry(new, &tmp_add_list, hlist)
|
||||
netdev_hw_addr_refcnt(new->f, vsi->netdev, 1);
|
||||
|
||||
if (retval)
|
||||
goto err_no_memory_locked;
|
||||
|
||||
@@ -2515,6 +2538,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
|
||||
if (new->f->state == I40E_FILTER_NEW)
|
||||
new->f->state = new->state;
|
||||
hlist_del(&new->hlist);
|
||||
netdev_hw_addr_refcnt(new->f, vsi->netdev, -1);
|
||||
kfree(new);
|
||||
}
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
@@ -8716,6 +8740,27 @@ int i40e_open(struct net_device *netdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_netif_set_realnum_tx_rx_queues - Update number of tx/rx queues
|
||||
* @vsi: vsi structure
|
||||
*
|
||||
* This updates netdev's number of tx/rx queues
|
||||
*
|
||||
* Returns status of setting tx/rx queues
|
||||
**/
|
||||
static int i40e_netif_set_realnum_tx_rx_queues(struct i40e_vsi *vsi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = netif_set_real_num_rx_queues(vsi->netdev,
|
||||
vsi->num_queue_pairs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return netif_set_real_num_tx_queues(vsi->netdev,
|
||||
vsi->num_queue_pairs);
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_vsi_open -
|
||||
* @vsi: the VSI to open
|
||||
@@ -8752,13 +8797,7 @@ int i40e_vsi_open(struct i40e_vsi *vsi)
|
||||
goto err_setup_rx;
|
||||
|
||||
/* Notify the stack of the actual queue counts. */
|
||||
err = netif_set_real_num_tx_queues(vsi->netdev,
|
||||
vsi->num_queue_pairs);
|
||||
if (err)
|
||||
goto err_set_queues;
|
||||
|
||||
err = netif_set_real_num_rx_queues(vsi->netdev,
|
||||
vsi->num_queue_pairs);
|
||||
err = i40e_netif_set_realnum_tx_rx_queues(vsi);
|
||||
if (err)
|
||||
goto err_set_queues;
|
||||
|
||||
@@ -14149,6 +14188,9 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
|
||||
case I40E_VSI_MAIN:
|
||||
case I40E_VSI_VMDQ2:
|
||||
ret = i40e_config_netdev(vsi);
|
||||
if (ret)
|
||||
goto err_netdev;
|
||||
ret = i40e_netif_set_realnum_tx_rx_queues(vsi);
|
||||
if (ret)
|
||||
goto err_netdev;
|
||||
ret = register_netdev(vsi->netdev);
|
||||
@@ -15451,8 +15493,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
|
||||
hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw))
|
||||
dev_info(&pdev->dev,
|
||||
"The driver for the device detected a newer version of the NVM image v%u.%u than expected v%u.%u. Please install the most recent version of the network driver.\n",
|
||||
dev_dbg(&pdev->dev,
|
||||
"The driver for the device detected a newer version of the NVM image v%u.%u than v%u.%u.\n",
|
||||
hw->aq.api_maj_ver,
|
||||
hw->aq.api_min_ver,
|
||||
I40E_FW_API_VERSION_MAJOR,
|
||||
|
||||
@@ -1877,17 +1877,19 @@ sriov_configure_out:
|
||||
/***********************virtual channel routines******************/
|
||||
|
||||
/**
|
||||
* i40e_vc_send_msg_to_vf
|
||||
* i40e_vc_send_msg_to_vf_ex
|
||||
* @vf: pointer to the VF info
|
||||
* @v_opcode: virtual channel opcode
|
||||
* @v_retval: virtual channel return value
|
||||
* @msg: pointer to the msg buffer
|
||||
* @msglen: msg length
|
||||
* @is_quiet: true for not printing unsuccessful return values, false otherwise
|
||||
*
|
||||
* send msg to VF
|
||||
**/
|
||||
static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
|
||||
u32 v_retval, u8 *msg, u16 msglen)
|
||||
static int i40e_vc_send_msg_to_vf_ex(struct i40e_vf *vf, u32 v_opcode,
|
||||
u32 v_retval, u8 *msg, u16 msglen,
|
||||
bool is_quiet)
|
||||
{
|
||||
struct i40e_pf *pf;
|
||||
struct i40e_hw *hw;
|
||||
@@ -1903,7 +1905,7 @@ static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
|
||||
abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
|
||||
|
||||
/* single place to detect unsuccessful return values */
|
||||
if (v_retval) {
|
||||
if (v_retval && !is_quiet) {
|
||||
vf->num_invalid_msgs++;
|
||||
dev_info(&pf->pdev->dev, "VF %d failed opcode %d, retval: %d\n",
|
||||
vf->vf_id, v_opcode, v_retval);
|
||||
@@ -1933,6 +1935,23 @@ static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_vc_send_msg_to_vf
|
||||
* @vf: pointer to the VF info
|
||||
* @v_opcode: virtual channel opcode
|
||||
* @v_retval: virtual channel return value
|
||||
* @msg: pointer to the msg buffer
|
||||
* @msglen: msg length
|
||||
*
|
||||
* send msg to VF
|
||||
**/
|
||||
static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
|
||||
u32 v_retval, u8 *msg, u16 msglen)
|
||||
{
|
||||
return i40e_vc_send_msg_to_vf_ex(vf, v_opcode, v_retval,
|
||||
msg, msglen, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_vc_send_resp_to_vf
|
||||
* @vf: pointer to the VF info
|
||||
@@ -2695,6 +2714,7 @@ error_param:
|
||||
* i40e_check_vf_permission
|
||||
* @vf: pointer to the VF info
|
||||
* @al: MAC address list from virtchnl
|
||||
* @is_quiet: set true for printing msg without opcode info, false otherwise
|
||||
*
|
||||
* Check that the given list of MAC addresses is allowed. Will return -EPERM
|
||||
* if any address in the list is not valid. Checks the following conditions:
|
||||
@@ -2709,13 +2729,15 @@ error_param:
|
||||
* addresses might not be accurate.
|
||||
**/
|
||||
static inline int i40e_check_vf_permission(struct i40e_vf *vf,
|
||||
struct virtchnl_ether_addr_list *al)
|
||||
struct virtchnl_ether_addr_list *al,
|
||||
bool *is_quiet)
|
||||
{
|
||||
struct i40e_pf *pf = vf->pf;
|
||||
struct i40e_vsi *vsi = pf->vsi[vf->lan_vsi_idx];
|
||||
int mac2add_cnt = 0;
|
||||
int i;
|
||||
|
||||
*is_quiet = false;
|
||||
for (i = 0; i < al->num_elements; i++) {
|
||||
struct i40e_mac_filter *f;
|
||||
u8 *addr = al->list[i].addr;
|
||||
@@ -2739,6 +2761,7 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
|
||||
!ether_addr_equal(addr, vf->default_lan_addr.addr)) {
|
||||
dev_err(&pf->pdev->dev,
|
||||
"VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
|
||||
*is_quiet = true;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -2775,6 +2798,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
|
||||
(struct virtchnl_ether_addr_list *)msg;
|
||||
struct i40e_pf *pf = vf->pf;
|
||||
struct i40e_vsi *vsi = NULL;
|
||||
bool is_quiet = false;
|
||||
i40e_status ret = 0;
|
||||
int i;
|
||||
|
||||
@@ -2791,7 +2815,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
|
||||
*/
|
||||
spin_lock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
||||
ret = i40e_check_vf_permission(vf, al);
|
||||
ret = i40e_check_vf_permission(vf, al, &is_quiet);
|
||||
if (ret) {
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
goto error_param;
|
||||
@@ -2829,8 +2853,8 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
|
||||
|
||||
error_param:
|
||||
/* send the response to the VF */
|
||||
return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_ETH_ADDR,
|
||||
ret);
|
||||
return i40e_vc_send_msg_to_vf_ex(vf, VIRTCHNL_OP_ADD_ETH_ADDR,
|
||||
ret, NULL, 0, is_quiet);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2708,8 +2708,11 @@ static int iavf_validate_ch_config(struct iavf_adapter *adapter,
|
||||
total_max_rate += tx_rate;
|
||||
num_qps += mqprio_qopt->qopt.count[i];
|
||||
}
|
||||
if (num_qps > IAVF_MAX_REQ_QUEUES)
|
||||
if (num_qps > adapter->num_active_queues) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"Cannot support requested number of queues\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = iavf_validate_tx_bandwidth(adapter, total_max_rate);
|
||||
return ret;
|
||||
|
||||
@@ -110,6 +110,8 @@ static struct page *ef4_reuse_page(struct ef4_rx_queue *rx_queue)
|
||||
struct ef4_rx_page_state *state;
|
||||
unsigned index;
|
||||
|
||||
if (unlikely(!rx_queue->page_ring))
|
||||
return NULL;
|
||||
index = rx_queue->page_remove & rx_queue->page_ptr_mask;
|
||||
page = rx_queue->page_ring[index];
|
||||
if (page == NULL)
|
||||
@@ -293,6 +295,9 @@ static void ef4_recycle_rx_pages(struct ef4_channel *channel,
|
||||
{
|
||||
struct ef4_rx_queue *rx_queue = ef4_channel_get_rx_queue(channel);
|
||||
|
||||
if (unlikely(!rx_queue->page_ring))
|
||||
return;
|
||||
|
||||
do {
|
||||
ef4_recycle_rx_page(channel, rx_buf);
|
||||
rx_buf = ef4_rx_buf_next(rx_queue, rx_buf);
|
||||
|
||||
@@ -45,6 +45,8 @@ static struct page *efx_reuse_page(struct efx_rx_queue *rx_queue)
|
||||
unsigned int index;
|
||||
struct page *page;
|
||||
|
||||
if (unlikely(!rx_queue->page_ring))
|
||||
return NULL;
|
||||
index = rx_queue->page_remove & rx_queue->page_ptr_mask;
|
||||
page = rx_queue->page_ring[index];
|
||||
if (page == NULL)
|
||||
@@ -114,6 +116,9 @@ void efx_recycle_rx_pages(struct efx_channel *channel,
|
||||
{
|
||||
struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
|
||||
|
||||
if (unlikely(!rx_queue->page_ring))
|
||||
return;
|
||||
|
||||
do {
|
||||
efx_recycle_rx_page(channel, rx_buf);
|
||||
rx_buf = efx_rx_buf_next(rx_queue, rx_buf);
|
||||
|
||||
@@ -93,7 +93,9 @@ static int atusb_control_msg(struct atusb *atusb, unsigned int pipe,
|
||||
|
||||
ret = usb_control_msg(usb_dev, pipe, request, requesttype,
|
||||
value, index, data, size, timeout);
|
||||
if (ret < 0) {
|
||||
if (ret < size) {
|
||||
ret = ret < 0 ? ret : -ENODATA;
|
||||
|
||||
atusb->err = ret;
|
||||
dev_err(&usb_dev->dev,
|
||||
"%s: req 0x%02x val 0x%x idx 0x%x, error %d\n",
|
||||
@@ -861,9 +863,9 @@ static int atusb_get_and_show_build(struct atusb *atusb)
|
||||
if (!build)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
|
||||
ATUSB_BUILD, ATUSB_REQ_FROM_DEV, 0, 0,
|
||||
build, ATUSB_BUILD_SIZE, 1000);
|
||||
/* We cannot call atusb_control_msg() here, since this request may read various length data */
|
||||
ret = usb_control_msg(atusb->usb_dev, usb_rcvctrlpipe(usb_dev, 0), ATUSB_BUILD,
|
||||
ATUSB_REQ_FROM_DEV, 0, 0, build, ATUSB_BUILD_SIZE, 1000);
|
||||
if (ret >= 0) {
|
||||
build[ret] = 0;
|
||||
dev_info(&usb_dev->dev, "Firmware: build %s\n", build);
|
||||
|
||||
@@ -239,8 +239,8 @@ static struct phy_device *__fixed_phy_register(unsigned int irq,
|
||||
/* Check if we have a GPIO associated with this fixed phy */
|
||||
if (!gpiod) {
|
||||
gpiod = fixed_phy_get_gpiod(np);
|
||||
if (!gpiod)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (IS_ERR(gpiod))
|
||||
return ERR_CAST(gpiod);
|
||||
}
|
||||
|
||||
/* Get the next available PHY address, up to PHY_MAX_ADDR */
|
||||
|
||||
@@ -9638,9 +9638,12 @@ static int rtl8152_probe(struct usb_interface *intf,
|
||||
netdev->hw_features &= ~NETIF_F_RXCSUM;
|
||||
}
|
||||
|
||||
if (udev->parent &&
|
||||
le16_to_cpu(udev->parent->descriptor.idVendor) == VENDOR_ID_LENOVO) {
|
||||
tp->lenovo_macpassthru = 1;
|
||||
if (le16_to_cpu(udev->descriptor.idVendor) == VENDOR_ID_LENOVO) {
|
||||
switch (le16_to_cpu(udev->descriptor.idProduct)) {
|
||||
case DEVICE_ID_THINKPAD_THUNDERBOLT3_DOCK_GEN2:
|
||||
case DEVICE_ID_THINKPAD_USB_C_DOCK_GEN2:
|
||||
tp->lenovo_macpassthru = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && udev->serial &&
|
||||
|
||||
@@ -608,6 +608,11 @@ static const struct usb_device_id products [] = {
|
||||
USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042,
|
||||
USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
|
||||
.driver_info = (unsigned long) &rndis_poll_status_info,
|
||||
}, {
|
||||
/* Hytera Communications DMR radios' "Radio to PC Network" */
|
||||
USB_VENDOR_AND_INTERFACE_INFO(0x238b,
|
||||
USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
|
||||
.driver_info = (unsigned long)&rndis_info,
|
||||
}, {
|
||||
/* RNDIS is MSFT's un-official variant of CDC ACM */
|
||||
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
|
||||
|
||||
@@ -134,6 +134,7 @@ struct inet6_skb_parm {
|
||||
__u16 dsthao;
|
||||
#endif
|
||||
__u16 frag_max_size;
|
||||
__u16 srhoff;
|
||||
|
||||
#define IP6SKB_XFRM_TRANSFORMED 1
|
||||
#define IP6SKB_FORWARDED 2
|
||||
@@ -143,6 +144,7 @@ struct inet6_skb_parm {
|
||||
#define IP6SKB_HOPBYHOP 32
|
||||
#define IP6SKB_L3SLAVE 64
|
||||
#define IP6SKB_JUMBOGRAM 128
|
||||
#define IP6SKB_SEG6 256
|
||||
};
|
||||
|
||||
#if defined(CONFIG_NET_L3_MASTER_DEV)
|
||||
|
||||
@@ -112,8 +112,7 @@ struct sctp_transport *sctp_transport_get_next(struct net *net,
|
||||
struct rhashtable_iter *iter);
|
||||
struct sctp_transport *sctp_transport_get_idx(struct net *net,
|
||||
struct rhashtable_iter *iter, int pos);
|
||||
int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
|
||||
struct net *net,
|
||||
int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net,
|
||||
const union sctp_addr *laddr,
|
||||
const union sctp_addr *paddr, void *p);
|
||||
int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done,
|
||||
|
||||
@@ -58,9 +58,30 @@ extern int seg6_local_init(void);
|
||||
extern void seg6_local_exit(void);
|
||||
|
||||
extern bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced);
|
||||
extern struct ipv6_sr_hdr *seg6_get_srh(struct sk_buff *skb, int flags);
|
||||
extern void seg6_icmp_srh(struct sk_buff *skb, struct inet6_skb_parm *opt);
|
||||
extern int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
|
||||
int proto);
|
||||
extern int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh);
|
||||
extern int seg6_lookup_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
|
||||
u32 tbl_id);
|
||||
|
||||
/* If the packet which invoked an ICMP error contains an SRH return
|
||||
* the true destination address from within the SRH, otherwise use the
|
||||
* destination address in the IP header.
|
||||
*/
|
||||
static inline const struct in6_addr *seg6_get_daddr(struct sk_buff *skb,
|
||||
struct inet6_skb_parm *opt)
|
||||
{
|
||||
struct ipv6_sr_hdr *srh;
|
||||
|
||||
if (opt->flags & IP6SKB_SEG6) {
|
||||
srh = (struct ipv6_sr_hdr *)(skb->data + opt->srhoff);
|
||||
return &srh->segments[0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3208,7 +3208,7 @@ struct trace_buffer_struct {
|
||||
char buffer[4][TRACE_BUF_SIZE];
|
||||
};
|
||||
|
||||
static struct trace_buffer_struct *trace_percpu_buffer;
|
||||
static struct trace_buffer_struct __percpu *trace_percpu_buffer;
|
||||
|
||||
/*
|
||||
* This allows for lockless recording. If we're nested too deeply, then
|
||||
@@ -3218,7 +3218,7 @@ static char *get_trace_buf(void)
|
||||
{
|
||||
struct trace_buffer_struct *buffer = this_cpu_ptr(trace_percpu_buffer);
|
||||
|
||||
if (!buffer || buffer->nesting >= 4)
|
||||
if (!trace_percpu_buffer || buffer->nesting >= 4)
|
||||
return NULL;
|
||||
|
||||
buffer->nesting++;
|
||||
@@ -3237,7 +3237,7 @@ static void put_trace_buf(void)
|
||||
|
||||
static int alloc_percpu_trace_buffer(void)
|
||||
{
|
||||
struct trace_buffer_struct *buffers;
|
||||
struct trace_buffer_struct __percpu *buffers;
|
||||
|
||||
if (trace_percpu_buffer)
|
||||
return 0;
|
||||
|
||||
@@ -1339,6 +1339,7 @@ batadv_mcast_forw_rtr_node_get(struct batadv_priv *bat_priv,
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
* @skb: The multicast packet to check
|
||||
* @orig: an originator to be set to forward the skb to
|
||||
* @is_routable: stores whether the destination is routable
|
||||
*
|
||||
* Return: the forwarding mode as enum batadv_forw_mode and in case of
|
||||
* BATADV_FORW_SINGLE set the orig to the single originator the skb
|
||||
@@ -1346,17 +1347,16 @@ batadv_mcast_forw_rtr_node_get(struct batadv_priv *bat_priv,
|
||||
*/
|
||||
enum batadv_forw_mode
|
||||
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
||||
struct batadv_orig_node **orig)
|
||||
struct batadv_orig_node **orig, int *is_routable)
|
||||
{
|
||||
int ret, tt_count, ip_count, unsnoop_count, total_count;
|
||||
bool is_unsnoopable = false;
|
||||
unsigned int mcast_fanout;
|
||||
struct ethhdr *ethhdr;
|
||||
int is_routable = 0;
|
||||
int rtr_count = 0;
|
||||
|
||||
ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable,
|
||||
&is_routable);
|
||||
is_routable);
|
||||
if (ret == -ENOMEM)
|
||||
return BATADV_FORW_NONE;
|
||||
else if (ret < 0)
|
||||
@@ -1369,7 +1369,7 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
||||
ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
|
||||
unsnoop_count = !is_unsnoopable ? 0 :
|
||||
atomic_read(&bat_priv->mcast.num_want_all_unsnoopables);
|
||||
rtr_count = batadv_mcast_forw_rtr_count(bat_priv, is_routable);
|
||||
rtr_count = batadv_mcast_forw_rtr_count(bat_priv, *is_routable);
|
||||
|
||||
total_count = tt_count + ip_count + unsnoop_count + rtr_count;
|
||||
|
||||
@@ -1689,6 +1689,7 @@ batadv_mcast_forw_want_rtr(struct batadv_priv *bat_priv,
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
* @skb: the multicast packet to transmit
|
||||
* @vid: the vlan identifier
|
||||
* @is_routable: stores whether the destination is routable
|
||||
*
|
||||
* Sends copies of a frame with multicast destination to any node that signaled
|
||||
* interest in it, that is either via the translation table or the according
|
||||
@@ -1701,7 +1702,7 @@ batadv_mcast_forw_want_rtr(struct batadv_priv *bat_priv,
|
||||
* is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
|
||||
*/
|
||||
int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
||||
unsigned short vid)
|
||||
unsigned short vid, int is_routable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -1717,12 +1718,16 @@ int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!is_routable)
|
||||
goto skip_mc_router;
|
||||
|
||||
ret = batadv_mcast_forw_want_rtr(bat_priv, skb, vid);
|
||||
if (ret != NET_XMIT_SUCCESS) {
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
skip_mc_router:
|
||||
consume_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ enum batadv_forw_mode {
|
||||
|
||||
enum batadv_forw_mode
|
||||
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
||||
struct batadv_orig_node **mcast_single_orig);
|
||||
struct batadv_orig_node **mcast_single_orig,
|
||||
int *is_routable);
|
||||
|
||||
int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
|
||||
struct sk_buff *skb,
|
||||
@@ -51,7 +52,7 @@ int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
|
||||
struct batadv_orig_node *orig_node);
|
||||
|
||||
int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
||||
unsigned short vid);
|
||||
unsigned short vid, int is_routable);
|
||||
|
||||
void batadv_mcast_init(struct batadv_priv *bat_priv);
|
||||
|
||||
@@ -68,7 +69,8 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node);
|
||||
|
||||
static inline enum batadv_forw_mode
|
||||
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
||||
struct batadv_orig_node **mcast_single_orig)
|
||||
struct batadv_orig_node **mcast_single_orig,
|
||||
int *is_routable)
|
||||
{
|
||||
return BATADV_FORW_ALL;
|
||||
}
|
||||
@@ -85,7 +87,7 @@ batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
|
||||
|
||||
static inline int
|
||||
batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
||||
unsigned short vid)
|
||||
unsigned short vid, int is_routable)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
return NET_XMIT_DROP;
|
||||
|
||||
@@ -198,6 +198,7 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
|
||||
int gw_mode;
|
||||
enum batadv_forw_mode forw_mode = BATADV_FORW_SINGLE;
|
||||
struct batadv_orig_node *mcast_single_orig = NULL;
|
||||
int mcast_is_routable = 0;
|
||||
int network_offset = ETH_HLEN;
|
||||
__be16 proto;
|
||||
|
||||
@@ -300,7 +301,8 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
|
||||
send:
|
||||
if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
|
||||
forw_mode = batadv_mcast_forw_mode(bat_priv, skb,
|
||||
&mcast_single_orig);
|
||||
&mcast_single_orig,
|
||||
&mcast_is_routable);
|
||||
if (forw_mode == BATADV_FORW_NONE)
|
||||
goto dropped;
|
||||
|
||||
@@ -359,7 +361,8 @@ send:
|
||||
ret = batadv_mcast_forw_send_orig(bat_priv, skb, vid,
|
||||
mcast_single_orig);
|
||||
} else if (forw_mode == BATADV_FORW_SOME) {
|
||||
ret = batadv_mcast_forw_send(bat_priv, skb, vid);
|
||||
ret = batadv_mcast_forw_send(bat_priv, skb, vid,
|
||||
mcast_is_routable);
|
||||
} else {
|
||||
if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
|
||||
skb))
|
||||
|
||||
@@ -197,6 +197,10 @@ int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining,
|
||||
nla_entype = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
|
||||
|
||||
if (nla_entype) {
|
||||
if (nla_len(nla_entype) < sizeof(u16)) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid RTA_ENCAP_TYPE");
|
||||
return -EINVAL;
|
||||
}
|
||||
encap_type = nla_get_u16(nla_entype);
|
||||
|
||||
if (lwtunnel_valid_encap_type(encap_type,
|
||||
|
||||
@@ -662,6 +662,19 @@ static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining,
|
||||
return nhs;
|
||||
}
|
||||
|
||||
static int fib_gw_from_attr(__be32 *gw, struct nlattr *nla,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (nla_len(nla) < sizeof(*gw)) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid IPv4 address in RTA_GATEWAY");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*gw = nla_get_in_addr(nla);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* only called when fib_nh is integrated into fib_info */
|
||||
static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
|
||||
int remaining, struct fib_config *cfg,
|
||||
@@ -704,7 +717,11 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
|
||||
return -EINVAL;
|
||||
}
|
||||
if (nla) {
|
||||
fib_cfg.fc_gw4 = nla_get_in_addr(nla);
|
||||
ret = fib_gw_from_attr(&fib_cfg.fc_gw4, nla,
|
||||
extack);
|
||||
if (ret)
|
||||
goto errout;
|
||||
|
||||
if (fib_cfg.fc_gw4)
|
||||
fib_cfg.fc_gw_family = AF_INET;
|
||||
} else if (nlav) {
|
||||
@@ -714,10 +731,18 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
|
||||
}
|
||||
|
||||
nla = nla_find(attrs, attrlen, RTA_FLOW);
|
||||
if (nla)
|
||||
if (nla) {
|
||||
if (nla_len(nla) < sizeof(u32)) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid RTA_FLOW");
|
||||
return -EINVAL;
|
||||
}
|
||||
fib_cfg.fc_flow = nla_get_u32(nla);
|
||||
}
|
||||
|
||||
fib_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
|
||||
/* RTA_ENCAP_TYPE length checked in
|
||||
* lwtunnel_valid_encap_type_attr
|
||||
*/
|
||||
nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
|
||||
if (nla)
|
||||
fib_cfg.fc_encap_type = nla_get_u16(nla);
|
||||
@@ -902,6 +927,7 @@ int fib_nh_match(struct net *net, struct fib_config *cfg, struct fib_info *fi,
|
||||
attrlen = rtnh_attrlen(rtnh);
|
||||
if (attrlen > 0) {
|
||||
struct nlattr *nla, *nlav, *attrs = rtnh_attrs(rtnh);
|
||||
int err;
|
||||
|
||||
nla = nla_find(attrs, attrlen, RTA_GATEWAY);
|
||||
nlav = nla_find(attrs, attrlen, RTA_VIA);
|
||||
@@ -912,12 +938,17 @@ int fib_nh_match(struct net *net, struct fib_config *cfg, struct fib_info *fi,
|
||||
}
|
||||
|
||||
if (nla) {
|
||||
__be32 gw;
|
||||
|
||||
err = fib_gw_from_attr(&gw, nla, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (nh->fib_nh_gw_family != AF_INET ||
|
||||
nla_get_in_addr(nla) != nh->fib_nh_gw4)
|
||||
gw != nh->fib_nh_gw4)
|
||||
return 1;
|
||||
} else if (nlav) {
|
||||
struct fib_config cfg2;
|
||||
int err;
|
||||
|
||||
err = fib_gw_from_via(&cfg2, nlav, extack);
|
||||
if (err)
|
||||
@@ -940,8 +971,14 @@ int fib_nh_match(struct net *net, struct fib_config *cfg, struct fib_info *fi,
|
||||
|
||||
#ifdef CONFIG_IP_ROUTE_CLASSID
|
||||
nla = nla_find(attrs, attrlen, RTA_FLOW);
|
||||
if (nla && nla_get_u32(nla) != nh->nh_tclassid)
|
||||
return 1;
|
||||
if (nla) {
|
||||
if (nla_len(nla) < sizeof(u32)) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid RTA_FLOW");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (nla_get_u32(nla) != nh->nh_tclassid)
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include <net/protocol.h>
|
||||
#include <net/raw.h>
|
||||
#include <net/rawv6.h>
|
||||
#include <net/seg6.h>
|
||||
#include <net/transp_v6.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/addrconf.h>
|
||||
@@ -820,6 +821,7 @@ out_bh_enable:
|
||||
|
||||
void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
|
||||
{
|
||||
struct inet6_skb_parm *opt = IP6CB(skb);
|
||||
const struct inet6_protocol *ipprot;
|
||||
int inner_offset;
|
||||
__be16 frag_off;
|
||||
@@ -829,6 +831,8 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
|
||||
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
|
||||
goto out;
|
||||
|
||||
seg6_icmp_srh(skb, opt);
|
||||
|
||||
nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
|
||||
if (ipv6_ext_hdr(nexthdr)) {
|
||||
/* now skip over extension headers */
|
||||
@@ -853,7 +857,7 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
|
||||
|
||||
ipprot = rcu_dereference(inet6_protos[nexthdr]);
|
||||
if (ipprot && ipprot->err_handler)
|
||||
ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
|
||||
ipprot->err_handler(skb, opt, type, code, inner_offset, info);
|
||||
|
||||
raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info);
|
||||
return;
|
||||
|
||||
@@ -5201,6 +5201,19 @@ out:
|
||||
return should_notify;
|
||||
}
|
||||
|
||||
static int fib6_gw_from_attr(struct in6_addr *gw, struct nlattr *nla,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (nla_len(nla) < sizeof(*gw)) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid IPv6 address in RTA_GATEWAY");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*gw = nla_get_in6_addr(nla);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ip6_route_multipath_add(struct fib6_config *cfg,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
@@ -5241,10 +5254,18 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
|
||||
|
||||
nla = nla_find(attrs, attrlen, RTA_GATEWAY);
|
||||
if (nla) {
|
||||
r_cfg.fc_gateway = nla_get_in6_addr(nla);
|
||||
err = fib6_gw_from_attr(&r_cfg.fc_gateway, nla,
|
||||
extack);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
r_cfg.fc_flags |= RTF_GATEWAY;
|
||||
}
|
||||
r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
|
||||
|
||||
/* RTA_ENCAP_TYPE length checked in
|
||||
* lwtunnel_valid_encap_type_attr
|
||||
*/
|
||||
nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
|
||||
if (nla)
|
||||
r_cfg.fc_encap_type = nla_get_u16(nla);
|
||||
@@ -5411,7 +5432,13 @@ static int ip6_route_multipath_del(struct fib6_config *cfg,
|
||||
|
||||
nla = nla_find(attrs, attrlen, RTA_GATEWAY);
|
||||
if (nla) {
|
||||
nla_memcpy(&r_cfg.fc_gateway, nla, 16);
|
||||
err = fib6_gw_from_attr(&r_cfg.fc_gateway, nla,
|
||||
extack);
|
||||
if (err) {
|
||||
last_err = err;
|
||||
goto next_rtnh;
|
||||
}
|
||||
|
||||
r_cfg.fc_flags |= RTF_GATEWAY;
|
||||
}
|
||||
}
|
||||
@@ -5419,6 +5446,7 @@ static int ip6_route_multipath_del(struct fib6_config *cfg,
|
||||
if (err)
|
||||
last_err = err;
|
||||
|
||||
next_rtnh:
|
||||
rtnh = rtnh_next(rtnh, &remaining);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,65 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ipv6_sr_hdr *seg6_get_srh(struct sk_buff *skb, int flags)
|
||||
{
|
||||
struct ipv6_sr_hdr *srh;
|
||||
int len, srhoff = 0;
|
||||
|
||||
if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, &flags) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
|
||||
return NULL;
|
||||
|
||||
srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
|
||||
|
||||
len = (srh->hdrlen + 1) << 3;
|
||||
|
||||
if (!pskb_may_pull(skb, srhoff + len))
|
||||
return NULL;
|
||||
|
||||
/* note that pskb_may_pull may change pointers in header;
|
||||
* for this reason it is necessary to reload them when needed.
|
||||
*/
|
||||
srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
|
||||
|
||||
if (!seg6_validate_srh(srh, len, true))
|
||||
return NULL;
|
||||
|
||||
return srh;
|
||||
}
|
||||
|
||||
/* Determine if an ICMP invoking packet contains a segment routing
|
||||
* header. If it does, extract the offset to the true destination
|
||||
* address, which is in the first segment address.
|
||||
*/
|
||||
void seg6_icmp_srh(struct sk_buff *skb, struct inet6_skb_parm *opt)
|
||||
{
|
||||
__u16 network_header = skb->network_header;
|
||||
struct ipv6_sr_hdr *srh;
|
||||
|
||||
/* Update network header to point to the invoking packet
|
||||
* inside the ICMP packet, so we can use the seg6_get_srh()
|
||||
* helper.
|
||||
*/
|
||||
skb_reset_network_header(skb);
|
||||
|
||||
srh = seg6_get_srh(skb, 0);
|
||||
if (!srh)
|
||||
goto out;
|
||||
|
||||
if (srh->type != IPV6_SRCRT_TYPE_4)
|
||||
goto out;
|
||||
|
||||
opt->flags |= IP6SKB_SEG6;
|
||||
opt->srhoff = (unsigned char *)srh - skb->data;
|
||||
|
||||
out:
|
||||
/* Restore the network header back to the ICMP packet */
|
||||
skb->network_header = network_header;
|
||||
}
|
||||
|
||||
static struct genl_family seg6_genl_family;
|
||||
|
||||
static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
|
||||
|
||||
@@ -150,40 +150,11 @@ static struct seg6_local_lwt *seg6_local_lwtunnel(struct lwtunnel_state *lwt)
|
||||
return (struct seg6_local_lwt *)lwt->data;
|
||||
}
|
||||
|
||||
static struct ipv6_sr_hdr *get_srh(struct sk_buff *skb, int flags)
|
||||
{
|
||||
struct ipv6_sr_hdr *srh;
|
||||
int len, srhoff = 0;
|
||||
|
||||
if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, &flags) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
|
||||
return NULL;
|
||||
|
||||
srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
|
||||
|
||||
len = (srh->hdrlen + 1) << 3;
|
||||
|
||||
if (!pskb_may_pull(skb, srhoff + len))
|
||||
return NULL;
|
||||
|
||||
/* note that pskb_may_pull may change pointers in header;
|
||||
* for this reason it is necessary to reload them when needed.
|
||||
*/
|
||||
srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
|
||||
|
||||
if (!seg6_validate_srh(srh, len, true))
|
||||
return NULL;
|
||||
|
||||
return srh;
|
||||
}
|
||||
|
||||
static struct ipv6_sr_hdr *get_and_validate_srh(struct sk_buff *skb)
|
||||
{
|
||||
struct ipv6_sr_hdr *srh;
|
||||
|
||||
srh = get_srh(skb, IP6_FH_F_SKIP_RH);
|
||||
srh = seg6_get_srh(skb, IP6_FH_F_SKIP_RH);
|
||||
if (!srh)
|
||||
return NULL;
|
||||
|
||||
@@ -200,7 +171,7 @@ static bool decap_and_validate(struct sk_buff *skb, int proto)
|
||||
struct ipv6_sr_hdr *srh;
|
||||
unsigned int off = 0;
|
||||
|
||||
srh = get_srh(skb, 0);
|
||||
srh = seg6_get_srh(skb, 0);
|
||||
if (srh && srh->segments_left > 0)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <net/transp_v6.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/raw.h>
|
||||
#include <net/seg6.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include <net/ip6_tunnel.h>
|
||||
@@ -561,7 +562,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
struct ipv6_pinfo *np;
|
||||
const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
|
||||
const struct in6_addr *saddr = &hdr->saddr;
|
||||
const struct in6_addr *daddr = &hdr->daddr;
|
||||
const struct in6_addr *daddr = seg6_get_daddr(skb, opt) ? : &hdr->daddr;
|
||||
struct udphdr *uh = (struct udphdr *)(skb->data+offset);
|
||||
bool tunnel = false;
|
||||
struct sock *sk;
|
||||
|
||||
@@ -647,6 +647,26 @@ struct mesh_csa_settings {
|
||||
struct cfg80211_csa_settings settings;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mesh_table
|
||||
*
|
||||
* @known_gates: list of known mesh gates and their mpaths by the station. The
|
||||
* gate's mpath may or may not be resolved and active.
|
||||
* @gates_lock: protects updates to known_gates
|
||||
* @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr
|
||||
* @walk_head: linked list containing all mesh_path objects
|
||||
* @walk_lock: lock protecting walk_head
|
||||
* @entries: number of entries in the table
|
||||
*/
|
||||
struct mesh_table {
|
||||
struct hlist_head known_gates;
|
||||
spinlock_t gates_lock;
|
||||
struct rhashtable rhead;
|
||||
struct hlist_head walk_head;
|
||||
spinlock_t walk_lock;
|
||||
atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
|
||||
};
|
||||
|
||||
struct ieee80211_if_mesh {
|
||||
struct timer_list housekeeping_timer;
|
||||
struct timer_list mesh_path_timer;
|
||||
@@ -721,8 +741,8 @@ struct ieee80211_if_mesh {
|
||||
/* offset from skb->data while building IE */
|
||||
int meshconf_offset;
|
||||
|
||||
struct mesh_table *mesh_paths;
|
||||
struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
|
||||
struct mesh_table mesh_paths;
|
||||
struct mesh_table mpp_paths; /* Store paths for MPP&MAP */
|
||||
int mesh_paths_generation;
|
||||
int mpp_paths_generation;
|
||||
};
|
||||
|
||||
@@ -127,26 +127,6 @@ struct mesh_path {
|
||||
u32 path_change_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mesh_table
|
||||
*
|
||||
* @known_gates: list of known mesh gates and their mpaths by the station. The
|
||||
* gate's mpath may or may not be resolved and active.
|
||||
* @gates_lock: protects updates to known_gates
|
||||
* @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr
|
||||
* @walk_head: linked list containing all mesh_path objects
|
||||
* @walk_lock: lock protecting walk_head
|
||||
* @entries: number of entries in the table
|
||||
*/
|
||||
struct mesh_table {
|
||||
struct hlist_head known_gates;
|
||||
spinlock_t gates_lock;
|
||||
struct rhashtable rhead;
|
||||
struct hlist_head walk_head;
|
||||
spinlock_t walk_lock;
|
||||
atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
|
||||
};
|
||||
|
||||
/* Recent multicast cache */
|
||||
/* RMC_BUCKETS must be a power of 2, maximum 256 */
|
||||
#define RMC_BUCKETS 256
|
||||
@@ -308,7 +288,7 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
|
||||
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
|
||||
void mesh_path_flush_pending(struct mesh_path *mpath);
|
||||
void mesh_path_tx_pending(struct mesh_path *mpath);
|
||||
int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr);
|
||||
void mesh_path_timer(struct timer_list *t);
|
||||
|
||||
@@ -47,32 +47,24 @@ static void mesh_path_rht_free(void *ptr, void *tblptr)
|
||||
mesh_path_free_rcu(tbl, mpath);
|
||||
}
|
||||
|
||||
static struct mesh_table *mesh_table_alloc(void)
|
||||
static void mesh_table_init(struct mesh_table *tbl)
|
||||
{
|
||||
struct mesh_table *newtbl;
|
||||
INIT_HLIST_HEAD(&tbl->known_gates);
|
||||
INIT_HLIST_HEAD(&tbl->walk_head);
|
||||
atomic_set(&tbl->entries, 0);
|
||||
spin_lock_init(&tbl->gates_lock);
|
||||
spin_lock_init(&tbl->walk_lock);
|
||||
|
||||
newtbl = kmalloc(sizeof(struct mesh_table), GFP_ATOMIC);
|
||||
if (!newtbl)
|
||||
return NULL;
|
||||
|
||||
INIT_HLIST_HEAD(&newtbl->known_gates);
|
||||
INIT_HLIST_HEAD(&newtbl->walk_head);
|
||||
atomic_set(&newtbl->entries, 0);
|
||||
spin_lock_init(&newtbl->gates_lock);
|
||||
spin_lock_init(&newtbl->walk_lock);
|
||||
if (rhashtable_init(&newtbl->rhead, &mesh_rht_params)) {
|
||||
kfree(newtbl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return newtbl;
|
||||
/* rhashtable_init() may fail only in case of wrong
|
||||
* mesh_rht_params
|
||||
*/
|
||||
WARN_ON(rhashtable_init(&tbl->rhead, &mesh_rht_params));
|
||||
}
|
||||
|
||||
static void mesh_table_free(struct mesh_table *tbl)
|
||||
{
|
||||
rhashtable_free_and_destroy(&tbl->rhead,
|
||||
mesh_path_rht_free, tbl);
|
||||
kfree(tbl);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,13 +230,13 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
|
||||
struct mesh_path *
|
||||
mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
|
||||
{
|
||||
return mpath_lookup(sdata->u.mesh.mesh_paths, dst, sdata);
|
||||
return mpath_lookup(&sdata->u.mesh.mesh_paths, dst, sdata);
|
||||
}
|
||||
|
||||
struct mesh_path *
|
||||
mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
|
||||
{
|
||||
return mpath_lookup(sdata->u.mesh.mpp_paths, dst, sdata);
|
||||
return mpath_lookup(&sdata->u.mesh.mpp_paths, dst, sdata);
|
||||
}
|
||||
|
||||
static struct mesh_path *
|
||||
@@ -281,7 +273,7 @@ __mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx)
|
||||
struct mesh_path *
|
||||
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
|
||||
{
|
||||
return __mesh_path_lookup_by_idx(sdata->u.mesh.mesh_paths, idx);
|
||||
return __mesh_path_lookup_by_idx(&sdata->u.mesh.mesh_paths, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,7 +288,7 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
|
||||
struct mesh_path *
|
||||
mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
|
||||
{
|
||||
return __mesh_path_lookup_by_idx(sdata->u.mesh.mpp_paths, idx);
|
||||
return __mesh_path_lookup_by_idx(&sdata->u.mesh.mpp_paths, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,7 +301,7 @@ int mesh_path_add_gate(struct mesh_path *mpath)
|
||||
int err;
|
||||
|
||||
rcu_read_lock();
|
||||
tbl = mpath->sdata->u.mesh.mesh_paths;
|
||||
tbl = &mpath->sdata->u.mesh.mesh_paths;
|
||||
|
||||
spin_lock_bh(&mpath->state_lock);
|
||||
if (mpath->is_gate) {
|
||||
@@ -418,7 +410,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
|
||||
if (!new_mpath)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
tbl = sdata->u.mesh.mesh_paths;
|
||||
tbl = &sdata->u.mesh.mesh_paths;
|
||||
spin_lock_bh(&tbl->walk_lock);
|
||||
mpath = rhashtable_lookup_get_insert_fast(&tbl->rhead,
|
||||
&new_mpath->rhash,
|
||||
@@ -460,7 +452,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(new_mpath->mpp, mpp, ETH_ALEN);
|
||||
tbl = sdata->u.mesh.mpp_paths;
|
||||
tbl = &sdata->u.mesh.mpp_paths;
|
||||
|
||||
spin_lock_bh(&tbl->walk_lock);
|
||||
ret = rhashtable_lookup_insert_fast(&tbl->rhead,
|
||||
@@ -489,7 +481,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
|
||||
void mesh_plink_broken(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
|
||||
struct mesh_table *tbl = &sdata->u.mesh.mesh_paths;
|
||||
static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
struct mesh_path *mpath;
|
||||
|
||||
@@ -548,7 +540,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath)
|
||||
void mesh_path_flush_by_nexthop(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
|
||||
struct mesh_table *tbl = &sdata->u.mesh.mesh_paths;
|
||||
struct mesh_path *mpath;
|
||||
struct hlist_node *n;
|
||||
|
||||
@@ -563,7 +555,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
|
||||
static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *proxy)
|
||||
{
|
||||
struct mesh_table *tbl = sdata->u.mesh.mpp_paths;
|
||||
struct mesh_table *tbl = &sdata->u.mesh.mpp_paths;
|
||||
struct mesh_path *mpath;
|
||||
struct hlist_node *n;
|
||||
|
||||
@@ -597,8 +589,8 @@ static void table_flush_by_iface(struct mesh_table *tbl)
|
||||
*/
|
||||
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
table_flush_by_iface(sdata->u.mesh.mesh_paths);
|
||||
table_flush_by_iface(sdata->u.mesh.mpp_paths);
|
||||
table_flush_by_iface(&sdata->u.mesh.mesh_paths);
|
||||
table_flush_by_iface(&sdata->u.mesh.mpp_paths);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,7 +636,7 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||
/* flush relevant mpp entries first */
|
||||
mpp_flush_by_proxy(sdata, addr);
|
||||
|
||||
err = table_path_del(sdata->u.mesh.mesh_paths, sdata, addr);
|
||||
err = table_path_del(&sdata->u.mesh.mesh_paths, sdata, addr);
|
||||
sdata->u.mesh.mesh_paths_generation++;
|
||||
return err;
|
||||
}
|
||||
@@ -682,7 +674,7 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
|
||||
struct mesh_path *gate;
|
||||
bool copy = false;
|
||||
|
||||
tbl = sdata->u.mesh.mesh_paths;
|
||||
tbl = &sdata->u.mesh.mesh_paths;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(gate, &tbl->known_gates, gate_list) {
|
||||
@@ -762,29 +754,10 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop)
|
||||
mesh_path_tx_pending(mpath);
|
||||
}
|
||||
|
||||
int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata)
|
||||
void mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct mesh_table *tbl_path, *tbl_mpp;
|
||||
int ret;
|
||||
|
||||
tbl_path = mesh_table_alloc();
|
||||
if (!tbl_path)
|
||||
return -ENOMEM;
|
||||
|
||||
tbl_mpp = mesh_table_alloc();
|
||||
if (!tbl_mpp) {
|
||||
ret = -ENOMEM;
|
||||
goto free_path;
|
||||
}
|
||||
|
||||
sdata->u.mesh.mesh_paths = tbl_path;
|
||||
sdata->u.mesh.mpp_paths = tbl_mpp;
|
||||
|
||||
return 0;
|
||||
|
||||
free_path:
|
||||
mesh_table_free(tbl_path);
|
||||
return ret;
|
||||
mesh_table_init(&sdata->u.mesh.mesh_paths);
|
||||
mesh_table_init(&sdata->u.mesh.mpp_paths);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -806,12 +779,12 @@ void mesh_path_tbl_expire(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
mesh_path_tbl_expire(sdata, sdata->u.mesh.mesh_paths);
|
||||
mesh_path_tbl_expire(sdata, sdata->u.mesh.mpp_paths);
|
||||
mesh_path_tbl_expire(sdata, &sdata->u.mesh.mesh_paths);
|
||||
mesh_path_tbl_expire(sdata, &sdata->u.mesh.mpp_paths);
|
||||
}
|
||||
|
||||
void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
mesh_table_free(sdata->u.mesh.mesh_paths);
|
||||
mesh_table_free(sdata->u.mesh.mpp_paths);
|
||||
mesh_table_free(&sdata->u.mesh.mesh_paths);
|
||||
mesh_table_free(&sdata->u.mesh.mpp_paths);
|
||||
}
|
||||
|
||||
@@ -5265,7 +5265,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
if (new_sta) {
|
||||
u32 rates = 0, basic_rates = 0;
|
||||
bool have_higher_than_11mbit;
|
||||
bool have_higher_than_11mbit = false;
|
||||
int min_rate = INT_MAX, min_rate_index = -1;
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
int shift = ieee80211_vif_get_shift(&sdata->vif);
|
||||
|
||||
@@ -85,8 +85,8 @@ void mctp_neigh_remove_dev(struct mctp_dev *mdev)
|
||||
mutex_unlock(&net->mctp.neigh_lock);
|
||||
}
|
||||
|
||||
// TODO: add a "source" flag so netlink can only delete static neighbours?
|
||||
static int mctp_neigh_remove(struct mctp_dev *mdev, mctp_eid_t eid)
|
||||
static int mctp_neigh_remove(struct mctp_dev *mdev, mctp_eid_t eid,
|
||||
enum mctp_neigh_source source)
|
||||
{
|
||||
struct net *net = dev_net(mdev->dev);
|
||||
struct mctp_neigh *neigh, *tmp;
|
||||
@@ -94,7 +94,8 @@ static int mctp_neigh_remove(struct mctp_dev *mdev, mctp_eid_t eid)
|
||||
|
||||
mutex_lock(&net->mctp.neigh_lock);
|
||||
list_for_each_entry_safe(neigh, tmp, &net->mctp.neighbours, list) {
|
||||
if (neigh->dev == mdev && neigh->eid == eid) {
|
||||
if (neigh->dev == mdev && neigh->eid == eid &&
|
||||
neigh->source == source) {
|
||||
list_del_rcu(&neigh->list);
|
||||
/* TODO: immediate RTM_DELNEIGH */
|
||||
call_rcu(&neigh->rcu, __mctp_neigh_free);
|
||||
@@ -202,7 +203,7 @@ static int mctp_rtm_delneigh(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
if (!mdev)
|
||||
return -ENODEV;
|
||||
|
||||
return mctp_neigh_remove(mdev, eid);
|
||||
return mctp_neigh_remove(mdev, eid, MCTP_NEIGH_STATIC);
|
||||
}
|
||||
|
||||
static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
||||
|
||||
@@ -306,7 +306,7 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
|
||||
if (optlen < sizeof(unsigned int))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_sockptr(&opt, optval, sizeof(unsigned int)))
|
||||
if (copy_from_sockptr(&opt, optval, sizeof(unsigned long)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (optname) {
|
||||
|
||||
@@ -1421,10 +1421,8 @@ static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (qdisc_dev(sch)->tx_queue_len + 1 > QFQ_MAX_AGG_CLASSES)
|
||||
max_classes = QFQ_MAX_AGG_CLASSES;
|
||||
else
|
||||
max_classes = qdisc_dev(sch)->tx_queue_len + 1;
|
||||
max_classes = min_t(u64, (u64)qdisc_dev(sch)->tx_queue_len + 1,
|
||||
QFQ_MAX_AGG_CLASSES);
|
||||
/* max_cl_shift = floor(log_2(max_classes)) */
|
||||
max_cl_shift = __fls(max_classes);
|
||||
q->max_agg_classes = 1<<max_cl_shift;
|
||||
|
||||
@@ -245,48 +245,44 @@ static size_t inet_assoc_attr_size(struct sctp_association *asoc)
|
||||
+ 64;
|
||||
}
|
||||
|
||||
static int sctp_tsp_dump_one(struct sctp_transport *tsp, void *p)
|
||||
static int sctp_sock_dump_one(struct sctp_endpoint *ep, struct sctp_transport *tsp, void *p)
|
||||
{
|
||||
struct sctp_association *assoc = tsp->asoc;
|
||||
struct sock *sk = tsp->asoc->base.sk;
|
||||
struct sctp_comm_param *commp = p;
|
||||
struct sk_buff *in_skb = commp->skb;
|
||||
struct sock *sk = ep->base.sk;
|
||||
const struct inet_diag_req_v2 *req = commp->r;
|
||||
const struct nlmsghdr *nlh = commp->nlh;
|
||||
struct net *net = sock_net(in_skb->sk);
|
||||
struct sk_buff *skb = commp->skb;
|
||||
struct sk_buff *rep;
|
||||
int err;
|
||||
|
||||
err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
|
||||
if (err)
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
err = -ENOMEM;
|
||||
rep = nlmsg_new(inet_assoc_attr_size(assoc), GFP_KERNEL);
|
||||
if (!rep)
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
|
||||
lock_sock(sk);
|
||||
if (sk != assoc->base.sk) {
|
||||
release_sock(sk);
|
||||
sk = assoc->base.sk;
|
||||
lock_sock(sk);
|
||||
}
|
||||
err = inet_sctp_diag_fill(sk, assoc, rep, req,
|
||||
sk_user_ns(NETLINK_CB(in_skb).sk),
|
||||
NETLINK_CB(in_skb).portid,
|
||||
nlh->nlmsg_seq, 0, nlh,
|
||||
commp->net_admin);
|
||||
release_sock(sk);
|
||||
if (err < 0) {
|
||||
WARN_ON(err == -EMSGSIZE);
|
||||
kfree_skb(rep);
|
||||
if (ep != assoc->ep) {
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid);
|
||||
err = inet_sctp_diag_fill(sk, assoc, rep, req, sk_user_ns(NETLINK_CB(skb).sk),
|
||||
NETLINK_CB(skb).portid, commp->nlh->nlmsg_seq, 0,
|
||||
commp->nlh, commp->net_admin);
|
||||
if (err < 0) {
|
||||
WARN_ON(err == -EMSGSIZE);
|
||||
goto out;
|
||||
}
|
||||
release_sock(sk);
|
||||
|
||||
return nlmsg_unicast(sock_net(skb->sk)->diag_nlsk, rep, NETLINK_CB(skb).portid);
|
||||
|
||||
out:
|
||||
release_sock(sk);
|
||||
kfree_skb(rep);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -429,15 +425,15 @@ static void sctp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
|
||||
static int sctp_diag_dump_one(struct netlink_callback *cb,
|
||||
const struct inet_diag_req_v2 *req)
|
||||
{
|
||||
struct sk_buff *in_skb = cb->skb;
|
||||
struct net *net = sock_net(in_skb->sk);
|
||||
struct sk_buff *skb = cb->skb;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
const struct nlmsghdr *nlh = cb->nlh;
|
||||
union sctp_addr laddr, paddr;
|
||||
struct sctp_comm_param commp = {
|
||||
.skb = in_skb,
|
||||
.skb = skb,
|
||||
.r = req,
|
||||
.nlh = nlh,
|
||||
.net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN),
|
||||
.net_admin = netlink_net_capable(skb, CAP_NET_ADMIN),
|
||||
};
|
||||
|
||||
if (req->sdiag_family == AF_INET) {
|
||||
@@ -460,7 +456,7 @@ static int sctp_diag_dump_one(struct netlink_callback *cb,
|
||||
paddr.v6.sin6_family = AF_INET6;
|
||||
}
|
||||
|
||||
return sctp_transport_lookup_process(sctp_tsp_dump_one,
|
||||
return sctp_transport_lookup_process(sctp_sock_dump_one,
|
||||
net, &laddr, &paddr, &commp);
|
||||
}
|
||||
|
||||
|
||||
@@ -5317,23 +5317,31 @@ int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *),
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sctp_for_each_endpoint);
|
||||
|
||||
int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
|
||||
struct net *net,
|
||||
int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net,
|
||||
const union sctp_addr *laddr,
|
||||
const union sctp_addr *paddr, void *p)
|
||||
{
|
||||
struct sctp_transport *transport;
|
||||
int err;
|
||||
struct sctp_endpoint *ep;
|
||||
int err = -ENOENT;
|
||||
|
||||
rcu_read_lock();
|
||||
transport = sctp_addrs_lookup_transport(net, laddr, paddr);
|
||||
if (!transport) {
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
ep = transport->asoc->ep;
|
||||
if (!sctp_endpoint_hold(ep)) { /* asoc can be peeled off */
|
||||
sctp_transport_put(transport);
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (!transport)
|
||||
return -ENOENT;
|
||||
|
||||
err = cb(transport, p);
|
||||
err = cb(ep, transport, p);
|
||||
sctp_endpoint_put(ep);
|
||||
sctp_transport_put(transport);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sctp_transport_lookup_process);
|
||||
|
||||
@@ -1461,6 +1461,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
|
||||
msg_set_syn(hdr, 1);
|
||||
}
|
||||
|
||||
memset(&skaddr, 0, sizeof(skaddr));
|
||||
|
||||
/* Determine destination */
|
||||
if (atype == TIPC_SERVICE_RANGE) {
|
||||
return tipc_sendmcast(sock, ua, m, dlen, timeout);
|
||||
|
||||
@@ -677,6 +677,8 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock,
|
||||
struct xdp_sock *xs = xdp_sk(sk);
|
||||
struct xsk_buff_pool *pool;
|
||||
|
||||
sock_poll_wait(file, sock, wait);
|
||||
|
||||
if (unlikely(!xsk_is_bound(xs)))
|
||||
return mask;
|
||||
|
||||
@@ -688,8 +690,6 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock,
|
||||
else
|
||||
/* Poll needs to drive Tx also in copy mode */
|
||||
__xsk_sendmsg(sk);
|
||||
} else {
|
||||
sock_poll_wait(file, sock, wait);
|
||||
}
|
||||
|
||||
if (xs->rx && !xskq_prod_is_empty(xs->rx))
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
extern void my_direct_func1(void);
|
||||
extern void my_direct_func2(void);
|
||||
|
||||
void my_direct_func1(void)
|
||||
{
|
||||
trace_printk("my direct func1\n");
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
extern void my_direct_func1(unsigned long ip);
|
||||
extern void my_direct_func2(unsigned long ip);
|
||||
|
||||
void my_direct_func1(unsigned long ip)
|
||||
{
|
||||
trace_printk("my direct func1 ip %lx\n", ip);
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
extern void my_direct_func(struct vm_area_struct *vma,
|
||||
unsigned long address, unsigned int flags);
|
||||
|
||||
void my_direct_func(struct vm_area_struct *vma,
|
||||
unsigned long address, unsigned int flags)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
extern void my_direct_func(struct task_struct *p);
|
||||
|
||||
void my_direct_func(struct task_struct *p)
|
||||
{
|
||||
trace_printk("waking up %s-%d\n", p->comm, p->pid);
|
||||
|
||||
@@ -1078,7 +1078,7 @@
|
||||
.errstr_unpriv = "R0 pointer -= pointer prohibited",
|
||||
},
|
||||
{
|
||||
"map access: trying to leak tained dst reg",
|
||||
"map access: trying to leak tainted dst reg",
|
||||
.insns = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
|
||||
0
tools/testing/selftests/net/amt.sh
Normal file → Executable file
0
tools/testing/selftests/net/amt.sh
Normal file → Executable file
@@ -193,7 +193,8 @@ for family in 4 6; do
|
||||
SUFFIX="64 nodad"
|
||||
VXDEV=vxlan6
|
||||
IPT=ip6tables
|
||||
PING="ping6"
|
||||
# Use ping6 on systems where ping doesn't handle IPv6
|
||||
ping -w 1 -c 1 ::1 > /dev/null 2>&1 || PING="ping6"
|
||||
fi
|
||||
|
||||
echo "IPv$family"
|
||||
|
||||
Reference in New Issue
Block a user