nl80211: Fixed re-initialization of removed and re-inserted interface

Network device ifindex will change when the interface is re-inserted.
driver_nl80211.c will need to accept netlink events from "unknown" (based
on ifindex) interfaces when a previously used card was removed earlier. If
the previously removed interface is added back, the driver_wext data need
to be updated to match with the new ifindex value. In addition, the initial
setup tasks for the card (set interface up, update ifindex, set mode, etc.)
from wpa_driver_nl80211_init() need to be run again.

This is the changes from commit 3fbda8f943
(driver_wext.c) ported for driver_nl80211.c.
This commit is contained in:
Jouni Malinen 2008-08-15 17:55:16 +03:00 committed by Jouni Malinen
parent 0a4e6cbf88
commit 7524cfb1a3

View file

@ -47,6 +47,7 @@ struct wpa_driver_nl80211_data {
int ioctl_sock; int ioctl_sock;
char ifname[IFNAMSIZ + 1]; char ifname[IFNAMSIZ + 1];
int ifindex; int ifindex;
int if_removed;
u8 *assoc_req_ies; u8 *assoc_req_ies;
size_t assoc_req_ies_len; size_t assoc_req_ies_len;
u8 *assoc_resp_ies; u8 *assoc_resp_ies;
@ -77,6 +78,9 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
static int wpa_driver_nl80211_set_mode(void *priv, int mode); static int wpa_driver_nl80211_set_mode(void *priv, int mode);
static int wpa_driver_nl80211_flush_pmkid(void *priv); static int wpa_driver_nl80211_flush_pmkid(void *priv);
static int wpa_driver_nl80211_get_range(void *priv); static int wpa_driver_nl80211_get_range(void *priv);
static void
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
static int wpa_driver_nl80211_send_oper_ifla( static int wpa_driver_nl80211_send_oper_ifla(
struct wpa_driver_nl80211_data *drv, struct wpa_driver_nl80211_data *drv,
@ -583,8 +587,9 @@ static void wpa_driver_nl80211_event_wireless(struct wpa_driver_nl80211_data *dr
} }
static void wpa_driver_nl80211_event_link(void *ctx, char *buf, size_t len, static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
int del) void *ctx, char *buf, size_t len,
int del)
{ {
union wpa_event_data event; union wpa_event_data event;
@ -600,10 +605,68 @@ static void wpa_driver_nl80211_event_link(void *ctx, char *buf, size_t len,
event.interface_status.ifname, event.interface_status.ifname,
del ? "removed" : "added"); del ? "removed" : "added");
if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
if (del)
drv->if_removed = 1;
else
drv->if_removed = 0;
}
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
} }
static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
struct nlmsghdr *h)
{
struct ifinfomsg *ifi;
int attrlen, _nlmsg_len, rta_len;
struct rtattr *attr;
ifi = NLMSG_DATA(h);
_nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
attrlen = h->nlmsg_len - _nlmsg_len;
if (attrlen < 0)
return 0;
attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_IFNAME) {
if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
== 0)
return 1;
else
break;
}
attr = RTA_NEXT(attr, attrlen);
}
return 0;
}
static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
int ifindex, struct nlmsghdr *h)
{
if (drv->ifindex == ifindex)
return 1;
if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, h)) {
drv->ifindex = if_nametoindex(drv->ifname);
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
wpa_driver_nl80211_finish_drv_init(drv);
return 1;
}
return 0;
}
static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv, static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
void *ctx, struct nlmsghdr *h, void *ctx, struct nlmsghdr *h,
size_t len) size_t len)
@ -617,7 +680,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data
ifi = NLMSG_DATA(h); ifi = NLMSG_DATA(h);
if (drv->ifindex != ifi->ifi_index) { if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, h)) {
wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d", wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
ifi->ifi_index); ifi->ifi_index);
return; return;
@ -656,9 +719,10 @@ static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data
drv, ctx, ((char *) attr) + rta_len, drv, ctx, ((char *) attr) + rta_len,
attr->rta_len - rta_len); attr->rta_len - rta_len);
} else if (attr->rta_type == IFLA_IFNAME) { } else if (attr->rta_type == IFLA_IFNAME) {
wpa_driver_nl80211_event_link(ctx, wpa_driver_nl80211_event_link(
((char *) attr) + rta_len, drv, ctx,
attr->rta_len - rta_len, 0); ((char *) attr) + rta_len,
attr->rta_len - rta_len, 0);
} }
attr = RTA_NEXT(attr, attrlen); attr = RTA_NEXT(attr, attrlen);
} }
@ -689,9 +753,10 @@ static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data
rta_len = RTA_ALIGN(sizeof(struct rtattr)); rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) { while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_IFNAME) { if (attr->rta_type == IFLA_IFNAME) {
wpa_driver_nl80211_event_link(ctx, wpa_driver_nl80211_event_link(
((char *) attr) + rta_len, drv, ctx,
attr->rta_len - rta_len, 1); ((char *) attr) + rta_len,
attr->rta_len - rta_len, 1);
} }
attr = RTA_NEXT(attr, attrlen); attr = RTA_NEXT(attr, attrlen);
} }
@ -833,7 +898,7 @@ static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
*/ */
void * wpa_driver_nl80211_init(void *ctx, const char *ifname) void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
{ {
int s, flags; int s;
struct sockaddr_nl local; struct sockaddr_nl local;
struct wpa_driver_nl80211_data *drv; struct wpa_driver_nl80211_data *drv;
@ -902,6 +967,31 @@ void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
ctx); ctx);
drv->event_sock = s; drv->event_sock = s;
wpa_driver_nl80211_finish_drv_init(drv);
return drv;
err6:
close(drv->ioctl_sock);
err5:
genl_family_put(drv->nl80211);
err4:
nl_cache_free(drv->nl_cache);
err3:
nl_handle_destroy(drv->nl_handle);
err2:
nl_cb_put(drv->nl_cb);
err1:
os_free(drv);
return NULL;
}
static void
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
{
int flags;
if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0) if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0)
printf("Could not get interface '%s' flags\n", drv->ifname); printf("Could not get interface '%s' flags\n", drv->ifname);
else if (!(flags & IFF_UP)) { else if (!(flags & IFF_UP)) {
@ -936,22 +1026,6 @@ void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
drv->ifindex = if_nametoindex(drv->ifname); drv->ifindex = if_nametoindex(drv->ifname);
wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT); wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
return drv;
err6:
close(drv->ioctl_sock);
err5:
genl_family_put(drv->nl80211);
err4:
nl_cache_free(drv->nl_cache);
err3:
nl_handle_destroy(drv->nl_handle);
err2:
nl_cb_put(drv->nl_cb);
err1:
os_free(drv);
return NULL;
} }