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

Network device ifindex will change when the interface is re-inserted.
driver_wext.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_wext_init() need to be run again.
This commit is contained in:
Jouni Malinen 2008-07-25 01:30:53 +03:00
parent 27e120c46d
commit 3fbda8f943
2 changed files with 79 additions and 10 deletions

View File

@ -154,6 +154,8 @@ enum {
static int wpa_driver_wext_flush_pmkid(void *priv);
static int wpa_driver_wext_get_range(void *priv);
static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
int linkmode, int operstate)
@ -689,7 +691,8 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
}
static void wpa_driver_wext_event_link(void *ctx, char *buf, size_t len,
static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
void *ctx, char *buf, size_t len,
int del)
{
union wpa_event_data event;
@ -706,10 +709,68 @@ static void wpa_driver_wext_event_link(void *ctx, char *buf, size_t len,
event.interface_status.ifname,
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);
}
static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_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_wext_own_ifindex(struct wpa_driver_wext_data *drv,
int ifindex, struct nlmsghdr *h)
{
if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
return 1;
if (drv->if_removed && wpa_driver_wext_own_ifname(drv, h)) {
drv->ifindex = if_nametoindex(drv->ifname);
wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
"interface");
wpa_driver_wext_finish_drv_init(drv);
return 1;
}
return 0;
}
static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
void *ctx, struct nlmsghdr *h,
size_t len)
@ -723,8 +784,7 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
ifi = NLMSG_DATA(h);
if (drv->ifindex != ifi->ifi_index && drv->ifindex2 != ifi->ifi_index)
{
if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, h)) {
wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
ifi->ifi_index);
return;
@ -763,7 +823,7 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
drv, ctx, ((char *) attr) + rta_len,
attr->rta_len - rta_len);
} else if (attr->rta_type == IFLA_IFNAME) {
wpa_driver_wext_event_link(ctx,
wpa_driver_wext_event_link(drv, ctx,
((char *) attr) + rta_len,
attr->rta_len - rta_len, 0);
}
@ -796,7 +856,7 @@ static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv,
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
if (attr->rta_type == IFLA_IFNAME) {
wpa_driver_wext_event_link(ctx,
wpa_driver_wext_event_link(drv, ctx,
((char *) attr) + rta_len,
attr->rta_len - rta_len, 1);
}
@ -977,7 +1037,7 @@ int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags)
*/
void * wpa_driver_wext_init(void *ctx, const char *ifname)
{
int s, flags;
int s;
struct sockaddr_nl local;
struct wpa_driver_wext_data *drv;
@ -1018,6 +1078,16 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
drv->mlme_sock = -1;
wpa_driver_wext_finish_drv_init(drv);
return drv;
}
static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
{
int flags;
if (wpa_driver_wext_get_ifflags(drv, &flags) != 0)
printf("Could not get interface '%s' flags\n", drv->ifname);
else if (!(flags & IFF_UP)) {
@ -1051,7 +1121,7 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
drv->ifindex = if_nametoindex(drv->ifname);
if (os_strncmp(ifname, "wlan", 4) == 0) {
if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
/*
* Host AP driver may use both wlan# and wifi# interface in
* wireless events. Since some of the versions included WE-18
@ -1061,14 +1131,12 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
* driver are not in use anymore.
*/
char ifname2[IFNAMSIZ + 1];
os_strlcpy(ifname2, ifname, sizeof(ifname2));
os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
os_memcpy(ifname2, "wifi", 4);
wpa_driver_wext_alternative_ifindex(drv, ifname2);
}
wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
return drv;
}

View File

@ -25,6 +25,7 @@ struct wpa_driver_wext_data {
char ifname[IFNAMSIZ + 1];
int ifindex;
int ifindex2;
int if_removed;
u8 *assoc_req_ies;
size_t assoc_req_ies_len;
u8 *assoc_resp_ies;