diff options
author | Jouni Malinen <j@w1.fi> | 2009-12-18 17:11:54 +0200 |
---|---|---|
committer | Jouni Malinen <j@w1.fi> | 2009-12-18 17:11:54 +0200 |
commit | 08063178fb48e2ee2f46b345326890ac295e2cfa (patch) | |
tree | d7a0a567b891c770a42fe90d55d895c4cf331354 /src | |
parent | e2d02c29b50aebacf13a8dcd3f27f46f9d16dff0 (diff) | |
download | external_wpa_supplicant_8_ti-08063178fb48e2ee2f46b345326890ac295e2cfa.zip external_wpa_supplicant_8_ti-08063178fb48e2ee2f46b345326890ac295e2cfa.tar.gz external_wpa_supplicant_8_ti-08063178fb48e2ee2f46b345326890ac295e2cfa.tar.bz2 |
nl80211/wext: Share netlink new/del link event receive code
Diffstat (limited to 'src')
-rw-r--r-- | src/drivers/driver_nl80211.c | 156 | ||||
-rw-r--r-- | src/drivers/driver_wext.c | 150 | ||||
-rw-r--r-- | src/drivers/driver_wext.h | 2 | ||||
-rw-r--r-- | src/drivers/netlink.c | 131 | ||||
-rw-r--r-- | src/drivers/netlink.h | 13 |
5 files changed, 209 insertions, 243 deletions
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 0fff540..feb910b 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -65,7 +65,7 @@ struct i802_bss { struct wpa_driver_nl80211_data { void *ctx; - int link_event_sock; + struct netlink_data *netlink; int ioctl_sock; /* socket for ioctl() use */ char ifname[IFNAMSIZ + 1]; int ifindex; @@ -325,8 +325,7 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, - void *ctx, char *buf, size_t len, - int del) + char *buf, size_t len, int del) { union wpa_event_data event; @@ -349,7 +348,7 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, drv->if_removed = 0; } - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); } @@ -404,10 +403,10 @@ static int wpa_driver_nl80211_own_ifindex(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, - size_t len) +static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, struct nlmsghdr *h, + size_t len) { + struct wpa_driver_nl80211_data *drv = ctx; struct ifinfomsg *ifi; int attrlen, _nlmsg_len, rta_len; struct rtattr * attr; @@ -439,7 +438,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && !(ifi->ifi_flags & IFF_RUNNING)) - netlink_send_oper_ifla(drv->link_event_sock, drv->ifindex, + netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, IF_OPER_UP); _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); @@ -454,7 +453,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { wpa_driver_nl80211_event_link( - drv, ctx, + drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 0); } @@ -463,10 +462,10 @@ static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data } -static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv, - void *ctx, struct nlmsghdr *h, - size_t len) +static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, struct nlmsghdr *h, + size_t len) { + struct wpa_driver_nl80211_data *drv = ctx; struct ifinfomsg *ifi; int attrlen, _nlmsg_len, rta_len; struct rtattr * attr; @@ -488,7 +487,7 @@ static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { wpa_driver_nl80211_event_link( - drv, ctx, + drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 1); } @@ -497,73 +496,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data } -static void wpa_driver_nl80211_event_receive_link(int sock, void *eloop_ctx, - void *sock_ctx) -{ - char buf[8192]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - int max_events = 10; - -try_again: - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - perror("recvfrom(netlink)"); - return; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - wpa_printf(MSG_DEBUG, "Malformed netlink message: " - "len=%d left=%d plen=%d", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - wpa_driver_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx, - h, plen); - break; - case RTM_DELLINK: - wpa_driver_nl80211_event_rtm_dellink(eloop_ctx, sock_ctx, - h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink " - "message", left); - } - - if (--max_events > 0) { - /* - * Try to receive all events in one eloop call in order to - * limit race condition on cases where AssocInfo event, Assoc - * event, and EAPOL frames are received more or less at the - * same time. We want to process the event messages first - * before starting EAPOL processing. - */ - goto try_again; - } -} - - static void mlme_event_auth(struct wpa_driver_nl80211_data *drv, const u8 *frame, size_t len) { @@ -1204,35 +1136,6 @@ err1: } -static int wpa_driver_nl80211_init_link_events( - struct wpa_driver_nl80211_data *drv) -{ - int s; - struct sockaddr_nl local; - - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); - return -1; - } - - os_memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - return -1; - } - - eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_link, drv, - drv->ctx); - drv->link_event_sock = s; - - return 0; -} - - /** * wpa_driver_nl80211_init - Initialize nl80211 driver interface * @ctx: context to be used when calling wpa_supplicant functions, @@ -1243,6 +1146,7 @@ static int wpa_driver_nl80211_init_link_events( static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) { struct wpa_driver_nl80211_data *drv; + struct netlink_config *cfg; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) @@ -1251,7 +1155,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); drv->monitor_ifidx = -1; drv->monitor_sock = -1; - drv->link_event_sock = -1; drv->ioctl_sock = -1; if (wpa_driver_nl80211_init_nl(drv, ctx)) { @@ -1265,17 +1168,24 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) goto failed; } - if (wpa_driver_nl80211_init_link_events(drv) || - wpa_driver_nl80211_finish_drv_init(drv)) + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + goto failed; + cfg->ctx = drv; + cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink; + cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink; + drv->netlink = netlink_init(cfg); + if (drv->netlink == NULL) { + os_free(cfg); + goto failed; + } + if (wpa_driver_nl80211_finish_drv_init(drv)) goto failed; return drv; failed: - if (drv->link_event_sock >= 0) { - eloop_unregister_read_sock(drv->link_event_sock); - close(drv->link_event_sock); - } + netlink_deinit(drv->netlink); if (drv->ioctl_sock >= 0) close(drv->ioctl_sock); @@ -1309,7 +1219,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) if (wpa_driver_nl80211_capa(drv)) return -1; - netlink_send_oper_ifla(drv->link_event_sock, drv->ifindex, + netlink_send_oper_ifla(drv->netlink, drv->ifindex, 1, IF_OPER_DORMANT); #endif /* HOSTAPD */ @@ -1389,13 +1299,8 @@ static void wpa_driver_nl80211_deinit(void *priv) wpa_driver_nl80211_free_bss(drv); #endif /* HOSTAPD */ - netlink_send_oper_ifla(drv->link_event_sock, drv->ifindex, - 0, IF_OPER_UP); - - if (drv->link_event_sock >= 0) { - eloop_unregister_read_sock(drv->link_event_sock); - close(drv->link_event_sock); - } + netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); + netlink_deinit(drv->netlink); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); @@ -3709,8 +3614,7 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state) wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", __func__, drv->operstate, state, state ? "UP" : "DORMANT"); drv->operstate = state; - return netlink_send_oper_ifla(drv->link_event_sock, drv->ifindex, - -1, + return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); } diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index cdd67c1..9401c77 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -419,7 +419,7 @@ static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv) static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, - void *ctx, char *data, int len) + char *data, int len) { struct iw_event iwe_buf, *iwe = &iwe_buf; char *pos, *end, *custom, *buf; @@ -467,12 +467,13 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, drv->assoc_req_ies = NULL; os_free(drv->assoc_resp_ies); drv->assoc_resp_ies = NULL; - wpa_supplicant_event(ctx, EVENT_DISASSOC, + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); } else { wpa_driver_wext_event_assoc_ies(drv); - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, + NULL); } break; case IWEVMICHAELMICFAILURE: @@ -482,7 +483,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, return; } wpa_driver_wext_event_wireless_michaelmicfailure( - ctx, custom, iwe->u.data.length); + drv->ctx, custom, iwe->u.data.length); break; case IWEVCUSTOM: if (custom + iwe->u.data.length > end) { @@ -495,14 +496,15 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, return; os_memcpy(buf, custom, iwe->u.data.length); buf[iwe->u.data.length] = '\0'; - wpa_driver_wext_event_wireless_custom(ctx, buf); + wpa_driver_wext_event_wireless_custom(drv->ctx, buf); os_free(buf); break; case SIOCGIWSCAN: drv->scan_complete_events = 1; eloop_cancel_timeout(wpa_driver_wext_scan_timeout, - drv, ctx); - wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); + drv, drv->ctx); + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, + NULL); break; case IWEVASSOCREQIE: if (custom + iwe->u.data.length > end) { @@ -539,8 +541,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, - void *ctx, char *buf, size_t len, - int del) + char *buf, size_t len, int del) { union wpa_event_data event; @@ -563,7 +564,7 @@ static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, drv->if_removed = 0; } - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); } @@ -618,13 +619,13 @@ static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv, } -static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv, - void *ctx, struct nlmsghdr *h, +static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct nlmsghdr *h, size_t len) { + struct wpa_driver_wext_data *drv = ctx; struct ifinfomsg *ifi; int attrlen, nlmsg_len, rta_len; - struct rtattr * attr; + struct rtattr *attr; if (len < sizeof(*ifi)) return; @@ -653,7 +654,7 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv, if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && !(ifi->ifi_flags & IFF_RUNNING)) - netlink_send_oper_ifla(drv->event_sock, drv->ifindex, + netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, IF_OPER_UP); nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); @@ -668,10 +669,10 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv, while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_WIRELESS) { wpa_driver_wext_event_wireless( - drv, ctx, ((char *) attr) + rta_len, + drv, ((char *) attr) + rta_len, attr->rta_len - rta_len); } else if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_wext_event_link(drv, ctx, + wpa_driver_wext_event_link(drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 0); } @@ -680,13 +681,13 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv, } -static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv, - void *ctx, struct nlmsghdr *h, +static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct nlmsghdr *h, size_t len) { + struct wpa_driver_wext_data *drv = ctx; struct ifinfomsg *ifi; int attrlen, nlmsg_len, rta_len; - struct rtattr * attr; + struct rtattr *attr; if (len < sizeof(*ifi)) return; @@ -704,7 +705,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(drv, ctx, + wpa_driver_wext_event_link(drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 1); } @@ -713,73 +714,6 @@ static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv, } -static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx, - void *sock_ctx) -{ - char buf[8192]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - int max_events = 10; - -try_again: - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - perror("recvfrom(netlink)"); - return; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - wpa_printf(MSG_DEBUG, "Malformed netlink message: " - "len=%d left=%d plen=%d", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - wpa_driver_wext_event_rtm_newlink(eloop_ctx, sock_ctx, - h, plen); - break; - case RTM_DELLINK: - wpa_driver_wext_event_rtm_dellink(eloop_ctx, sock_ctx, - h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink " - "message", left); - } - - if (--max_events > 0) { - /* - * Try to receive all events in one eloop call in order to - * limit race condition on cases where AssocInfo event, Assoc - * event, and EAPOL frames are received more or less at the - * same time. We want to process the event messages first - * before starting EAPOL processing. - */ - goto try_again; - } -} - - static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv, const char *ifname, int *flags) { @@ -845,9 +779,8 @@ 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; - struct sockaddr_nl local; struct wpa_driver_wext_data *drv; + struct netlink_config *cfg; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) @@ -861,36 +794,29 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) goto err1; } - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + goto err1; + cfg->ctx = drv; + cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink; + cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink; + drv->netlink = netlink_init(cfg); + if (drv->netlink == NULL) { + os_free(cfg); goto err2; } - drv->event_sock = s; - - os_memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - goto err3; - } - - eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx); drv->mlme_sock = -1; if (wpa_driver_wext_finish_drv_init(drv) < 0) - goto err4; + goto err3; wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1); return drv; -err4: - eloop_unregister_read_sock(drv->event_sock); err3: - close(drv->event_sock); + netlink_deinit(drv->netlink); err2: close(drv->ioctl_sock); err1: @@ -965,7 +891,7 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) wpa_driver_wext_alternative_ifindex(drv, ifname2); } - netlink_send_oper_ifla(drv->event_sock, drv->ifindex, + netlink_send_oper_ifla(drv->netlink, drv->ifindex, 1, IF_OPER_DORMANT); return 0; @@ -994,16 +920,15 @@ void wpa_driver_wext_deinit(void *priv) */ wpa_driver_wext_disconnect(drv); - netlink_send_oper_ifla(drv->event_sock, drv->ifindex, 0, IF_OPER_UP); + netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); + netlink_deinit(drv->netlink); - eloop_unregister_read_sock(drv->event_sock); if (drv->mlme_sock >= 0) eloop_unregister_read_sock(drv->mlme_sock); if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP); - close(drv->event_sock); close(drv->ioctl_sock); if (drv->mlme_sock >= 0) close(drv->mlme_sock); @@ -2303,8 +2228,7 @@ int wpa_driver_wext_set_operstate(void *priv, int state) wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", __func__, drv->operstate, state, state ? "UP" : "DORMANT"); drv->operstate = state; - return netlink_send_oper_ifla(drv->event_sock, drv->ifindex, - -1, + return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); } diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index 1999e2f..8c64974 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -19,7 +19,7 @@ struct wpa_driver_wext_data { void *ctx; - int event_sock; + struct netlink_data *netlink; int ioctl_sock; int mlme_sock; char ifname[IFNAMSIZ + 1]; diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c index 98ec387..5e61183 100644 --- a/src/drivers/netlink.c +++ b/src/drivers/netlink.c @@ -15,11 +15,138 @@ #include "includes.h" #include "common.h" +#include "eloop.h" #include "priv_netlink.h" #include "netlink.h" -int netlink_send_oper_ifla(int sock, int ifindex, int linkmode, int operstate) +struct netlink_data { + struct netlink_config *cfg; + int sock; +}; + + +static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct netlink_data *netlink = eloop_ctx; + char buf[8192]; + int left; + struct sockaddr_nl from; + socklen_t fromlen; + struct nlmsghdr *h; + int max_events = 10; + +try_again: + fromlen = sizeof(from); + left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, + (struct sockaddr *) &from, &fromlen); + if (left < 0) { + if (errno != EINTR && errno != EAGAIN) + wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s", + strerror(errno)); + return; + } + + h = (struct nlmsghdr *) buf; + while (left >= (int) sizeof(*h)) { + int len, plen; + + len = h->nlmsg_len; + plen = len - sizeof(*h); + if (len > left || plen < 0) { + wpa_printf(MSG_DEBUG, "netlnk: Malformed message: " + "len=%d left=%d plen=%d", + len, left, plen); + break; + } + + switch (h->nlmsg_type) { + case RTM_NEWLINK: + if (netlink->cfg->newlink_cb) + netlink->cfg->newlink_cb(netlink->cfg->ctx, + h, plen); + break; + case RTM_DELLINK: + if (netlink->cfg->dellink_cb) + netlink->cfg->dellink_cb(netlink->cfg->ctx, + h, plen); + break; + } + + len = NLMSG_ALIGN(len); + left -= len; + h = (struct nlmsghdr *) ((char *) h + len); + } + + if (left > 0) { + wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of " + "netlink message", left); + } + + if (--max_events > 0) { + /* + * Try to receive all events in one eloop call in order to + * limit race condition on cases where AssocInfo event, Assoc + * event, and EAPOL frames are received more or less at the + * same time. We want to process the event messages first + * before starting EAPOL processing. + */ + goto try_again; + } +} + + +struct netlink_data * netlink_init(struct netlink_config *cfg) +{ + struct netlink_data *netlink; + struct sockaddr_nl local; + + netlink = os_zalloc(sizeof(*netlink)); + if (netlink == NULL) + return NULL; + + netlink->cfg = cfg; + + netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (netlink->sock < 0) { + wpa_printf(MSG_ERROR, "netlink: Failed to open netlink " + "socket: %s", strerror(errno)); + netlink_deinit(netlink); + return NULL; + } + + os_memset(&local, 0, sizeof(local)); + local.nl_family = AF_NETLINK; + local.nl_groups = RTMGRP_LINK; + if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0) + { + wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink " + "socket: %s", strerror(errno)); + netlink_deinit(netlink); + return NULL; + } + + eloop_register_read_sock(netlink->sock, netlink_receive, netlink, + NULL); + + return netlink; +} + + +void netlink_deinit(struct netlink_data *netlink) +{ + if (netlink == NULL) + return; + if (netlink->sock >= 0) { + eloop_unregister_read_sock(netlink->sock); + close(netlink->sock); + } + os_free(netlink->cfg); + os_free(netlink); +} + +int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, + int linkmode, int operstate) { struct { struct nlmsghdr hdr; @@ -68,7 +195,7 @@ int netlink_send_oper_ifla(int sock, int ifindex, int linkmode, int operstate) wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d", linkmode, operstate); - ret = send(sock, &req, req.hdr.nlmsg_len, 0); + ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0); if (ret < 0) { wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA " "failed: %s (assume operstate is not supported)", diff --git a/src/drivers/netlink.h b/src/drivers/netlink.h index c2cf59d..ee595c1 100644 --- a/src/drivers/netlink.h +++ b/src/drivers/netlink.h @@ -15,6 +15,17 @@ #ifndef NETLINK_H #define NETLINK_H -int netlink_send_oper_ifla(int sock, int ifindex, int linkmode, int operstate); +struct netlink_data; + +struct netlink_config { + void *ctx; + void (*newlink_cb)(void *ctx, struct nlmsghdr *buf, size_t len); + void (*dellink_cb)(void *ctx, struct nlmsghdr *buf, size_t len); +}; + +struct netlink_data * netlink_init(struct netlink_config *cfg); +void netlink_deinit(struct netlink_data *netlink); +int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, + int linkmode, int operstate); #endif /* NETLINK_H */ |