diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 84df3fcf37b393c35d4fac12ce948448a7191d12..0dbda8dfbd9941bcbcaaa36e3d58e3065283b55f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -281,6 +281,8 @@ struct mac80211_hwsim_data { struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; + struct mac_address addresses[2]; + struct ieee80211_channel *channel; unsigned long beacon_int; /* in jiffies unit */ unsigned int rx_filter; @@ -1154,7 +1156,11 @@ static int __init init_mac80211_hwsim(void) SET_IEEE80211_DEV(hw, data->dev); addr[3] = i >> 8; addr[4] = i; - SET_IEEE80211_PERM_ADDR(hw, addr); + memcpy(data->addresses[0].addr, addr, ETH_ALEN); + memcpy(data->addresses[1].addr, addr, ETH_ALEN); + data->addresses[1].addr[0] |= 0x40; + hw->wiphy->n_addresses = 2; + hw->wiphy->addresses = data->addresses; hw->channel_change_time = 1; hw->queues = 4; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2af52704e670590d9792a0d0a4b44e159e6104ef..c5d16f299d6f17b5912270b30ff0a0ac2b3d01d8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1195,6 +1195,10 @@ enum wiphy_flags { WIPHY_FLAG_4ADDR_STATION = BIT(6), }; +struct mac_address { + u8 addr[ETH_ALEN]; +}; + /** * struct wiphy - wireless hardware description * @idx: the wiphy index assigned to this item @@ -1213,12 +1217,28 @@ enum wiphy_flags { * -1 = fragmentation disabled, only odd values >= 256 used * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled * @net: the network namespace this wiphy currently lives in + * @perm_addr: permanent MAC address of this device + * @addr_mask: If the device supports multiple MAC addresses by masking, + * set this to a mask with variable bits set to 1, e.g. if the last + * four bits are variable then set it to 00:...:00:0f. The actual + * variable bits shall be determined by the interfaces added, with + * interfaces not matching the mask being rejected to be brought up. + * @n_addresses: number of addresses in @addresses. + * @addresses: If the device has more than one address, set this pointer + * to a list of addresses (6 bytes each). The first one will be used + * by default for perm_addr. In this case, the mask should be set to + * all-zeroes. In this case it is assumed that the device can handle + * the same number of arbitrary MAC addresses. */ struct wiphy { /* assign these fields before you register the wiphy */ - /* permanent MAC address */ + /* permanent MAC address(es) */ u8 perm_addr[ETH_ALEN]; + u8 addr_mask[ETH_ALEN]; + + u16 n_addresses; + struct mac_address *addresses; /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ u16 interface_modes; diff --git a/net/wireless/core.c b/net/wireless/core.c index d07f57c906dbe968011457ed31ee8c827f489370..71b6b3a9cf1f1b38484a1764c43d17d3c0372d86 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -413,6 +413,18 @@ int wiphy_register(struct wiphy *wiphy) int i; u16 ifmodes = wiphy->interface_modes; + if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) + return -EINVAL; + + if (WARN_ON(wiphy->addresses && + !is_zero_ether_addr(wiphy->perm_addr) && + memcmp(wiphy->perm_addr, wiphy->addresses[0].addr, + ETH_ALEN))) + return -EINVAL; + + if (wiphy->addresses) + memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); + /* sanity check ifmodes */ WARN_ON(!ifmodes); ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index efe3c5c92b2dedbb48271d89d1664cd57cf182cf..9f2cef3e0ca0cd21640127a27fd72edba88434a5 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -33,10 +33,30 @@ static ssize_t name ## _show(struct device *dev, \ SHOW_FMT(index, "%d", wiphy_idx); SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); +SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); + +static ssize_t addresses_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; + char *start = buf; + int i; + + if (!wiphy->addresses) + return sprintf(buf, "%pM\n", wiphy->perm_addr); + + for (i = 0; i < wiphy->n_addresses; i++) + buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr); + + return buf - start; +} static struct device_attribute ieee80211_dev_attrs[] = { __ATTR_RO(index), __ATTR_RO(macaddress), + __ATTR_RO(address_mask), + __ATTR_RO(addresses), {} };