Description:
Unsigned integer.
- Write a number ranging from 1 to 127 to add a qmap mux
+ Write a number ranging from 1 to 254 to add a qmap mux
based network device, supported by recent Qualcomm based
modems.
Description:
Unsigned integer.
- Write a number ranging from 1 to 127 to delete a previously
+ Write a number ranging from 1 to 254 to delete a previously
created qmap mux based network device.
in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks)
Default: 100
+tcp_rx_skb_cache - BOOLEAN
+ Controls a per TCP socket cache of one skb, that might help
+ performance of some workloads. This might be dangerous
+ on systems with a lot of TCP sockets, since it increases
+ memory usage.
+
+ Default: 0 (disabled)
+
UDP variables:
udp_l3mdev_accept - BOOLEAN
a common (to all paths) part, and a per-path struct rds_conn_path. All
I/O workqs and reconnect threads are driven from the rds_conn_path.
Transports such as TCP that are multipath capable may then set up a
- TPC socket per rds_conn_path, and this is managed by the transport via
+ TCP socket per rds_conn_path, and this is managed by the transport via
the transport privatee cp_transport_data pointer.
Transports announce themselves as multipath capable by setting the
obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
-obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek.o
-realtek-objs := realtek-smi.o rtl8366.o rtl8366rb.o
+obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
+realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
int i;
for (i = 0; i < dev->mib_port_cnt; i++) {
+ if (dsa_is_unused_port(dev->ds, i))
+ continue;
+
p = &dev->ports[i];
mib = &p->mib;
mutex_lock(&mib->cnt_mutex);
#include <linux/bitops.h>
#include <linux/if_bridge.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
#define REALTEK_SMI_ACK_RETRY_COUNT 5
#define REALTEK_SMI_HW_STOP_DELAY 25 /* msecs */
#include <linux/if_bridge.h>
#include <net/dsa.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used)
{
struct rtl8366_vlan_4k vlan4k;
int ret;
- if (!smi->ops->is_vlan_valid(smi, port))
+ /* Use VLAN nr port + 1 since VLAN0 is not valid */
+ if (!smi->ops->is_vlan_valid(smi, port + 1))
return -EINVAL;
dev_info(smi->dev, "%s filtering on port %d\n",
* The hardware support filter ID (FID) 0..7, I have no clue how to
* support this in the driver when the callback only says on/off.
*/
- ret = smi->ops->get_vlan_4k(smi, port, &vlan4k);
+ ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k);
if (ret)
return ret;
/* Just set the filter to FID 1 for now then */
- ret = rtl8366_set_vlan(smi, port,
+ ret = rtl8366_set_vlan(smi, port + 1,
vlan4k.member,
vlan4k.untag,
1);
#include <linux/of_irq.h>
#include <linux/regmap.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
#define RTL8366RB_PORT_NUM_CPU 5
#define RTL8366RB_NUM_PORTS 6
}
/* Find tcam entry with matched pair <vid,port> */
-static int mvpp2_prs_vid_range_find(struct mvpp2 *priv, int pmap, u16 vid,
- u16 mask)
+static int mvpp2_prs_vid_range_find(struct mvpp2_port *port, u16 vid, u16 mask)
{
unsigned char byte[2], enable[2];
struct mvpp2_prs_entry pe;
int tid;
/* Go through the all entries with MVPP2_PRS_LU_VID */
- for (tid = MVPP2_PE_VID_FILT_RANGE_START;
- tid <= MVPP2_PE_VID_FILT_RANGE_END; tid++) {
- if (!priv->prs_shadow[tid].valid ||
- priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
+ for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
+ tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
+ if (!port->priv->prs_shadow[tid].valid ||
+ port->priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid);
+ mvpp2_prs_init_from_hw(port->priv, &pe, tid);
mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
memset(&pe, 0, sizeof(pe));
/* Scan TCAM and see if entry with this <vid,port> already exist */
- tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, mask);
+ tid = mvpp2_prs_vid_range_find(port, vid, mask);
reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
if (reg_val & MVPP2_DSA_EXTENDED)
int tid;
/* Scan TCAM and see if entry with this <vid,port> already exist */
- tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, 0xfff);
+ tid = mvpp2_prs_vid_range_find(port, vid, 0xfff);
/* No such entry */
if (tid < 0)
for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
- if (priv->prs_shadow[tid].valid)
- mvpp2_prs_vid_entry_remove(port, tid);
+ if (priv->prs_shadow[tid].valid) {
+ mvpp2_prs_hw_inv(priv, tid);
+ priv->prs_shadow[tid].valid = false;
+ }
}
}
MLXSW_REG_ZERO(spaft, payload);
mlxsw_reg_spaft_local_port_set(payload, local_port);
mlxsw_reg_spaft_allow_untagged_set(payload, allow_untagged);
- mlxsw_reg_spaft_allow_prio_tagged_set(payload, true);
+ mlxsw_reg_spaft_allow_prio_tagged_set(payload, allow_untagged);
mlxsw_reg_spaft_allow_tagged_set(payload, true);
}
}
}
+#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe
+
static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
{
char slcr_pl[MLXSW_REG_SLCR_LEN];
u32 seed;
int err;
- seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0);
+ seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac),
+ MLXSW_SP_LAG_SEED_INIT);
mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC |
MLXSW_REG_SLCR_LAG_HASH_DMAC |
MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE |
MLXSW_SP1_SB_PR_CPU_SIZE, true, false),
};
-#define MLXSW_SP2_SB_PR_INGRESS_SIZE 40960000
-#define MLXSW_SP2_SB_PR_EGRESS_SIZE 40960000
+#define MLXSW_SP2_SB_PR_INGRESS_SIZE 38128752
+#define MLXSW_SP2_SB_PR_EGRESS_SIZE 38128752
#define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000)
/* Order according to mlxsw_sp2_sb_pool_dess */
match.mask->tos & 0x3);
mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_IP_DSCP,
- match.key->tos >> 6,
- match.mask->tos >> 6);
+ match.key->tos >> 2,
+ match.mask->tos >> 2);
return 0;
}
static void
mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
- bool removing);
+ bool removing, bool dead);
static enum mlxsw_reg_rauht_op mlxsw_sp_rauht_op(bool adding)
{
memcpy(neigh_entry->ha, ha, ETH_ALEN);
mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, entry_connected);
- mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected);
+ mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected,
+ dead);
if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list))
mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
nh->update = 1;
}
+static int
+mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_neigh_entry *neigh_entry)
+{
+ struct neighbour *n, *old_n = neigh_entry->key.n;
+ struct mlxsw_sp_nexthop *nh;
+ bool entry_connected;
+ u8 nud_state, dead;
+ int err;
+
+ nh = list_first_entry(&neigh_entry->nexthop_list,
+ struct mlxsw_sp_nexthop, neigh_list_node);
+
+ n = neigh_lookup(nh->nh_grp->neigh_tbl, &nh->gw_addr, nh->rif->dev);
+ if (!n) {
+ n = neigh_create(nh->nh_grp->neigh_tbl, &nh->gw_addr,
+ nh->rif->dev);
+ if (IS_ERR(n))
+ return PTR_ERR(n);
+ neigh_event_send(n, NULL);
+ }
+
+ mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
+ neigh_entry->key.n = n;
+ err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
+ if (err)
+ goto err_neigh_entry_insert;
+
+ read_lock_bh(&n->lock);
+ nud_state = n->nud_state;
+ dead = n->dead;
+ read_unlock_bh(&n->lock);
+ entry_connected = nud_state & NUD_VALID && !dead;
+
+ list_for_each_entry(nh, &neigh_entry->nexthop_list,
+ neigh_list_node) {
+ neigh_release(old_n);
+ neigh_clone(n);
+ __mlxsw_sp_nexthop_neigh_update(nh, !entry_connected);
+ mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
+ }
+
+ neigh_release(n);
+
+ return 0;
+
+err_neigh_entry_insert:
+ neigh_entry->key.n = old_n;
+ mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
+ neigh_release(n);
+ return err;
+}
+
static void
mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
- bool removing)
+ bool removing, bool dead)
{
struct mlxsw_sp_nexthop *nh;
+ if (list_empty(&neigh_entry->nexthop_list))
+ return;
+
+ if (dead) {
+ int err;
+
+ err = mlxsw_sp_nexthop_dead_neigh_replace(mlxsw_sp,
+ neigh_entry);
+ if (err)
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to replace dead neigh\n");
+ return;
+ }
+
list_for_each_entry(nh, &neigh_entry->nexthop_list,
neigh_list_node) {
__mlxsw_sp_nexthop_neigh_update(nh, removing);
u8 zero_vni[3] = { 0 };
u8 *vni = zero_vni;
- if (skb->len < GENEVE_BASE_HLEN)
+ if (!pskb_may_pull(skb, skb_transport_offset(skb) + GENEVE_BASE_HLEN))
return -EINVAL;
geneveh = geneve_hdr(skb);
.probe = netvsc_probe,
.remove = netvsc_remove,
.driver = {
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .probe_type = PROBE_FORCE_SYNCHRONOUS,
},
};
#include <linux/usb/cdc.h>
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc-wdm.h>
+#include <linux/u64_stats_sync.h>
/* This driver supports wwan (3G/LTE/?) devices using a vendor
* specific management protocol called Qualcomm MSM Interface (QMI) -
struct qmimux_priv {
struct net_device *real_dev;
u8 mux_id;
+ struct pcpu_sw_netstats __percpu *stats64;
};
static int qmimux_open(struct net_device *dev)
struct qmimux_priv *priv = netdev_priv(dev);
unsigned int len = skb->len;
struct qmimux_hdr *hdr;
+ netdev_tx_t ret;
hdr = skb_push(skb, sizeof(struct qmimux_hdr));
hdr->pad = 0;
hdr->mux_id = priv->mux_id;
hdr->pkt_len = cpu_to_be16(len);
skb->dev = priv->real_dev;
- return dev_queue_xmit(skb);
+ ret = dev_queue_xmit(skb);
+
+ if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
+ struct pcpu_sw_netstats *stats64 = this_cpu_ptr(priv->stats64);
+
+ u64_stats_update_begin(&stats64->syncp);
+ stats64->tx_packets++;
+ stats64->tx_bytes += len;
+ u64_stats_update_end(&stats64->syncp);
+ } else {
+ dev->stats.tx_dropped++;
+ }
+
+ return ret;
+}
+
+static void qmimux_get_stats64(struct net_device *net,
+ struct rtnl_link_stats64 *stats)
+{
+ struct qmimux_priv *priv = netdev_priv(net);
+ unsigned int start;
+ int cpu;
+
+ netdev_stats_to_stats64(stats, &net->stats);
+
+ for_each_possible_cpu(cpu) {
+ struct pcpu_sw_netstats *stats64;
+ u64 rx_packets, rx_bytes;
+ u64 tx_packets, tx_bytes;
+
+ stats64 = per_cpu_ptr(priv->stats64, cpu);
+
+ do {
+ start = u64_stats_fetch_begin_irq(&stats64->syncp);
+ rx_packets = stats64->rx_packets;
+ rx_bytes = stats64->rx_bytes;
+ tx_packets = stats64->tx_packets;
+ tx_bytes = stats64->tx_bytes;
+ } while (u64_stats_fetch_retry_irq(&stats64->syncp, start));
+
+ stats->rx_packets += rx_packets;
+ stats->rx_bytes += rx_bytes;
+ stats->tx_packets += tx_packets;
+ stats->tx_bytes += tx_bytes;
+ }
}
static const struct net_device_ops qmimux_netdev_ops = {
- .ndo_open = qmimux_open,
- .ndo_stop = qmimux_stop,
- .ndo_start_xmit = qmimux_start_xmit,
+ .ndo_open = qmimux_open,
+ .ndo_stop = qmimux_stop,
+ .ndo_start_xmit = qmimux_start_xmit,
+ .ndo_get_stats64 = qmimux_get_stats64,
};
static void qmimux_setup(struct net_device *dev)
static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- unsigned int len, offset = 0;
+ unsigned int len, offset = 0, pad_len, pkt_len;
struct qmimux_hdr *hdr;
struct net_device *net;
struct sk_buff *skbn;
if (hdr->pad & 0x80)
goto skip;
+ /* extract padding length and check for valid length info */
+ pad_len = hdr->pad & 0x3f;
+ if (len == 0 || pad_len >= len)
+ goto skip;
+ pkt_len = len - pad_len;
+
net = qmimux_find_dev(dev, hdr->mux_id);
if (!net)
goto skip;
- skbn = netdev_alloc_skb(net, len);
+ skbn = netdev_alloc_skb(net, pkt_len);
if (!skbn)
return 0;
skbn->dev = net;
goto skip;
}
- skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, len);
- if (netif_rx(skbn) != NET_RX_SUCCESS)
+ skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, pkt_len);
+ if (netif_rx(skbn) != NET_RX_SUCCESS) {
+ net->stats.rx_errors++;
return 0;
+ } else {
+ struct pcpu_sw_netstats *stats64;
+ struct qmimux_priv *priv = netdev_priv(net);
+
+ stats64 = this_cpu_ptr(priv->stats64);
+ u64_stats_update_begin(&stats64->syncp);
+ stats64->rx_packets++;
+ stats64->rx_bytes += pkt_len;
+ u64_stats_update_end(&stats64->syncp);
+ }
skip:
offset += len + qmimux_hdr_sz;
priv->mux_id = mux_id;
priv->real_dev = real_dev;
+ priv->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+ if (!priv->stats64) {
+ err = -ENOBUFS;
+ goto out_free_newdev;
+ }
+
err = register_netdevice(new_dev);
if (err < 0)
goto out_free_newdev;
return err;
}
-static void qmimux_unregister_device(struct net_device *dev)
+static void qmimux_unregister_device(struct net_device *dev,
+ struct list_head *head)
{
struct qmimux_priv *priv = netdev_priv(dev);
struct net_device *real_dev = priv->real_dev;
+ free_percpu(priv->stats64);
netdev_upper_dev_unlink(real_dev, dev);
- unregister_netdevice(dev);
+ unregister_netdevice_queue(dev, head);
/* Get rid of the reference to real_dev */
dev_put(real_dev);
if (kstrtou8(buf, 0, &mux_id))
return -EINVAL;
- /* mux_id [1 - 0x7f] range empirically found */
- if (mux_id < 1 || mux_id > 0x7f)
+ /* mux_id [1 - 254] for compatibility with ip(8) and the rmnet driver */
+ if (mux_id < 1 || mux_id > 254)
return -EINVAL;
if (!rtnl_trylock())
ret = -EINVAL;
goto err;
}
- qmimux_unregister_device(del_dev);
+ qmimux_unregister_device(del_dev, NULL);
if (!qmimux_has_slaves(dev))
info->flags &= ~QMI_WWAN_FLAG_MUX;
struct qmi_wwan_state *info;
struct list_head *iter;
struct net_device *ldev;
+ LIST_HEAD(list);
/* called twice if separate control and data intf */
if (!dev)
}
rcu_read_lock();
netdev_for_each_upper_dev_rcu(dev->net, ldev, iter)
- qmimux_unregister_device(ldev);
+ qmimux_unregister_device(ldev, &list);
rcu_read_unlock();
+ unregister_netdevice_many(&list);
rtnl_unlock();
info->flags &= ~QMI_WWAN_FLAG_MUX;
}
struct vxlanhdr *hdr;
__be32 vni;
- if (skb->len < VXLAN_HLEN)
+ if (!pskb_may_pull(skb, skb_transport_offset(skb) + VXLAN_HLEN))
return -EINVAL;
hdr = vxlan_hdr(skb);
break;
case HWSIM_REGTEST_STRICT_ALL:
param.reg_strict = true;
+ /* fall through */
case HWSIM_REGTEST_DRIVER_REG_ALL:
param.reg_alpha2 = hwsim_alpha2s[0];
break;
void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr);
extern int sysctl_unprivileged_bpf_disabled;
-extern int sysctl_bpf_stats_enabled;
int bpf_map_new_fd(struct bpf_map *map, int flags);
int bpf_prog_new_fd(struct bpf_prog *prog);
* @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
* @state: a pointer to a &struct phylink_link_state.
*
+ * Note - not all members of @state are valid. In particular,
+ * @state->lp_advertising, @state->link, @state->an_complete are never
+ * guaranteed to be correct, and so any mac_config() implementation must
+ * never reference these fields.
+ *
* The action performed depends on the currently selected mode:
*
* %MLO_AN_FIXED, %MLO_AN_PHY:
* Configure the specified @state->speed, @state->duplex and
- * @state->pause (%MLO_PAUSE_TX / %MLO_PAUSE_RX) mode.
+ * @state->pause (%MLO_PAUSE_TX / %MLO_PAUSE_RX) modes over a link
+ * specified by @state->interface. @state->advertising may be used,
+ * but is not required. Other members of @state must be ignored.
+ *
+ * Valid state members: interface, speed, duplex, pause, advertising.
*
* %MLO_AN_INBAND:
* place the link in an inband negotiation mode (such as 802.3z
* responsible for reading the configuration word and configuring
* itself accordingly.
*
+ * Valid state members: interface, an_enabled, pause, advertising.
+ *
* Implementations are expected to update the MAC to reflect the
* requested settings - i.o.w., if nothing has changed between two
* calls, no action is expected. If only flow control settings have
void __user *, size_t *, loff_t *);
extern int proc_do_large_bitmap(struct ctl_table *, int,
void __user *, size_t *, loff_t *);
+extern int proc_do_static_key(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos);
/*
* Register a set of sysctl names by calling register_sysctl_table
}
/**
+ * __in6_dev_stats_get - get inet6_dev pointer for stats
+ * @dev: network device
+ * @skb: skb for original incoming interface if neeeded
+ *
+ * Caller must hold rcu_read_lock or RTNL, because this function
+ * does not take a reference on the inet6_dev.
+ */
+static inline struct inet6_dev *__in6_dev_stats_get(const struct net_device *dev,
+ const struct sk_buff *skb)
+{
+ if (netif_is_l3_master(dev))
+ dev = dev_get_by_index_rcu(dev_net(dev), inet6_iif(skb));
+ return __in6_dev_get(dev);
+}
+
+/**
* __in6_dev_get_safely - get inet6_dev pointer from netdevice
* @dev: network device
*
* on wiphy_new(), but can be changed by the driver if it has a good
* reason to override the default
* @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
- * on a VLAN interface)
+ * on a VLAN interface). This flag also serves an extra purpose of
+ * supporting 4ADDR AP mode on devices which do not support AP/VLAN iftype.
* @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
* @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
* control port protocol ethertype. The device also honours the
struct flow_dissector_key_vlan {
u16 vlan_id:12,
+ vlan_dei:1,
vlan_priority:3;
__be16 vlan_tpid;
};
__sk_mem_reclaim(sk, 1 << 20);
}
+DECLARE_STATIC_KEY_FALSE(tcp_tx_skb_cache_key);
static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
{
sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
sk->sk_wmem_queued -= skb->truesize;
sk_mem_uncharge(sk, skb->truesize);
- if (!sk->sk_tx_skb_cache && !skb_cloned(skb)) {
+ if (static_branch_unlikely(&tcp_tx_skb_cache_key) &&
+ !sk->sk_tx_skb_cache && !skb_cloned(skb)) {
skb_zcopy_clear(skb, true);
sk->sk_tx_skb_cache = skb;
return;
* This routine must be called with interrupts disabled or with the socket
* locked so that the sk_buff queue operation is ok.
*/
+DECLARE_STATIC_KEY_FALSE(tcp_rx_skb_cache_key);
static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb)
{
__skb_unlink(skb, &sk->sk_receive_queue);
- if (
-#ifdef CONFIG_RPS
- !static_branch_unlikely(&rps_needed) &&
-#endif
+ if (static_branch_unlikely(&tcp_rx_skb_cache_key) &&
!sk->sk_rx_skb_cache) {
sk->sk_rx_skb_cache = skb;
skb_orphan(skb);
extern __u32 sysctl_wmem_default;
extern __u32 sysctl_rmem_default;
+DECLARE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key);
+
static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto)
{
/* Does this proto have per netns sysctl_wmem ? */
DEFINE_STATIC_KEY_FALSE(bpf_stats_enabled_key);
EXPORT_SYMBOL(bpf_stats_enabled_key);
-int sysctl_bpf_stats_enabled __read_mostly;
/* All definitions of tracepoints related to BPF. */
#define CREATE_TRACE_POINTS
#endif
static int proc_dopipe_max_size(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
-#ifdef CONFIG_BPF_SYSCALL
-static int proc_dointvec_minmax_bpf_stats(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp,
- loff_t *ppos);
-#endif
#ifdef CONFIG_MAGIC_SYSRQ
/* Note: sysrq code uses its own private copy */
},
{
.procname = "bpf_stats_enabled",
- .data = &sysctl_bpf_stats_enabled,
- .maxlen = sizeof(sysctl_bpf_stats_enabled),
+ .data = &bpf_stats_enabled_key.key,
+ .maxlen = sizeof(bpf_stats_enabled_key),
.mode = 0644,
- .proc_handler = proc_dointvec_minmax_bpf_stats,
- .extra1 = &zero,
- .extra2 = &one,
+ .proc_handler = proc_do_static_key,
},
#endif
#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
#endif /* CONFIG_PROC_SYSCTL */
-#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_SYSCTL)
-static int proc_dointvec_minmax_bpf_stats(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp,
- loff_t *ppos)
+#if defined(CONFIG_SYSCTL)
+int proc_do_static_key(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
{
- int ret, bpf_stats = *(int *)table->data;
- struct ctl_table tmp = *table;
+ struct static_key *key = (struct static_key *)table->data;
+ static DEFINE_MUTEX(static_key_mutex);
+ int val, ret;
+ struct ctl_table tmp = {
+ .data = &val,
+ .maxlen = sizeof(val),
+ .mode = table->mode,
+ .extra1 = &zero,
+ .extra2 = &one,
+ };
if (write && !capable(CAP_SYS_ADMIN))
return -EPERM;
- tmp.data = &bpf_stats;
+ mutex_lock(&static_key_mutex);
+ val = static_key_enabled(key);
ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
if (write && !ret) {
- *(int *)table->data = bpf_stats;
- if (bpf_stats)
- static_branch_enable(&bpf_stats_enabled_key);
+ if (val)
+ static_key_enable(key);
else
- static_branch_disable(&bpf_stats_enabled_key);
+ static_key_disable(key);
}
+ mutex_unlock(&static_key_mutex);
return ret;
}
#endif
match->mask.vlan.vlan_id =
ntohs(ext_m_spec->vlan_tci) & 0x0fff;
+ match->key.vlan.vlan_dei =
+ !!(ext_h_spec->vlan_tci & htons(0x1000));
+ match->mask.vlan.vlan_dei =
+ !!(ext_m_spec->vlan_tci & htons(0x1000));
+
match->key.vlan.vlan_priority =
(ntohs(ext_h_spec->vlan_tci) & 0xe000) >> 13;
match->mask.vlan.vlan_priority =
/* On 32bit arches, an skb frag is limited to 2^15 */
#define SKB_FRAG_PAGE_ORDER get_order(32768)
+DEFINE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key);
/**
* skb_page_frag_refill - check that a page_frag contains enough room
}
pfrag->offset = 0;
- if (SKB_FRAG_PAGE_ORDER) {
+ if (SKB_FRAG_PAGE_ORDER &&
+ !static_branch_unlikely(&net_high_order_alloc_disable_key)) {
/* Avoid direct reclaim but allow kswapd to wake */
pfrag->page = alloc_pages((gfp & ~__GFP_DIRECT_RECLAIM) |
__GFP_COMP | __GFP_NOWARN |
.extra1 = &zero,
.extra2 = &two,
},
+ {
+ .procname = "high_order_alloc_disable",
+ .data = &net_high_order_alloc_disable_key.key,
+ .maxlen = sizeof(net_high_order_alloc_disable_key),
+ .mode = 0644,
+ .proc_handler = proc_do_static_key,
+ },
{ }
};
uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
if (!uarg)
return -ENOBUFS;
- extra_uref = !skb; /* only extra ref if !MSG_MORE */
+ extra_uref = !skb_zcopy(skb); /* only ref on new uarg */
if (rt->dst.dev->features & NETIF_F_SG &&
csummode == CHECKSUM_PARTIAL) {
paged = true;
static u32 u32_max_div_HZ = UINT_MAX / HZ;
static int one_day_secs = 24 * 3600;
+DEFINE_STATIC_KEY_FALSE(tcp_rx_skb_cache_key);
+EXPORT_SYMBOL(tcp_rx_skb_cache_key);
+
+DEFINE_STATIC_KEY_FALSE(tcp_tx_skb_cache_key);
+
/* obsolete */
static int sysctl_tcp_low_latency __read_mostly;
.extra1 = &sysctl_fib_sync_mem_min,
.extra2 = &sysctl_fib_sync_mem_max,
},
+ {
+ .procname = "tcp_rx_skb_cache",
+ .data = &tcp_rx_skb_cache_key.key,
+ .mode = 0644,
+ .proc_handler = proc_do_static_key,
+ },
+ {
+ .procname = "tcp_tx_skb_cache",
+ .data = &tcp_tx_skb_cache_key.key,
+ .mode = 0644,
+ .proc_handler = proc_do_static_key,
+ },
{ }
};
return ERR_PTR(err);
}
-static int icmp6_iif(const struct sk_buff *skb)
+static struct net_device *icmp6_dev(const struct sk_buff *skb)
{
- int iif = skb->dev->ifindex;
+ struct net_device *dev = skb->dev;
/* for local traffic to local address, skb dev is the loopback
* device. Check if there is a dst attached to the skb and if so
* get the real device index. Same is needed for replies to a link
* local address on a device enslaved to an L3 master device
*/
- if (unlikely(iif == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) {
+ if (unlikely(dev->ifindex == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) {
const struct rt6_info *rt6 = skb_rt6_info(skb);
if (rt6)
- iif = rt6->rt6i_idev->dev->ifindex;
+ dev = rt6->rt6i_idev->dev;
}
- return iif;
+ return dev;
+}
+
+static int icmp6_iif(const struct sk_buff *skb)
+{
+ return icmp6_dev(skb)->ifindex;
}
/*
static int icmpv6_rcv(struct sk_buff *skb)
{
struct net *net = dev_net(skb->dev);
- struct net_device *dev = skb->dev;
+ struct net_device *dev = icmp6_dev(skb);
struct inet6_dev *idev = __in6_dev_get(dev);
const struct in6_addr *saddr, *daddr;
struct icmp6hdr *hdr;
uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
if (!uarg)
return -ENOBUFS;
- extra_uref = !skb; /* only extra ref if !MSG_MORE */
+ extra_uref = !skb_zcopy(skb); /* only ref on new uarg */
if (rt->dst.dev->features & NETIF_F_SG &&
csummode == CHECKSUM_PARTIAL) {
paged = true;
skb_network_header_len(skb));
rcu_read_lock();
- __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
+ __IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMOKS);
rcu_read_unlock();
fq->q.rb_fragments = RB_ROOT;
fq->q.fragments_tail = NULL;
net_dbg_ratelimited("ip6_frag_reasm: no memory for reassembly\n");
out_fail:
rcu_read_lock();
- __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
+ __IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMFAILS);
rcu_read_unlock();
inet_frag_kill(&fq->q);
return -1;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
- if (WARN_ON(!chanctx_conf)) {
+ if (WARN_ON_ONCE(!chanctx_conf)) {
rcu_read_unlock();
return NULL;
}
static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
{
/*
+ * It's unsafe to try to do any work during reconfigure flow.
+ * When the flow ends the work will be requeued.
+ */
+ if (local->in_reconfig)
+ return false;
+
+ /*
* If quiescing is set, we are racing with __ieee80211_suspend.
* __ieee80211_suspend flushes the workers after setting quiescing,
* and we check quiescing / suspended before enqueing new workers.
const u8 *addr);
void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata);
void ieee80211_tdls_chsw_work(struct work_struct *wk);
+void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata,
+ const u8 *peer, u16 reason);
+const char *ieee80211_get_reason_code_string(u16 reason_code);
extern const struct ethtool_ops ieee80211_ethtool_ops;
{
struct sta_info *sta = key->sta;
struct ieee80211_local *local = key->local;
- struct ieee80211_key *old;
assert_key_lock(local);
- old = key_mtx_dereference(local, sta->ptk[sta->ptk_idx]);
sta->ptk_idx = key->conf.keyidx;
ieee80211_check_fast_xmit(sta);
/* flush STAs and mpaths on this iface */
sta_info_flush(sdata);
+ ieee80211_free_keys(sdata, true);
mesh_path_flush_by_iface(sdata);
/* stop the beacon */
ifmsh->chsw_ttl = 0;
/* Remove the CSA and MCSP elements from the beacon */
- tmp_csa_settings = rcu_dereference(ifmsh->csa);
+ tmp_csa_settings = rcu_dereference_protected(ifmsh->csa,
+ lockdep_is_held(&sdata->wdev.mtx));
RCU_INIT_POINTER(ifmsh->csa, NULL);
if (tmp_csa_settings)
kfree_rcu(tmp_csa_settings, rcu_head);
struct mesh_csa_settings *tmp_csa_settings;
int ret = 0;
+ lockdep_assert_held(&sdata->wdev.mtx);
+
tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
GFP_ATOMIC);
if (!tmp_csa_settings)
#define case_WLAN(type) \
case WLAN_REASON_##type: return #type
-static const char *ieee80211_get_reason_code_string(u16 reason_code)
+const char *ieee80211_get_reason_code_string(u16 reason_code)
{
switch (reason_code) {
case_WLAN(UNSPECIFIED);
if (len < 24 + 2)
return;
+ if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
+ ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
+ return;
+ }
+
if (ifmgd->associated &&
ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) {
const u8 *bssid = ifmgd->associated->bssid;
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+ if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
+ ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
+ return;
+ }
+
sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n",
mgmt->sa, reason_code,
ieee80211_get_reason_code_string(reason_code));
case NL80211_IFTYPE_STATION:
if (!bssid && !sdata->u.mgd.use_4addr)
return false;
+ if (ieee80211_is_robust_mgmt_frame(skb) && !rx->sta)
+ return false;
if (multicast)
return true;
return ether_addr_equal(sdata->vif.addr, hdr->addr1);
}
rtnl_unlock();
}
+
+void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata,
+ const u8 *peer, u16 reason)
+{
+ struct ieee80211_sta *sta;
+
+ rcu_read_lock();
+ sta = ieee80211_find_sta(&sdata->vif, peer);
+ if (!sta || !sta->tdls) {
+ rcu_read_unlock();
+ return;
+ }
+ rcu_read_unlock();
+
+ tdls_dbg(sdata, "disconnected from TDLS peer %pM (Reason: %u=%s)\n",
+ peer, reason,
+ ieee80211_get_reason_code_string(reason));
+
+ ieee80211_tdls_oper_request(&sdata->vif, peer,
+ NL80211_TDLS_TEARDOWN,
+ WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE,
+ GFP_ATOMIC);
+}
mutex_lock(&local->mtx);
ieee80211_start_next_roc(local);
mutex_unlock(&local->mtx);
+
+ /* Requeue all works */
+ list_for_each_entry(sdata, &local->interfaces, list)
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
}
/* Always allow software iftypes */
- if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
+ if (local->hw.wiphy->software_iftypes & BIT(iftype) ||
+ (iftype == NL80211_IFTYPE_AP_VLAN &&
+ local->hw.wiphy->flags & WIPHY_FLAG_4ADDR_AP)) {
if (radar_detect)
return -EINVAL;
return 0;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_key *key = rx->key;
struct ieee80211_mmie_16 *mmie;
- u8 aad[GMAC_AAD_LEN], mic[GMAC_MIC_LEN], ipn[6], nonce[GMAC_NONCE_LEN];
+ u8 aad[GMAC_AAD_LEN], *mic, ipn[6], nonce[GMAC_NONCE_LEN];
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (!ieee80211_is_mgmt(hdr->frame_control))
memcpy(nonce, hdr->addr2, ETH_ALEN);
memcpy(nonce + ETH_ALEN, ipn, 6);
+ mic = kmalloc(GMAC_MIC_LEN, GFP_ATOMIC);
+ if (!mic)
+ return RX_DROP_UNUSABLE;
if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce,
skb->data + 24, skb->len - 24,
mic) < 0 ||
crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) {
key->u.aes_gmac.icverrors++;
+ kfree(mic);
return RX_DROP_UNUSABLE;
}
+ kfree(mic);
}
memcpy(key->u.aes_gmac.rx_pn, ipn, 6);
config MPLS_ROUTING
tristate "MPLS: routing support"
depends on NET_IP_TUNNEL || NET_IP_TUNNEL=n
- select PROC_SYSCTL
+ depends on PROC_SYSCTL
---help---
Add support for forwarding of mpls packets.
u32 device_idx, target_idx;
int rc;
- if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+ if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
+ !info->attrs[NFC_ATTR_TARGET_INDEX])
return -EINVAL;
device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
{
struct vport *vport;
struct internal_dev *internal_dev;
+ struct net_device *dev;
int err;
+ bool free_vport = true;
vport = ovs_vport_alloc(0, &ovs_internal_vport_ops, parms);
if (IS_ERR(vport)) {
goto error;
}
- vport->dev = alloc_netdev(sizeof(struct internal_dev),
- parms->name, NET_NAME_USER, do_setup);
+ dev = alloc_netdev(sizeof(struct internal_dev),
+ parms->name, NET_NAME_USER, do_setup);
+ vport->dev = dev;
if (!vport->dev) {
err = -ENOMEM;
goto error_free_vport;
rtnl_lock();
err = register_netdevice(vport->dev);
- if (err)
+ if (err) {
+ free_vport = false;
goto error_unlock;
+ }
dev_set_promiscuity(vport->dev, 1);
rtnl_unlock();
error_unlock:
rtnl_unlock();
- free_percpu(vport->dev->tstats);
+ free_percpu(dev->tstats);
error_free_netdev:
- free_netdev(vport->dev);
+ free_netdev(dev);
error_free_vport:
- ovs_vport_free(vport);
+ if (free_vport)
+ ovs_vport_free(vport);
error:
return ERR_PTR(err);
}
return rhashtable_init(&head->ht, &mask_ht_params);
}
-static void fl_mask_free(struct fl_flow_mask *mask)
+static void fl_mask_free(struct fl_flow_mask *mask, bool mask_init_done)
{
- WARN_ON(!list_empty(&mask->filters));
- rhashtable_destroy(&mask->ht);
+ /* temporary masks don't have their filters list and ht initialized */
+ if (mask_init_done) {
+ WARN_ON(!list_empty(&mask->filters));
+ rhashtable_destroy(&mask->ht);
+ }
kfree(mask);
}
struct fl_flow_mask *mask = container_of(to_rcu_work(work),
struct fl_flow_mask, rwork);
- fl_mask_free(mask);
+ fl_mask_free(mask, true);
+}
+
+static void fl_uninit_mask_free_work(struct work_struct *work)
+{
+ struct fl_flow_mask *mask = container_of(to_rcu_work(work),
+ struct fl_flow_mask, rwork);
+
+ fl_mask_free(mask, false);
}
static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask)
if (err)
goto errout_destroy;
- /* Wait until any potential concurrent users of mask are finished */
- synchronize_rcu();
-
spin_lock(&head->masks_lock);
list_add_tail_rcu(&newmask->list, &head->masks);
spin_unlock(&head->masks_lock);
/* Insert mask as temporary node to prevent concurrent creation of mask
* with same key. Any concurrent lookups with same key will return
- * -EAGAIN because mask's refcnt is zero. It is safe to insert
- * stack-allocated 'mask' to masks hash table because we call
- * synchronize_rcu() before returning from this function (either in case
- * of error or after replacing it with heap-allocated mask in
- * fl_create_new_mask()).
+ * -EAGAIN because mask's refcnt is zero.
*/
fnew->mask = rhashtable_lookup_get_insert_fast(&head->ht,
&mask->ht_node,
errout_cleanup:
rhashtable_remove_fast(&head->ht, &mask->ht_node,
mask_ht_params);
- /* Wait until any potential concurrent users of mask are finished */
- synchronize_rcu();
return ret;
}
*arg = fnew;
kfree(tb);
- kfree(mask);
+ tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work);
return 0;
errout_ht:
errout_tb:
kfree(tb);
errout_mask_alloc:
- kfree(mask);
+ tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work);
errout_fold:
if (fold)
__fl_put(fold);
case SCTP_PARAM_STATE_COOKIE:
asoc->peer.cookie_len =
ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
+ if (asoc->peer.cookie)
+ kfree(asoc->peer.cookie);
asoc->peer.cookie = kmemdup(param.cookie->body, asoc->peer.cookie_len, gfp);
if (!asoc->peer.cookie)
retval = 0;
goto fall_through;
/* Save peer's random parameter */
+ if (asoc->peer.peer_random)
+ kfree(asoc->peer.peer_random);
asoc->peer.peer_random = kmemdup(param.p,
ntohs(param.p->length), gfp);
if (!asoc->peer.peer_random) {
goto fall_through;
/* Save peer's HMAC list */
+ if (asoc->peer.peer_hmacs)
+ kfree(asoc->peer.peer_hmacs);
asoc->peer.peer_hmacs = kmemdup(param.p,
ntohs(param.p->length), gfp);
if (!asoc->peer.peer_hmacs) {
if (!ep->auth_enable)
goto fall_through;
+ if (asoc->peer.peer_chunks)
+ kfree(asoc->peer.peer_chunks);
asoc->peer.peer_chunks = kmemdup(param.p,
ntohs(param.p->length), gfp);
if (!asoc->peer.peer_chunks)
full_record = false;
record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size;
- copied = 0;
copy = size;
if (copy >= record_room) {
copy = record_room;
if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_SEND)
vsk->peer_shutdown |= SEND_SHUTDOWN;
if (vsk->peer_shutdown == SHUTDOWN_MASK &&
- vsock_stream_has_data(vsk) <= 0)
+ vsock_stream_has_data(vsk) <= 0) {
+ sock_set_flag(sk, SOCK_DONE);
sk->sk_state = TCP_CLOSING;
+ }
if (le32_to_cpu(pkt->hdr.flags))
sk->sk_state_change(sk);
break;
@(set -e; \
allf=""; \
for f in $^ ; do \
+ test -f $$f || continue;\
# similar to hexdump -v -e '1/1 "0x%.2x," "\n"' \
thisf=$$(od -An -v -tx1 < $$f | \
sed -e 's/ /\n/g' | \
&rdev->rfkill_ops, rdev);
if (!rdev->rfkill) {
- kfree(rdev);
+ wiphy_free(&rdev->wiphy);
return NULL;
}
}
break;
case NETDEV_PRE_UP:
- if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
+ if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)) &&
+ !(wdev->iftype == NL80211_IFTYPE_AP_VLAN &&
+ rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP &&
+ wdev->use_4addr))
return notifier_from_errno(-EOPNOTSUPP);
+
if (rfkill_blocked(rdev->rfkill))
return notifier_from_errno(-ERFKILL);
break;
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
- [NL80211_ATTR_MAC] = { .len = ETH_ALEN },
- [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN },
+ [NL80211_ATTR_MAC] = { .type = NLA_EXACT_LEN_WARN, .len = ETH_ALEN },
+ [NL80211_ATTR_PREV_BSSID] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = ETH_ALEN
+ },
[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
[NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
[NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
- [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN },
+ [NL80211_ATTR_HT_CAPABILITY] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = NL80211_HT_CAPABILITY_LEN
+ },
[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
[NL80211_ATTR_IE] = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
[NL80211_ATTR_PID] = { .type = NLA_U32 },
[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
- [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN },
+ [NL80211_ATTR_PMKID] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = WLAN_PMKID_LEN
+ },
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
[NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
- [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
+ [NL80211_ATTR_VHT_CAPABILITY] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = NL80211_VHT_CAPABILITY_LEN
+ },
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127),
[NL80211_ATTR_P2P_OPPPS] = NLA_POLICY_MAX(NLA_U8, 1),
[NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
[NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
.len = IEEE80211_QOS_MAP_LEN_MAX },
- [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
+ [NL80211_ATTR_MAC_HINT] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = ETH_ALEN
+ },
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
[NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_UPS - 1),
[NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
[NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
- [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
+ [NL80211_ATTR_MAC_MASK] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = ETH_ALEN
+ },
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
[NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
.len = VHT_MUMIMO_GROUPS_DATA_LEN
},
- [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN },
+ [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = ETH_ALEN
+ },
[NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1),
[NL80211_ATTR_BANDS] = { .type = NLA_U32 },
[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
[NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
.len = FILS_MAX_KEK_LEN },
- [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
+ [NL80211_ATTR_FILS_NONCES] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = 2 * FILS_NONCE_LEN
+ },
[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
- [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
+ [NL80211_ATTR_BSSID] = { .type = NLA_EXACT_LEN_WARN, .len = ETH_ALEN },
[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
.len = sizeof(struct nl80211_bss_select_rssi_adjust)
[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
[NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
.len = FILS_ERP_MAX_RRK_LEN },
- [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
+ [NL80211_ATTR_FILS_CACHE_ID] = { .type = NLA_EXACT_LEN_WARN, .len = 2 },
[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
[NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
[NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
[NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
- [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN },
+ [NL80211_WOWLAN_TCP_DST_MAC] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = ETH_ALEN
+ },
[NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
[NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
- [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 },
+ [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .type = NLA_MIN_LEN, .len = 1 },
[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
.len = sizeof(struct nl80211_wowlan_tcp_data_seq)
},
.len = sizeof(struct nl80211_wowlan_tcp_data_token)
},
[NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
- [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
- [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
+ [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .type = NLA_MIN_LEN, .len = 1 },
+ [NL80211_WOWLAN_TCP_WAKE_MASK] = { .type = NLA_MIN_LEN, .len = 1 },
};
#endif /* CONFIG_PM */
/* policy for GTK rekey offload attributes */
static const struct nla_policy
nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
- [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
- [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
- [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
+ [NL80211_REKEY_DATA_KEK] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = NL80211_KEK_LEN,
+ },
+ [NL80211_REKEY_DATA_KCK] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = NL80211_KCK_LEN,
+ },
+ [NL80211_REKEY_DATA_REPLAY_CTR] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = NL80211_REPLAY_CTR_LEN
+ },
};
static const struct nla_policy
nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_SSID_LEN },
- [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = { .len = ETH_ALEN },
+ [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = ETH_ALEN
+ },
[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
NLA_POLICY_NESTED(nl80211_match_band_rssi_policy),
[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
[NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
- [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { .len = ETH_ALEN },
+ [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = ETH_ALEN
+ },
[NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
[NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
[NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
if (info->attrs[NL80211_ATTR_IFTYPE])
type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
- if (!rdev->ops->add_virtual_intf ||
- !(rdev->wiphy.interface_modes & (1 << type)))
+ if (!rdev->ops->add_virtual_intf)
return -EOPNOTSUPP;
if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
return err;
}
+ if (!(rdev->wiphy.interface_modes & (1 << type)) &&
+ !(type == NL80211_IFTYPE_AP_VLAN && params.use_4addr &&
+ rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP))
+ return -EOPNOTSUPP;
+
err = nl80211_parse_mon_options(rdev, type, info, ¶ms);
if (err < 0)
return err;
.len = NL80211_MAX_SUPP_RATES },
[NL80211_TXRATE_HT] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_HT_RATES },
- [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
+ [NL80211_TXRATE_VHT] = {
+ .type = NLA_EXACT_LEN_WARN,
+ .len = sizeof(struct nl80211_txrate_vht),
+ },
[NL80211_TXRATE_GI] = { .type = NLA_U8 },
};
struct nlattr *sinfoattr, *bss_param;
hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
- if (!hdr)
+ if (!hdr) {
+ cfg80211_sinfo_release_content(sinfo);
return -1;
+ }
if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) ||
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018 - 2019 Intel Corporation
*/
#ifndef __PMSR_H
#define __PMSR_H
if (res->ap_tsf_valid &&
nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_AP_TSF,
- res->host_time, NL80211_PMSR_RESP_ATTR_PAD))
+ res->ap_tsf, NL80211_PMSR_RESP_ATTR_PAD))
goto error;
if (res->final && nla_put_flag(msg, NL80211_PMSR_RESP_ATTR_FINAL))
continue;
}
- if (seen_indices & BIT(mbssid_index_ie[2]))
+ if (seen_indices & BIT_ULL(mbssid_index_ie[2]))
/* We don't support legacy split of a profile */
net_dbg_ratelimited("Partial info for BSSID index %d\n",
mbssid_index_ie[2]);
- seen_indices |= BIT(mbssid_index_ie[2]);
+ seen_indices |= BIT_ULL(mbssid_index_ie[2]);
non_tx_data->bssid_index = mbssid_index_ie[2];
non_tx_data->max_bssid_indicator = elem->data[0];
if (rate->he_dcm)
result /= 2;
- return result;
+ return result / 10000;
}
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
continue;
if (supp >= mcs_encoding) {
- max_vht_nss = i;
+ max_vht_nss = i + 1;
break;
}
}
vlan_interface_uppers_test
bridge_extern_learn_test
neigh_offload_test
+ nexthop_offload_test
devlink_reload_test
"
NUM_NETIFS=2
ip -4 address del 192.0.2.1/24 dev $swp1
}
+nexthop_offload_test()
+{
+ # Test that IPv4 and IPv6 nexthops are marked as offloaded
+ RET=0
+
+ sysctl_set net.ipv6.conf.$swp2.keep_addr_on_down 1
+ simple_if_init $swp1 192.0.2.1/24 2001:db8:1::1/64
+ simple_if_init $swp2 192.0.2.2/24 2001:db8:1::2/64
+ setup_wait
+
+ ip -4 route add 198.51.100.0/24 vrf v$swp1 \
+ nexthop via 192.0.2.2 dev $swp1
+ ip -6 route add 2001:db8:2::/64 vrf v$swp1 \
+ nexthop via 2001:db8:1::2 dev $swp1
+
+ ip -4 route show 198.51.100.0/24 vrf v$swp1 | grep -q offload
+ check_err $? "ipv4 nexthop not marked as offloaded when should"
+ ip -6 route show 2001:db8:2::/64 vrf v$swp1 | grep -q offload
+ check_err $? "ipv6 nexthop not marked as offloaded when should"
+
+ ip link set dev $swp2 down
+ sleep 1
+
+ ip -4 route show 198.51.100.0/24 vrf v$swp1 | grep -q offload
+ check_fail $? "ipv4 nexthop marked as offloaded when should not"
+ ip -6 route show 2001:db8:2::/64 vrf v$swp1 | grep -q offload
+ check_fail $? "ipv6 nexthop marked as offloaded when should not"
+
+ ip link set dev $swp2 up
+ setup_wait
+
+ ip -4 route show 198.51.100.0/24 vrf v$swp1 | grep -q offload
+ check_err $? "ipv4 nexthop not marked as offloaded after neigh add"
+ ip -6 route show 2001:db8:2::/64 vrf v$swp1 | grep -q offload
+ check_err $? "ipv6 nexthop not marked as offloaded after neigh add"
+
+ log_test "nexthop offload indication"
+
+ ip -6 route del 2001:db8:2::/64 vrf v$swp1
+ ip -4 route del 198.51.100.0/24 vrf v$swp1
+
+ simple_if_fini $swp2 192.0.2.2/24 2001:db8:1::2/64
+ simple_if_fini $swp1 192.0.2.1/24 2001:db8:1::1/64
+ sysctl_restore net.ipv6.conf.$swp2.keep_addr_on_down
+}
+
devlink_reload_test()
{
# Test that after executing all the above configuration tests, a
# SPDX-License-Identifier: GPL-2.0
ALL_TESTS="match_dst_mac_test match_src_mac_test match_dst_ip_test \
- match_src_ip_test match_ip_flags_test match_pcp_test match_vlan_test"
+ match_src_ip_test match_ip_flags_test match_pcp_test match_vlan_test \
+ match_ip_tos_test"
NUM_NETIFS=2
source tc_common.sh
source lib.sh
log_test "VLAN match ($tcflags)"
}
+match_ip_tos_test()
+{
+ RET=0
+
+ tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
+ $tcflags dst_ip 192.0.2.2 ip_tos 0x20 action drop
+ tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
+ $tcflags dst_ip 192.0.2.2 ip_tos 0x18 action drop
+
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
+ -t ip tos=18 -q
+
+ tc_check_packets "dev $h2 ingress" 101 1
+ check_fail $? "Matched on a wrong filter (0x18)"
+
+ tc_check_packets "dev $h2 ingress" 102 1
+ check_err $? "Did not match on correct filter (0x18)"
+
+ $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
+ -t ip tos=20 -q
+
+ tc_check_packets "dev $h2 ingress" 102 2
+ check_fail $? "Matched on a wrong filter (0x20)"
+
+ tc_check_packets "dev $h2 ingress" 101 1
+ check_err $? "Did not match on correct filter (0x20)"
+
+ tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
+ tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
+
+ log_test "ip_tos match ($tcflags)"
+}
+
setup_prepare()
{
h1=${NETIFS[p1]}