Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 193678
b: refs/heads/master
c: fa9029f
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Mar 9, 2010
1 parent 65220a9 commit 397f8d3
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: df13cce53a7b28a81460e6bfc4857e9df4956141
refs/heads/master: fa9029f8c34576e121a4b6ddbbd645081fe50c74
116 changes: 114 additions & 2 deletions trunk/net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,118 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
return 0;
}

static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
struct net_device *dev,
enum nl80211_iftype type)
{
struct ieee80211_sub_if_data *sdata;
u64 mask, start, addr, val, inc;
u8 *m;
u8 tmp_addr[ETH_ALEN];
int i;

/* default ... something at least */
memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN);

if (is_zero_ether_addr(local->hw.wiphy->addr_mask) &&
local->hw.wiphy->n_addresses <= 1)
return;


mutex_lock(&local->iflist_mtx);

switch (type) {
case NL80211_IFTYPE_MONITOR:
/* doesn't matter */
break;
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_AP_VLAN:
/* match up with an AP interface */
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_AP)
continue;
memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN);
break;
}
/* keep default if no AP interface present */
break;
default:
/* assign a new address if possible -- try n_addresses first */
for (i = 0; i < local->hw.wiphy->n_addresses; i++) {
bool used = false;

list_for_each_entry(sdata, &local->interfaces, list) {
if (memcmp(local->hw.wiphy->addresses[i].addr,
sdata->vif.addr, ETH_ALEN) == 0) {
used = true;
break;
}
}

if (!used) {
memcpy(dev->perm_addr,
local->hw.wiphy->addresses[i].addr,
ETH_ALEN);
break;
}
}

/* try mask if available */
if (is_zero_ether_addr(local->hw.wiphy->addr_mask))
break;

m = local->hw.wiphy->addr_mask;
mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);

if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {
/* not a contiguous mask ... not handled now! */
printk(KERN_DEBUG "not contiguous\n");
break;
}

m = local->hw.wiphy->perm_addr;
start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);

inc = 1ULL<<__ffs64(mask);
val = (start & mask);
addr = (start & ~mask) | (val & mask);
do {
bool used = false;

tmp_addr[5] = addr >> 0*8;
tmp_addr[4] = addr >> 1*8;
tmp_addr[3] = addr >> 2*8;
tmp_addr[2] = addr >> 3*8;
tmp_addr[1] = addr >> 4*8;
tmp_addr[0] = addr >> 5*8;

val += inc;

list_for_each_entry(sdata, &local->interfaces, list) {
if (memcmp(tmp_addr, sdata->vif.addr,
ETH_ALEN) == 0) {
used = true;
break;
}
}

if (!used) {
memcpy(dev->perm_addr, tmp_addr, ETH_ALEN);
break;
}
addr = (start & ~mask) | (val & mask);
} while (addr != start);

break;
}

mutex_unlock(&local->iflist_mtx);
}

int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device **new_dev, enum nl80211_iftype type,
struct vif_params *params)
Expand Down Expand Up @@ -844,8 +956,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
if (ret < 0)
goto fail;

memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
ieee80211_assign_perm_addr(local, ndev, type);
memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));

/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
Expand Down

0 comments on commit 397f8d3

Please sign in to comment.