nl80211: Add command for changing local MAC address

This can be used to allow wpa_supplicant to control local MAC address
for connections.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-09-27 19:11:24 +03:00
parent 321c7f6034
commit fee354c74d
3 changed files with 73 additions and 0 deletions

View file

@ -2820,6 +2820,14 @@ struct wpa_driver_ops {
*/
int (*roaming)(void *priv, int allowed, const u8 *bssid);
/**
* set_mac_addr - Set MAC address
* @priv: Private driver interface data
* @addr: MAC address to use or %NULL for setting back to permanent
* Returns: 0 on success, -1 on failure
*/
int (*set_mac_addr)(void *priv, const u8 *addr);
#ifdef CONFIG_MACSEC
int (*macsec_init)(void *priv, struct macsec_init_params *params);

View file

@ -253,6 +253,7 @@ struct wpa_driver_nl80211_data {
struct dl_list list;
struct dl_list wiphy_list;
char phyname[32];
u8 perm_addr[ETH_ALEN];
void *ctx;
int ifindex;
int if_removed;
@ -311,6 +312,7 @@ struct wpa_driver_nl80211_data {
unsigned int dfs_vendor_cmd_avail:1;
unsigned int have_low_prio_scan:1;
unsigned int force_connect_cmd:1;
unsigned int addr_changed:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
@ -4874,6 +4876,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
bss->addr))
return -1;
os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
if (send_rfkill_event) {
eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
@ -4962,6 +4965,16 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
if (!drv->start_iface_up)
(void) i802_set_iface_flags(bss, 0);
if (drv->addr_changed) {
linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
drv->perm_addr) < 0) {
wpa_printf(MSG_DEBUG,
"nl80211: Could not restore permanent MAC address");
}
}
if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
if (!drv->hostapd || !drv->start_mode_ap)
wpa_driver_nl80211_set_mode(bss,
@ -10057,6 +10070,7 @@ static void *i802_init(struct hostapd_data *hapd,
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
params->own_addr))
goto failed;
os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
memcpy(bss->addr, params->own_addr, ETH_ALEN);
@ -12012,6 +12026,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
res = os_snprintf(pos, end - pos,
"phyname=%s\n"
"perm_addr=" MACSTR "\n"
"drv_ifindex=%d\n"
"operstate=%d\n"
"scan_state=%s\n"
@ -12028,6 +12043,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
"eapol_tx_sock=%d\n"
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
drv->phyname,
MAC2STR(drv->perm_addr),
drv->ifindex,
drv->operstate,
scan_state_str(drv->scan_state),
@ -12454,6 +12470,46 @@ static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
}
static int nl80211_set_mac_addr(void *priv, const u8 *addr)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int new_addr = addr != NULL;
if (!addr)
addr = drv->perm_addr;
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
return -1;
if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
{
wpa_printf(MSG_DEBUG,
"nl80211: failed to set_mac_addr for %s to " MACSTR,
bss->ifname, MAC2STR(addr));
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
1) < 0) {
wpa_printf(MSG_DEBUG,
"nl80211: Could not restore interface UP after failed set_mac_addr");
}
return -1;
}
wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
bss->ifname, MAC2STR(addr));
drv->addr_changed = new_addr;
os_memcpy(bss->addr, addr, ETH_ALEN);
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
{
wpa_printf(MSG_DEBUG,
"nl80211: Could not restore interface UP after set_mac_addr");
}
return 0;
}
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@ -12546,4 +12602,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_qos_map = nl80211_set_qos_map,
.set_wowlan = nl80211_set_wowlan,
.roaming = nl80211_roaming,
.set_mac_addr = nl80211_set_mac_addr,
};

View file

@ -640,6 +640,14 @@ static inline int wpa_drv_roaming(struct wpa_supplicant *wpa_s, int allowed,
return wpa_s->driver->roaming(wpa_s->drv_priv, allowed, bssid);
}
static inline int wpa_drv_set_mac_addr(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
if (!wpa_s->driver->set_mac_addr)
return -1;
return wpa_s->driver->set_mac_addr(wpa_s->drv_priv, addr);
}
#ifdef CONFIG_MACSEC