aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-01-20 06:02:33 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-22 16:11:16 -0500
commitef15aac6073b27fd4f70007784d2d52ed394bf43 (patch)
tree80eeb99e74263e255d4e8af582550a6363ad7884
parentb3fbdcf49f940d0703c356441e0daf045e64e076 (diff)
cfg80211: export multiple MAC addresses in sysfs
If a device has multiple MAC addresses, userspace will need to know about that. Similarly, if it allows the MAC addresses to vary by a bitmask. If a driver exports multiple addresses, it is assumed that it will be able to deal with that many different addresses, which need not necessarily match the ones programmed into the device; if a mask is set then the device should deal addresses within that mask based on an arbitrary "base address". To test it all and show how it is used, add support to hwsim even though it can't actually deal with addresses different from the default. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c8
-rw-r--r--include/net/cfg80211.h22
-rw-r--r--net/wireless/core.c12
-rw-r--r--net/wireless/sysfs.c20
4 files changed, 60 insertions, 2 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 84df3fcf37b3..0dbda8dfbd99 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -281,6 +281,8 @@ struct mac80211_hwsim_data {
281 struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; 281 struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)];
282 struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; 282 struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
283 283
284 struct mac_address addresses[2];
285
284 struct ieee80211_channel *channel; 286 struct ieee80211_channel *channel;
285 unsigned long beacon_int; /* in jiffies unit */ 287 unsigned long beacon_int; /* in jiffies unit */
286 unsigned int rx_filter; 288 unsigned int rx_filter;
@@ -1154,7 +1156,11 @@ static int __init init_mac80211_hwsim(void)
1154 SET_IEEE80211_DEV(hw, data->dev); 1156 SET_IEEE80211_DEV(hw, data->dev);
1155 addr[3] = i >> 8; 1157 addr[3] = i >> 8;
1156 addr[4] = i; 1158 addr[4] = i;
1157 SET_IEEE80211_PERM_ADDR(hw, addr); 1159 memcpy(data->addresses[0].addr, addr, ETH_ALEN);
1160 memcpy(data->addresses[1].addr, addr, ETH_ALEN);
1161 data->addresses[1].addr[0] |= 0x40;
1162 hw->wiphy->n_addresses = 2;
1163 hw->wiphy->addresses = data->addresses;
1158 1164
1159 hw->channel_change_time = 1; 1165 hw->channel_change_time = 1;
1160 hw->queues = 4; 1166 hw->queues = 4;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2af52704e670..c5d16f299d6f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1195,6 +1195,10 @@ enum wiphy_flags {
1195 WIPHY_FLAG_4ADDR_STATION = BIT(6), 1195 WIPHY_FLAG_4ADDR_STATION = BIT(6),
1196}; 1196};
1197 1197
1198struct mac_address {
1199 u8 addr[ETH_ALEN];
1200};
1201
1198/** 1202/**
1199 * struct wiphy - wireless hardware description 1203 * struct wiphy - wireless hardware description
1200 * @idx: the wiphy index assigned to this item 1204 * @idx: the wiphy index assigned to this item
@@ -1213,12 +1217,28 @@ enum wiphy_flags {
1213 * -1 = fragmentation disabled, only odd values >= 256 used 1217 * -1 = fragmentation disabled, only odd values >= 256 used
1214 * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled 1218 * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
1215 * @net: the network namespace this wiphy currently lives in 1219 * @net: the network namespace this wiphy currently lives in
1220 * @perm_addr: permanent MAC address of this device
1221 * @addr_mask: If the device supports multiple MAC addresses by masking,
1222 * set this to a mask with variable bits set to 1, e.g. if the last
1223 * four bits are variable then set it to 00:...:00:0f. The actual
1224 * variable bits shall be determined by the interfaces added, with
1225 * interfaces not matching the mask being rejected to be brought up.
1226 * @n_addresses: number of addresses in @addresses.
1227 * @addresses: If the device has more than one address, set this pointer
1228 * to a list of addresses (6 bytes each). The first one will be used
1229 * by default for perm_addr. In this case, the mask should be set to
1230 * all-zeroes. In this case it is assumed that the device can handle
1231 * the same number of arbitrary MAC addresses.
1216 */ 1232 */
1217struct wiphy { 1233struct wiphy {
1218 /* assign these fields before you register the wiphy */ 1234 /* assign these fields before you register the wiphy */
1219 1235
1220 /* permanent MAC address */ 1236 /* permanent MAC address(es) */
1221 u8 perm_addr[ETH_ALEN]; 1237 u8 perm_addr[ETH_ALEN];
1238 u8 addr_mask[ETH_ALEN];
1239
1240 u16 n_addresses;
1241 struct mac_address *addresses;
1222 1242
1223 /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ 1243 /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
1224 u16 interface_modes; 1244 u16 interface_modes;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d07f57c906db..71b6b3a9cf1f 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -413,6 +413,18 @@ int wiphy_register(struct wiphy *wiphy)
413 int i; 413 int i;
414 u16 ifmodes = wiphy->interface_modes; 414 u16 ifmodes = wiphy->interface_modes;
415 415
416 if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
417 return -EINVAL;
418
419 if (WARN_ON(wiphy->addresses &&
420 !is_zero_ether_addr(wiphy->perm_addr) &&
421 memcmp(wiphy->perm_addr, wiphy->addresses[0].addr,
422 ETH_ALEN)))
423 return -EINVAL;
424
425 if (wiphy->addresses)
426 memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
427
416 /* sanity check ifmodes */ 428 /* sanity check ifmodes */
417 WARN_ON(!ifmodes); 429 WARN_ON(!ifmodes);
418 ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; 430 ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index efe3c5c92b2d..9f2cef3e0ca0 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -33,10 +33,30 @@ static ssize_t name ## _show(struct device *dev, \
33 33
34SHOW_FMT(index, "%d", wiphy_idx); 34SHOW_FMT(index, "%d", wiphy_idx);
35SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); 35SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
36SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
37
38static ssize_t addresses_show(struct device *dev,
39 struct device_attribute *attr,
40 char *buf)
41{
42 struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy;
43 char *start = buf;
44 int i;
45
46 if (!wiphy->addresses)
47 return sprintf(buf, "%pM\n", wiphy->perm_addr);
48
49 for (i = 0; i < wiphy->n_addresses; i++)
50 buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr);
51
52 return buf - start;
53}
36 54
37static struct device_attribute ieee80211_dev_attrs[] = { 55static struct device_attribute ieee80211_dev_attrs[] = {
38 __ATTR_RO(index), 56 __ATTR_RO(index),
39 __ATTR_RO(macaddress), 57 __ATTR_RO(macaddress),
58 __ATTR_RO(address_mask),
59 __ATTR_RO(addresses),
40 {} 60 {}
41}; 61};
42 62