diff options
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r-- | net/wireless/util.c | 236 |
1 files changed, 165 insertions, 71 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index 156a2a6337b9..dd4be0466ae0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -13,6 +13,7 @@ #include <net/dsfield.h> #include <linux/if_vlan.h> #include <linux/mpls.h> +#include <linux/gcd.h> #include "core.h" #include "rdev-ops.h" @@ -47,7 +48,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband, if (WARN_ON(!sband)) return 1; - if (sband->band == IEEE80211_BAND_2GHZ) { + if (sband->band == NL80211_BAND_2GHZ) { if (scan_width == NL80211_BSS_CHAN_WIDTH_5 || scan_width == NL80211_BSS_CHAN_WIDTH_10) mandatory_flag = IEEE80211_RATE_MANDATORY_G; @@ -65,26 +66,26 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband, } EXPORT_SYMBOL(ieee80211_mandatory_rates); -int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) +int ieee80211_channel_to_frequency(int chan, enum nl80211_band band) { /* see 802.11 17.3.8.3.2 and Annex J * there are overlapping channel numbers in 5GHz and 2GHz bands */ if (chan <= 0) return 0; /* not supported */ switch (band) { - case IEEE80211_BAND_2GHZ: + case NL80211_BAND_2GHZ: if (chan == 14) return 2484; else if (chan < 14) return 2407 + chan * 5; break; - case IEEE80211_BAND_5GHZ: + case NL80211_BAND_5GHZ: if (chan >= 182 && chan <= 196) return 4000 + chan * 5; else return 5000 + chan * 5; break; - case IEEE80211_BAND_60GHZ: + case NL80211_BAND_60GHZ: if (chan < 5) return 56160 + chan * 2160; break; @@ -116,11 +117,11 @@ EXPORT_SYMBOL(ieee80211_frequency_to_channel); struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, int freq) { - enum ieee80211_band band; + enum nl80211_band band; struct ieee80211_supported_band *sband; int i; - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + for (band = 0; band < NUM_NL80211_BANDS; band++) { sband = wiphy->bands[band]; if (!sband) @@ -137,12 +138,12 @@ struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, EXPORT_SYMBOL(__ieee80211_get_channel); static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, - enum ieee80211_band band) + enum nl80211_band band) { int i, want; switch (band) { - case IEEE80211_BAND_5GHZ: + case NL80211_BAND_5GHZ: want = 3; for (i = 0; i < sband->n_bitrates; i++) { if (sband->bitrates[i].bitrate == 60 || @@ -155,7 +156,7 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, } WARN_ON(want); break; - case IEEE80211_BAND_2GHZ: + case NL80211_BAND_2GHZ: want = 7; for (i = 0; i < sband->n_bitrates; i++) { if (sband->bitrates[i].bitrate == 10) { @@ -185,12 +186,12 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, } WARN_ON(want != 0 && want != 3 && want != 6); break; - case IEEE80211_BAND_60GHZ: + case NL80211_BAND_60GHZ: /* check for mandatory HT MCS 1..4 */ WARN_ON(!sband->ht_cap.ht_supported); WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); break; - case IEEE80211_NUM_BANDS: + case NUM_NL80211_BANDS: WARN_ON(1); break; } @@ -198,9 +199,9 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, void ieee80211_set_bitrate_flags(struct wiphy *wiphy) { - enum ieee80211_band band; + enum nl80211_band band; - for (band = 0; band < IEEE80211_NUM_BANDS; band++) + for (band = 0; band < NUM_NL80211_BANDS; band++) if (wiphy->bands[band]) set_mandatory_flags_band(wiphy->bands[band], band); } @@ -590,6 +591,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, hdr.frame_control = fc; hdr.duration_id = 0; hdr.seq_ctrl = 0; + eth_zero_addr(hdr.addr4); skip_header_bytes = ETH_HLEN; if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { @@ -857,7 +859,6 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) { struct cfg80211_event *ev; unsigned long flags; - const u8 *bssid = NULL; spin_lock_irqsave(&wdev->event_lock, flags); while (!list_empty(&wdev->event_list)) { @@ -869,15 +870,10 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) wdev_lock(wdev); switch (ev->type) { case EVENT_CONNECT_RESULT: - if (!is_zero_ether_addr(ev->cr.bssid)) - bssid = ev->cr.bssid; __cfg80211_connect_result( - wdev->netdev, bssid, - ev->cr.req_ie, ev->cr.req_ie_len, - ev->cr.resp_ie, ev->cr.resp_ie_len, - ev->cr.status, - ev->cr.status == WLAN_STATUS_SUCCESS, - NULL); + wdev->netdev, + &ev->cr, + ev->cr.status == WLAN_STATUS_SUCCESS); break; case EVENT_ROAMED: __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie, @@ -913,7 +909,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) ASSERT_RTNL(); - list_for_each_entry(wdev, &rdev->wdev_list, list) + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) cfg80211_process_wdev_events(wdev); } @@ -1083,7 +1079,7 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) 58500000, 65000000, 78000000, - 0, + 86500000, }, { 13500000, 27000000, @@ -1334,22 +1330,22 @@ size_t ieee80211_ie_split(const u8 *ies, size_t ielen, EXPORT_SYMBOL(ieee80211_ie_split); bool ieee80211_operating_class_to_band(u8 operating_class, - enum ieee80211_band *band) + enum nl80211_band *band) { switch (operating_class) { case 112: case 115 ... 127: case 128 ... 130: - *band = IEEE80211_BAND_5GHZ; + *band = NL80211_BAND_5GHZ; return true; case 81: case 82: case 83: case 84: - *band = IEEE80211_BAND_2GHZ; + *band = NL80211_BAND_2GHZ; return true; case 180: - *band = IEEE80211_BAND_60GHZ; + *band = NL80211_BAND_60GHZ; return true; } @@ -1486,31 +1482,57 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, } EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); -int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, - u32 beacon_int) +static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, + u32 *beacon_int_gcd, + bool *beacon_int_different) { struct wireless_dev *wdev; - int res = 0; - if (!beacon_int) - return -EINVAL; + *beacon_int_gcd = 0; + *beacon_int_different = false; - list_for_each_entry(wdev, &rdev->wdev_list, list) { + list_for_each_entry(wdev, &wiphy->wdev_list, list) { if (!wdev->beacon_interval) continue; - if (wdev->beacon_interval != beacon_int) { - res = -EINVAL; - break; + + if (!*beacon_int_gcd) { + *beacon_int_gcd = wdev->beacon_interval; + continue; } + + if (wdev->beacon_interval == *beacon_int_gcd) + continue; + + *beacon_int_different = true; + *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval); } - return res; + if (new_beacon_int && *beacon_int_gcd != new_beacon_int) { + if (*beacon_int_gcd) + *beacon_int_different = true; + *beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int); + } +} + +int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, + enum nl80211_iftype iftype, u32 beacon_int) +{ + /* + * This is just a basic pre-condition check; if interface combinations + * are possible the driver must already be checking those with a call + * to cfg80211_check_combinations(), in which case we'll validate more + * through the cfg80211_calculate_bi_data() call and code in + * cfg80211_iter_combinations(). + */ + + if (beacon_int < 10 || beacon_int > 10000) + return -EINVAL; + + return 0; } int cfg80211_iter_combinations(struct wiphy *wiphy, - const int num_different_channels, - const u8 radar_detect, - const int iftype_num[NUM_NL80211_IFTYPES], + struct iface_combination_params *params, void (*iter)(const struct ieee80211_iface_combination *c, void *data), void *data) @@ -1520,8 +1542,23 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, int i, j, iftype; int num_interfaces = 0; u32 used_iftypes = 0; + u32 beacon_int_gcd; + bool beacon_int_different; - if (radar_detect) { + /* + * This is a bit strange, since the iteration used to rely only on + * the data given by the driver, but here it now relies on context, + * in form of the currently operating interfaces. + * This is OK for all current users, and saves us from having to + * push the GCD calculations into all the drivers. + * In the future, this should probably rely more on data that's in + * cfg80211 already - the only thing not would appear to be any new + * interfaces (while being brought up) and channel/radar data. + */ + cfg80211_calculate_bi_data(wiphy, params->new_beacon_int, + &beacon_int_gcd, &beacon_int_different); + + if (params->radar_detect) { rcu_read_lock(); regdom = rcu_dereference(cfg80211_regdomain); if (regdom) @@ -1530,8 +1567,8 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, } for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { - num_interfaces += iftype_num[iftype]; - if (iftype_num[iftype] > 0 && + num_interfaces += params->iftype_num[iftype]; + if (params->iftype_num[iftype] > 0 && !(wiphy->software_iftypes & BIT(iftype))) used_iftypes |= BIT(iftype); } @@ -1545,7 +1582,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, if (num_interfaces > c->max_interfaces) continue; - if (num_different_channels > c->num_different_channels) + if (params->num_different_channels > c->num_different_channels) continue; limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, @@ -1560,16 +1597,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, all_iftypes |= limits[j].types; if (!(limits[j].types & BIT(iftype))) continue; - if (limits[j].max < iftype_num[iftype]) + if (limits[j].max < params->iftype_num[iftype]) goto cont; - limits[j].max -= iftype_num[iftype]; + limits[j].max -= params->iftype_num[iftype]; } } - if (radar_detect != (c->radar_detect_widths & radar_detect)) + if (params->radar_detect != + (c->radar_detect_widths & params->radar_detect)) goto cont; - if (radar_detect && c->radar_detect_regions && + if (params->radar_detect && c->radar_detect_regions && !(c->radar_detect_regions & BIT(region))) goto cont; @@ -1581,6 +1619,14 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, if ((all_iftypes & used_iftypes) != used_iftypes) goto cont; + if (beacon_int_gcd) { + if (c->beacon_int_min_gcd && + beacon_int_gcd < c->beacon_int_min_gcd) + goto cont; + if (!c->beacon_int_min_gcd && beacon_int_different) + goto cont; + } + /* This combination covered all interface types and * supported the requested numbers, so we're good. */ @@ -1603,14 +1649,11 @@ cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c, } int cfg80211_check_combinations(struct wiphy *wiphy, - const int num_different_channels, - const u8 radar_detect, - const int iftype_num[NUM_NL80211_IFTYPES]) + struct iface_combination_params *params) { int err, num = 0; - err = cfg80211_iter_combinations(wiphy, num_different_channels, - radar_detect, iftype_num, + err = cfg80211_iter_combinations(wiphy, params, cfg80211_iter_sum_ifcombs, &num); if (err) return err; @@ -1629,14 +1672,15 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, u8 radar_detect) { struct wireless_dev *wdev_iter; - int num[NUM_NL80211_IFTYPES]; struct ieee80211_channel *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; struct ieee80211_channel *ch; enum cfg80211_chan_mode chmode; - int num_different_channels = 0; int total = 1; int i; + struct iface_combination_params params = { + .radar_detect = radar_detect, + }; ASSERT_RTNL(); @@ -1653,10 +1697,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, return 0; } - memset(num, 0, sizeof(num)); memset(used_channels, 0, sizeof(used_channels)); - num[iftype] = 1; + params.iftype_num[iftype] = 1; /* TODO: We'll probably not need this anymore, since this * should only be called with CHAN_MODE_UNDEFINED. There are @@ -1669,14 +1712,14 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, case CHAN_MODE_SHARED: WARN_ON(!chan); used_channels[0] = chan; - num_different_channels++; + params.num_different_channels++; break; case CHAN_MODE_EXCLUSIVE: - num_different_channels++; + params.num_different_channels++; break; } - list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { + list_for_each_entry(wdev_iter, &rdev->wiphy.wdev_list, list) { if (wdev_iter == wdev) continue; if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { @@ -1700,7 +1743,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, */ mutex_lock_nested(&wdev_iter->mtx, 1); __acquire(wdev_iter->mtx); - cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect); + cfg80211_get_chan_state(wdev_iter, &ch, &chmode, + ¶ms.radar_detect); wdev_unlock(wdev_iter); switch (chmode) { @@ -1716,23 +1760,22 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, if (used_channels[i] == NULL) { used_channels[i] = ch; - num_different_channels++; + params.num_different_channels++; } break; case CHAN_MODE_EXCLUSIVE: - num_different_channels++; + params.num_different_channels++; break; } - num[wdev_iter->iftype]++; + params.iftype_num[wdev_iter->iftype]++; total++; } - if (total == 1 && !radar_detect) + if (total == 1 && !params.radar_detect) return 0; - return cfg80211_check_combinations(&rdev->wiphy, num_different_channels, - radar_detect, num); + return cfg80211_check_combinations(&rdev->wiphy, ¶ms); } int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, @@ -1775,10 +1818,10 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy) { - enum ieee80211_band band; + enum nl80211_band band; unsigned int n_channels = 0; - for (band = 0; band < IEEE80211_NUM_BANDS; band++) + for (band = 0; band < NUM_NL80211_BANDS; band++) if (wiphy->bands[band]) n_channels += wiphy->bands[band]->n_channels; @@ -1815,6 +1858,57 @@ const unsigned char bridge_tunnel_header[] __aligned(2) = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; EXPORT_SYMBOL(bridge_tunnel_header); +bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb) +{ + const struct ethhdr *eth = (void *)skb->data; + const struct { + struct arphdr hdr; + u8 ar_sha[ETH_ALEN]; + u8 ar_sip[4]; + u8 ar_tha[ETH_ALEN]; + u8 ar_tip[4]; + } __packed *arp; + const struct ipv6hdr *ipv6; + const struct icmp6hdr *icmpv6; + + switch (eth->h_proto) { + case cpu_to_be16(ETH_P_ARP): + /* can't say - but will probably be dropped later anyway */ + if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*arp))) + return false; + + arp = (void *)(eth + 1); + + if ((arp->hdr.ar_op == cpu_to_be16(ARPOP_REPLY) || + arp->hdr.ar_op == cpu_to_be16(ARPOP_REQUEST)) && + !memcmp(arp->ar_sip, arp->ar_tip, sizeof(arp->ar_sip))) + return true; + break; + case cpu_to_be16(ETH_P_IPV6): + /* can't say - but will probably be dropped later anyway */ + if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*ipv6) + + sizeof(*icmpv6))) + return false; + + ipv6 = (void *)(eth + 1); + icmpv6 = (void *)(ipv6 + 1); + + if (icmpv6->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT && + !memcmp(&ipv6->saddr, &ipv6->daddr, sizeof(ipv6->saddr))) + return true; + break; + default: + /* + * no need to support other protocols, proxy service isn't + * specified for any others + */ + break; + } + + return false; +} +EXPORT_SYMBOL(cfg80211_is_gratuitous_arp_unsolicited_na); + /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ struct iapp_layer2_update { u8 da[ETH_ALEN]; /* broadcast */ |