Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next

Pull networking changes from David Miller:
 "Noteworthy changes this time around:

   1) Multicast rejoin support for team driver, from Jiri Pirko.

   2) Centralize and simplify TCP RTT measurement handling in order to
      reduce the impact of bad RTO seeding from SYN/ACKs.  Also, when
      both timestamps and local RTT measurements are available prefer
      the later because there are broken middleware devices which
      scramble the timestamp.

      From Yuchung Cheng.

   3) Add TCP_NOTSENT_LOWAT socket option to limit the amount of kernel
      memory consumed to queue up unsend user data.  From Eric Dumazet.

   4) Add a "physical port ID" abstraction for network devices, from
      Jiri Pirko.

   5) Add a "suppress" operation to influence fib_rules lookups, from
      Stefan Tomanek.

   6) Add a networking development FAQ, from Paul Gortmaker.

   7) Extend the information provided by tcp_probe and add ipv6 support,
      from Daniel Borkmann.

   8) Use RCU locking more extensively in openvswitch data paths, from
      Pravin B Shelar.

   9) Add SCTP support to openvswitch, from Joe Stringer.

  10) Add EF10 chip support to SFC driver, from Ben Hutchings.

  11) Add new SYNPROXY netfilter target, from Patrick McHardy.

  12) Compute a rate approximation for sending in TCP sockets, and use
      this to more intelligently coalesce TSO frames.  Furthermore, add
      a new packet scheduler which takes advantage of this estimate when
      available.  From Eric Dumazet.

  13) Allow AF_PACKET fanouts with random selection, from Daniel
      Borkmann.

  14) Add ipv6 support to vxlan driver, from Cong Wang"

Resolved conflicts as per discussion.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1218 commits)
  openvswitch: Fix alignment of struct sw_flow_key.
  netfilter: Fix build errors with xt_socket.c
  tcp: Add missing braces to do_tcp_setsockopt
  caif: Add missing braces to multiline if in cfctrl_linkup_request
  bnx2x: Add missing braces in bnx2x:bnx2x_link_initialize
  vxlan: Fix kernel panic on device delete.
  net: mvneta: implement ->ndo_do_ioctl() to support PHY ioctls
  net: mvneta: properly disable HW PHY polling and ensure adjust_link() works
  icplus: Use netif_running to determine device state
  ethernet/arc/arc_emac: Fix huge delays in large file copies
  tuntap: orphan frags before trying to set tx timestamp
  tuntap: purge socket error queue on detach
  qlcnic: use standard NAPI weights
  ipv6:introduce function to find route for redirect
  bnx2x: VF RSS support - VF side
  bnx2x: VF RSS support - PF side
  vxlan: Notify drivers for listening UDP port changes
  net: usbnet: update addr_assign_type if appropriate
  driver/net: enic: update enic maintainers and driver
  driver/net: enic: Exposing symbols for Cisco's low latency driver
  ...
This commit is contained in:
Linus Torvalds 2013-09-05 14:54:29 -07:00
commit cc998ff881
974 changed files with 56740 additions and 23930 deletions

View file

@ -462,6 +462,14 @@ int wiphy_register(struct wiphy *wiphy)
return -EINVAL;
#endif
if (WARN_ON(wiphy->coalesce &&
(!wiphy->coalesce->n_rules ||
!wiphy->coalesce->n_patterns) &&
(!wiphy->coalesce->pattern_min_len ||
wiphy->coalesce->pattern_min_len >
wiphy->coalesce->pattern_max_len)))
return -EINVAL;
if (WARN_ON(wiphy->ap_sme_capa &&
!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
return -EINVAL;
@ -668,6 +676,7 @@ void wiphy_unregister(struct wiphy *wiphy)
rdev_set_wakeup(rdev, false);
#endif
cfg80211_rdev_free_wowlan(rdev);
cfg80211_rdev_free_coalesce(rdev);
}
EXPORT_SYMBOL(wiphy_unregister);

View file

@ -79,6 +79,8 @@ struct cfg80211_registered_device {
/* netlink port which started critical protocol (0 means not started) */
u32 crit_proto_nlportid;
struct cfg80211_coalesce *coalesce;
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
struct wiphy wiphy __aligned(NETDEV_ALIGN);

View file

@ -167,9 +167,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
* basic rates
*/
if (!setup->basic_rates) {
enum nl80211_bss_scan_width scan_width;
struct ieee80211_supported_band *sband =
rdev->wiphy.bands[setup->chandef.chan->band];
setup->basic_rates = ieee80211_mandatory_rates(sband);
scan_width = cfg80211_chandef_to_scan_width(&setup->chandef);
setup->basic_rates = ieee80211_mandatory_rates(sband,
scan_width);
}
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))

View file

@ -621,7 +621,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
}
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
const u8 *buf, size_t len, gfp_t gfp)
const u8 *buf, size_t len, u32 flags, gfp_t gfp)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
@ -664,7 +664,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
/* Indicate the received Action frame to user space */
if (nl80211_send_mgmt(rdev, wdev, reg->nlportid,
freq, sig_mbm,
buf, len, gfp))
buf, len, flags, gfp))
continue;
result = true;

View file

@ -349,6 +349,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
[NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
[NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
[NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
[NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 },
[NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
};
/* policy for the key attributes */
@ -403,6 +408,14 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
[NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
};
/* policy for coalesce rule attributes */
static const struct nla_policy
nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
[NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
[NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
};
/* policy for GTK rekey offload attributes */
static const struct nla_policy
nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
@ -976,7 +989,7 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
return -ENOBUFS;
if (dev->wiphy.wowlan->n_patterns) {
struct nl80211_wowlan_pattern_support pat = {
struct nl80211_pattern_support pat = {
.max_patterns = dev->wiphy.wowlan->n_patterns,
.min_pattern_len = dev->wiphy.wowlan->pattern_min_len,
.max_pattern_len = dev->wiphy.wowlan->pattern_max_len,
@ -997,6 +1010,27 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
}
#endif
static int nl80211_send_coalesce(struct sk_buff *msg,
struct cfg80211_registered_device *dev)
{
struct nl80211_coalesce_rule_support rule;
if (!dev->wiphy.coalesce)
return 0;
rule.max_rules = dev->wiphy.coalesce->n_rules;
rule.max_delay = dev->wiphy.coalesce->max_delay;
rule.pat.max_patterns = dev->wiphy.coalesce->n_patterns;
rule.pat.min_pattern_len = dev->wiphy.coalesce->pattern_min_len;
rule.pat.max_pattern_len = dev->wiphy.coalesce->pattern_max_len;
rule.pat.max_pkt_offset = dev->wiphy.coalesce->max_pkt_offset;
if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
return -ENOBUFS;
return 0;
}
static int nl80211_send_band_rateinfo(struct sk_buff *msg,
struct ieee80211_supported_band *sband)
{
@ -1395,6 +1429,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
if (state->split) {
CMD(crit_proto_start, CRIT_PROTOCOL_START);
CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
CMD(channel_switch, CHANNEL_SWITCH);
}
#ifdef CONFIG_NL80211_TESTMODE
@ -1515,6 +1551,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
dev->wiphy.vht_capa_mod_mask))
goto nla_put_failure;
state->split_start++;
break;
case 10:
if (nl80211_send_coalesce(msg, dev))
goto nla_put_failure;
/* done */
state->split_start = 0;
break;
@ -5580,6 +5622,111 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
return err;
}
static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_csa_settings params;
/* csa_attrs is defined static to avoid waste of stack size - this
* function is called under RTNL lock, so this should not be a problem.
*/
static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
u8 radar_detect_width = 0;
int err;
if (!rdev->ops->channel_switch ||
!(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
return -EOPNOTSUPP;
/* may add IBSS support later */
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
memset(&params, 0, sizeof(params));
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
!info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
return -EINVAL;
/* only important for AP, IBSS and mesh create IEs internally */
if (!info->attrs[NL80211_ATTR_CSA_IES])
return -EINVAL;
/* useless if AP is not running */
if (!wdev->beacon_interval)
return -EINVAL;
params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
if (err)
return err;
err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX,
info->attrs[NL80211_ATTR_CSA_IES],
nl80211_policy);
if (err)
return err;
err = nl80211_parse_beacon(csa_attrs, &params.beacon_csa);
if (err)
return err;
if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
return -EINVAL;
params.counter_offset_beacon =
nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
if (params.counter_offset_beacon >= params.beacon_csa.tail_len)
return -EINVAL;
/* sanity check - counters should be the same */
if (params.beacon_csa.tail[params.counter_offset_beacon] !=
params.count)
return -EINVAL;
if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
params.counter_offset_presp =
nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
if (params.counter_offset_presp >=
params.beacon_csa.probe_resp_len)
return -EINVAL;
if (params.beacon_csa.probe_resp[params.counter_offset_presp] !=
params.count)
return -EINVAL;
}
err = nl80211_parse_chandef(rdev, info, &params.chandef);
if (err)
return err;
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
return -EINVAL;
err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
if (err < 0) {
return err;
} else if (err) {
radar_detect_width = BIT(params.chandef.width);
params.radar_required = true;
}
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
params.chandef.chan,
CHAN_MODE_SHARED,
radar_detect_width);
if (err)
return err;
if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
params.block_tx = true;
return rdev_channel_switch(rdev, dev, &params);
}
static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
u32 seq, int flags,
struct cfg80211_registered_device *rdev,
@ -5641,6 +5788,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
goto nla_put_failure;
if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
jiffies_to_msecs(jiffies - intbss->ts)))
goto nla_put_failure;
@ -6321,6 +6469,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
switch (ibss.chandef.width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20_NOHT:
break;
case NL80211_CHAN_WIDTH_20:
@ -6348,6 +6498,19 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
return err;
}
if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
memcpy(&ibss.ht_capa_mask,
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
sizeof(ibss.ht_capa_mask));
if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
return -EINVAL;
memcpy(&ibss.ht_capa,
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
sizeof(ibss.ht_capa));
}
if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
!nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
@ -6430,19 +6593,30 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = {
static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev =
__cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
int err;
if (!rdev->ops->testmode_cmd)
return -EOPNOTSUPP;
if (IS_ERR(wdev)) {
err = PTR_ERR(wdev);
if (err != -EINVAL)
return err;
wdev = NULL;
} else if (wdev->wiphy != &rdev->wiphy) {
return -EINVAL;
}
if (!info->attrs[NL80211_ATTR_TESTDATA])
return -EINVAL;
err = -EOPNOTSUPP;
if (rdev->ops->testmode_cmd) {
rdev->testmode_info = info;
err = rdev_testmode_cmd(rdev,
rdev->testmode_info = info;
err = rdev_testmode_cmd(rdev, wdev,
nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
rdev->testmode_info = NULL;
}
rdev->testmode_info = NULL;
return err;
}
@ -7404,14 +7578,12 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
u32 rate, u32 pkts, u32 intvl)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev;
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
return -EINVAL;
wdev = dev->ieee80211_ptr;
if (!rdev->ops->set_cqm_txe_config)
return -EOPNOTSUPP;
@ -7426,13 +7598,15 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
s32 threshold, u32 hysteresis)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev;
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
if (threshold > 0)
return -EINVAL;
wdev = dev->ieee80211_ptr;
/* disabling - hysteresis should also be zero then */
if (threshold == 0)
hysteresis = 0;
if (!rdev->ops->set_cqm_rssi_config)
return -EOPNOTSUPP;
@ -7451,36 +7625,33 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
int err;
cqm = info->attrs[NL80211_ATTR_CQM];
if (!cqm) {
err = -EINVAL;
goto out;
}
if (!cqm)
return -EINVAL;
err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
nl80211_attr_cqm_policy);
if (err)
goto out;
return err;
if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
s32 threshold;
u32 hysteresis;
threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
} else if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
u32 rate, pkts, intvl;
rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
err = nl80211_set_cqm_txe(info, rate, pkts, intvl);
} else
err = -EINVAL;
s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
out:
return err;
return nl80211_set_cqm_rssi(info, threshold, hysteresis);
}
if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
u32 rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
u32 pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
u32 intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
return nl80211_set_cqm_txe(info, rate, pkts, intvl);
}
return -EINVAL;
}
static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
@ -7596,12 +7767,11 @@ static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
if (!nl_pat)
return -ENOBUFS;
pat_len = wowlan->patterns[i].pattern_len;
if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK,
DIV_ROUND_UP(pat_len, 8),
if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
wowlan->patterns[i].mask) ||
nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
pat_len, wowlan->patterns[i].pattern) ||
nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET,
nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
wowlan->patterns[i].pattern) ||
nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
wowlan->patterns[i].pkt_offset))
return -ENOBUFS;
nla_nest_end(msg, nl_pat);
@ -7942,7 +8112,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
struct nlattr *pat;
int n_patterns = 0;
int rem, pat_len, mask_len, pkt_offset;
struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT];
struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
rem)
@ -7961,26 +8131,25 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
rem) {
nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT,
nla_data(pat), nla_len(pat), NULL);
nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
nla_len(pat), NULL);
err = -EINVAL;
if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] ||
!pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN])
if (!pat_tb[NL80211_PKTPAT_MASK] ||
!pat_tb[NL80211_PKTPAT_PATTERN])
goto error;
pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]);
pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
mask_len = DIV_ROUND_UP(pat_len, 8);
if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) !=
mask_len)
if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
goto error;
if (pat_len > wowlan->pattern_max_len ||
pat_len < wowlan->pattern_min_len)
goto error;
if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET])
if (!pat_tb[NL80211_PKTPAT_OFFSET])
pkt_offset = 0;
else
pkt_offset = nla_get_u32(
pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]);
pat_tb[NL80211_PKTPAT_OFFSET]);
if (pkt_offset > wowlan->max_pkt_offset)
goto error;
new_triggers.patterns[i].pkt_offset = pkt_offset;
@ -7994,11 +8163,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
new_triggers.patterns[i].pattern =
new_triggers.patterns[i].mask + mask_len;
memcpy(new_triggers.patterns[i].mask,
nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]),
nla_data(pat_tb[NL80211_PKTPAT_MASK]),
mask_len);
new_triggers.patterns[i].pattern_len = pat_len;
memcpy(new_triggers.patterns[i].pattern,
nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]),
nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
pat_len);
i++;
}
@ -8037,6 +8206,264 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
}
#endif
static int nl80211_send_coalesce_rules(struct sk_buff *msg,
struct cfg80211_registered_device *rdev)
{
struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
int i, j, pat_len;
struct cfg80211_coalesce_rules *rule;
if (!rdev->coalesce->n_rules)
return 0;
nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
if (!nl_rules)
return -ENOBUFS;
for (i = 0; i < rdev->coalesce->n_rules; i++) {
nl_rule = nla_nest_start(msg, i + 1);
if (!nl_rule)
return -ENOBUFS;
rule = &rdev->coalesce->rules[i];
if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
rule->delay))
return -ENOBUFS;
if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
rule->condition))
return -ENOBUFS;
nl_pats = nla_nest_start(msg,
NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
if (!nl_pats)
return -ENOBUFS;
for (j = 0; j < rule->n_patterns; j++) {
nl_pat = nla_nest_start(msg, j + 1);
if (!nl_pat)
return -ENOBUFS;
pat_len = rule->patterns[j].pattern_len;
if (nla_put(msg, NL80211_PKTPAT_MASK,
DIV_ROUND_UP(pat_len, 8),
rule->patterns[j].mask) ||
nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
rule->patterns[j].pattern) ||
nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
rule->patterns[j].pkt_offset))
return -ENOBUFS;
nla_nest_end(msg, nl_pat);
}
nla_nest_end(msg, nl_pats);
nla_nest_end(msg, nl_rule);
}
nla_nest_end(msg, nl_rules);
return 0;
}
static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct sk_buff *msg;
void *hdr;
if (!rdev->wiphy.coalesce)
return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
NL80211_CMD_GET_COALESCE);
if (!hdr)
goto nla_put_failure;
if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
goto nla_put_failure;
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
nla_put_failure:
nlmsg_free(msg);
return -ENOBUFS;
}
void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
{
struct cfg80211_coalesce *coalesce = rdev->coalesce;
int i, j;
struct cfg80211_coalesce_rules *rule;
if (!coalesce)
return;
for (i = 0; i < coalesce->n_rules; i++) {
rule = &coalesce->rules[i];
for (j = 0; j < rule->n_patterns; j++)
kfree(rule->patterns[j].mask);
kfree(rule->patterns);
}
kfree(coalesce->rules);
kfree(coalesce);
rdev->coalesce = NULL;
}
static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
struct nlattr *rule,
struct cfg80211_coalesce_rules *new_rule)
{
int err, i;
const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
err = nla_parse(tb, NL80211_ATTR_COALESCE_RULE_MAX, nla_data(rule),
nla_len(rule), nl80211_coalesce_policy);
if (err)
return err;
if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
new_rule->delay =
nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
if (new_rule->delay > coalesce->max_delay)
return -EINVAL;
if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
new_rule->condition =
nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
return -EINVAL;
if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
return -EINVAL;
nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
rem)
n_patterns++;
if (n_patterns > coalesce->n_patterns)
return -EINVAL;
new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
GFP_KERNEL);
if (!new_rule->patterns)
return -ENOMEM;
new_rule->n_patterns = n_patterns;
i = 0;
nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
rem) {
nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
nla_len(pat), NULL);
if (!pat_tb[NL80211_PKTPAT_MASK] ||
!pat_tb[NL80211_PKTPAT_PATTERN])
return -EINVAL;
pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
mask_len = DIV_ROUND_UP(pat_len, 8);
if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
return -EINVAL;
if (pat_len > coalesce->pattern_max_len ||
pat_len < coalesce->pattern_min_len)
return -EINVAL;
if (!pat_tb[NL80211_PKTPAT_OFFSET])
pkt_offset = 0;
else
pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
if (pkt_offset > coalesce->max_pkt_offset)
return -EINVAL;
new_rule->patterns[i].pkt_offset = pkt_offset;
new_rule->patterns[i].mask =
kmalloc(mask_len + pat_len, GFP_KERNEL);
if (!new_rule->patterns[i].mask)
return -ENOMEM;
new_rule->patterns[i].pattern =
new_rule->patterns[i].mask + mask_len;
memcpy(new_rule->patterns[i].mask,
nla_data(pat_tb[NL80211_PKTPAT_MASK]), mask_len);
new_rule->patterns[i].pattern_len = pat_len;
memcpy(new_rule->patterns[i].pattern,
nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), pat_len);
i++;
}
return 0;
}
static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
struct cfg80211_coalesce new_coalesce = {};
struct cfg80211_coalesce *n_coalesce;
int err, rem_rule, n_rules = 0, i, j;
struct nlattr *rule;
struct cfg80211_coalesce_rules *tmp_rule;
if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
return -EOPNOTSUPP;
if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
cfg80211_rdev_free_coalesce(rdev);
rdev->ops->set_coalesce(&rdev->wiphy, NULL);
return 0;
}
nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
rem_rule)
n_rules++;
if (n_rules > coalesce->n_rules)
return -EINVAL;
new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
GFP_KERNEL);
if (!new_coalesce.rules)
return -ENOMEM;
new_coalesce.n_rules = n_rules;
i = 0;
nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
rem_rule) {
err = nl80211_parse_coalesce_rule(rdev, rule,
&new_coalesce.rules[i]);
if (err)
goto error;
i++;
}
err = rdev->ops->set_coalesce(&rdev->wiphy, &new_coalesce);
if (err)
goto error;
n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
if (!n_coalesce) {
err = -ENOMEM;
goto error;
}
cfg80211_rdev_free_coalesce(rdev);
rdev->coalesce = n_coalesce;
return 0;
error:
for (i = 0; i < new_coalesce.n_rules; i++) {
tmp_rule = &new_coalesce.rules[i];
for (j = 0; j < tmp_rule->n_patterns; j++)
kfree(tmp_rule->patterns[j].mask);
kfree(tmp_rule->patterns);
}
kfree(new_coalesce.rules);
return err;
}
static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@ -9043,7 +9470,30 @@ static struct genl_ops nl80211_ops[] = {
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL,
}
},
{
.cmd = NL80211_CMD_GET_COALESCE,
.doit = nl80211_get_coalesce,
.policy = nl80211_policy,
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_SET_COALESCE,
.doit = nl80211_set_coalesce,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_CHANNEL_SWITCH,
.doit = nl80211_channel_switch,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@ -10000,7 +10450,7 @@ EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u32 nlportid,
int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp)
const u8 *buf, size_t len, u32 flags, gfp_t gfp)
{
struct net_device *netdev = wdev->netdev;
struct sk_buff *msg;
@ -10023,7 +10473,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, buf))
nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
(flags &&
nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags)))
goto nla_put_failure;
genlmsg_end(msg, hdr);

View file

@ -66,7 +66,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u32 nlpid,
int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp);
const u8 *buf, size_t len, u32 flags, gfp_t gfp);
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
@ -74,4 +74,6 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
enum nl80211_radar_event event,
struct net_device *netdev, gfp_t gfp);
void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
#endif /* __NET_WIRELESS_NL80211_H */

View file

@ -516,11 +516,12 @@ static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev)
#ifdef CONFIG_NL80211_TESTMODE
static inline int rdev_testmode_cmd(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
void *data, int len)
{
int ret;
trace_rdev_testmode_cmd(&rdev->wiphy);
ret = rdev->ops->testmode_cmd(&rdev->wiphy, data, len);
trace_rdev_testmode_cmd(&rdev->wiphy, wdev);
ret = rdev->ops->testmode_cmd(&rdev->wiphy, wdev, data, len);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
@ -923,4 +924,16 @@ static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev,
trace_rdev_return_void(&rdev->wiphy);
}
static inline int rdev_channel_switch(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_csa_settings *params)
{
int ret;
trace_rdev_channel_switch(&rdev->wiphy, dev, params);
ret = rdev->ops->channel_switch(&rdev->wiphy, dev, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */

View file

@ -465,10 +465,6 @@ static int cmp_bss(struct cfg80211_bss *a,
}
}
/*
* we can't use compare_ether_addr here since we need a < > operator.
* The binary return value of compare_ether_addr isn't enough
*/
r = memcmp(a->bssid, b->bssid, sizeof(a->bssid));
if (r)
return r;
@ -651,6 +647,8 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
continue;
if (bss->pub.channel != new->pub.channel)
continue;
if (bss->pub.scan_width != new->pub.scan_width)
continue;
if (rcu_access_pointer(bss->pub.beacon_ies))
continue;
ies = rcu_access_pointer(bss->pub.ies);
@ -870,11 +868,12 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
/* Returned bss is reference counted and must be cleaned up appropriately. */
struct cfg80211_bss*
cfg80211_inform_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp)
cfg80211_inform_bss_width(struct wiphy *wiphy,
struct ieee80211_channel *channel,
enum nl80211_bss_scan_width scan_width,
const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp)
{
struct cfg80211_bss_ies *ies;
struct cfg80211_internal_bss tmp = {}, *res;
@ -892,6 +891,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
tmp.pub.channel = channel;
tmp.pub.scan_width = scan_width;
tmp.pub.signal = signal;
tmp.pub.beacon_interval = beacon_interval;
tmp.pub.capability = capability;
@ -924,14 +924,15 @@ cfg80211_inform_bss(struct wiphy *wiphy,
/* cfg80211_bss_update gives us a referenced result */
return &res->pub;
}
EXPORT_SYMBOL(cfg80211_inform_bss);
EXPORT_SYMBOL(cfg80211_inform_bss_width);
/* Returned bss is reference counted and must be cleaned up appropriately. */
struct cfg80211_bss *
cfg80211_inform_bss_frame(struct wiphy *wiphy,
struct ieee80211_channel *channel,
struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp)
cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
struct ieee80211_channel *channel,
enum nl80211_bss_scan_width scan_width,
struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp)
{
struct cfg80211_internal_bss tmp = {}, *res;
struct cfg80211_bss_ies *ies;
@ -941,7 +942,8 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
offsetof(struct ieee80211_mgmt, u.beacon.variable));
trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal);
trace_cfg80211_inform_bss_width_frame(wiphy, channel, scan_width, mgmt,
len, signal);
if (WARN_ON(!mgmt))
return NULL;
@ -976,6 +978,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
tmp.pub.channel = channel;
tmp.pub.scan_width = scan_width;
tmp.pub.signal = signal;
tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
@ -991,7 +994,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
/* cfg80211_bss_update gives us a referenced result */
return &res->pub;
}
EXPORT_SYMBOL(cfg80211_inform_bss_frame);
EXPORT_SYMBOL(cfg80211_inform_bss_width_frame);
void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
{

View file

@ -1293,15 +1293,17 @@ TRACE_EVENT(rdev_return_int_int,
#ifdef CONFIG_NL80211_TESTMODE
TRACE_EVENT(rdev_testmode_cmd,
TP_PROTO(struct wiphy *wiphy),
TP_ARGS(wiphy),
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
TP_ARGS(wiphy, wdev),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
),
TP_fast_assign(
WIPHY_ASSIGN;
WDEV_ASSIGN;
),
TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG)
TP_printk(WIPHY_PR_FMT WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
);
TRACE_EVENT(rdev_testmode_dump,
@ -1841,6 +1843,39 @@ TRACE_EVENT(rdev_crit_proto_stop,
WIPHY_PR_ARG, WDEV_PR_ARG)
);
TRACE_EVENT(rdev_channel_switch,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_csa_settings *params),
TP_ARGS(wiphy, netdev, params),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
CHAN_DEF_ENTRY
__field(u16, counter_offset_beacon)
__field(u16, counter_offset_presp)
__field(bool, radar_required)
__field(bool, block_tx)
__field(u8, count)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
CHAN_DEF_ASSIGN(&params->chandef);
__entry->counter_offset_beacon = params->counter_offset_beacon;
__entry->counter_offset_presp = params->counter_offset_presp;
__entry->radar_required = params->radar_required;
__entry->block_tx = params->block_tx;
__entry->count = params->count;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT
", block_tx: %d, count: %u, radar_required: %d"
", counter offsets (beacon/presp): %u/%u",
WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG,
__entry->block_tx, __entry->count, __entry->radar_required,
__entry->counter_offset_beacon,
__entry->counter_offset_presp)
);
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
@ -2391,26 +2426,30 @@ TRACE_EVENT(cfg80211_get_bss,
__entry->capa_mask, __entry->capa_val)
);
TRACE_EVENT(cfg80211_inform_bss_frame,
TRACE_EVENT(cfg80211_inform_bss_width_frame,
TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
enum nl80211_bss_scan_width scan_width,
struct ieee80211_mgmt *mgmt, size_t len,
s32 signal),
TP_ARGS(wiphy, channel, mgmt, len, signal),
TP_ARGS(wiphy, channel, scan_width, mgmt, len, signal),
TP_STRUCT__entry(
WIPHY_ENTRY
CHAN_ENTRY
__field(enum nl80211_bss_scan_width, scan_width)
__dynamic_array(u8, mgmt, len)
__field(s32, signal)
),
TP_fast_assign(
WIPHY_ASSIGN;
CHAN_ASSIGN(channel);
__entry->scan_width = scan_width;
if (mgmt)
memcpy(__get_dynamic_array(mgmt), mgmt, len);
__entry->signal = signal;
),
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "signal: %d",
WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal)
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "(scan_width: %d) signal: %d",
WIPHY_PR_ARG, CHAN_PR_ARG, __entry->scan_width,
__entry->signal)
);
DECLARE_EVENT_CLASS(cfg80211_bss_evt,

View file

@ -33,7 +33,8 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
}
EXPORT_SYMBOL(ieee80211_get_response_rate);
u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband)
u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
enum nl80211_bss_scan_width scan_width)
{
struct ieee80211_rate *bitrates;
u32 mandatory_rates = 0;
@ -43,10 +44,15 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband)
if (WARN_ON(!sband))
return 1;
if (sband->band == IEEE80211_BAND_2GHZ)
mandatory_flag = IEEE80211_RATE_MANDATORY_B;
else
if (sband->band == IEEE80211_BAND_2GHZ) {
if (scan_width == NL80211_BSS_CHAN_WIDTH_5 ||
scan_width == NL80211_BSS_CHAN_WIDTH_10)
mandatory_flag = IEEE80211_RATE_MANDATORY_G;
else
mandatory_flag = IEEE80211_RATE_MANDATORY_B;
} else {
mandatory_flag = IEEE80211_RATE_MANDATORY_A;
}
bitrates = sband->bitrates;
for (i = 0; i < sband->n_bitrates; i++)