From 3fbda8f943fff3e8afd649663bdcbba9cbfd6ee3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 25 Jul 2008 01:30:53 +0300 Subject: [PATCH] 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. --- src/drivers/driver_wext.c | 88 ++++++++++++++++++++++++++++++++++----- src/drivers/driver_wext.h | 1 + 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index a7f4ead5d..6aac4276a 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -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; } diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index 590c1e156..b89c2cb2f 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -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;