mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-02-06 12:14:04 -05:00
nl80211/wext: Share netlink new/del link event receive code
This commit is contained in:
parent
e2d02c29b5
commit
08063178fb
@ -65,7 +65,7 @@ struct i802_bss {
|
|||||||
|
|
||||||
struct wpa_driver_nl80211_data {
|
struct wpa_driver_nl80211_data {
|
||||||
void *ctx;
|
void *ctx;
|
||||||
int link_event_sock;
|
struct netlink_data *netlink;
|
||||||
int ioctl_sock; /* socket for ioctl() use */
|
int ioctl_sock; /* socket for ioctl() use */
|
||||||
char ifname[IFNAMSIZ + 1];
|
char ifname[IFNAMSIZ + 1];
|
||||||
int ifindex;
|
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,
|
static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
|
||||||
void *ctx, char *buf, size_t len,
|
char *buf, size_t len, int del)
|
||||||
int del)
|
|
||||||
{
|
{
|
||||||
union wpa_event_data event;
|
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;
|
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,
|
static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, struct nlmsghdr *h,
|
||||||
void *ctx, struct nlmsghdr *h,
|
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
|
struct wpa_driver_nl80211_data *drv = ctx;
|
||||||
struct ifinfomsg *ifi;
|
struct ifinfomsg *ifi;
|
||||||
int attrlen, _nlmsg_len, rta_len;
|
int attrlen, _nlmsg_len, rta_len;
|
||||||
struct rtattr * attr;
|
struct rtattr * attr;
|
||||||
@ -439,7 +438,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data
|
|||||||
if (drv->operstate == 1 &&
|
if (drv->operstate == 1 &&
|
||||||
(ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
|
(ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
|
||||||
!(ifi->ifi_flags & IFF_RUNNING))
|
!(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);
|
-1, IF_OPER_UP);
|
||||||
|
|
||||||
_nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
|
_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)) {
|
while (RTA_OK(attr, attrlen)) {
|
||||||
if (attr->rta_type == IFLA_IFNAME) {
|
if (attr->rta_type == IFLA_IFNAME) {
|
||||||
wpa_driver_nl80211_event_link(
|
wpa_driver_nl80211_event_link(
|
||||||
drv, ctx,
|
drv,
|
||||||
((char *) attr) + rta_len,
|
((char *) attr) + rta_len,
|
||||||
attr->rta_len - rta_len, 0);
|
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,
|
static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, struct nlmsghdr *h,
|
||||||
void *ctx, struct nlmsghdr *h,
|
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
|
struct wpa_driver_nl80211_data *drv = ctx;
|
||||||
struct ifinfomsg *ifi;
|
struct ifinfomsg *ifi;
|
||||||
int attrlen, _nlmsg_len, rta_len;
|
int attrlen, _nlmsg_len, rta_len;
|
||||||
struct rtattr * attr;
|
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)) {
|
while (RTA_OK(attr, attrlen)) {
|
||||||
if (attr->rta_type == IFLA_IFNAME) {
|
if (attr->rta_type == IFLA_IFNAME) {
|
||||||
wpa_driver_nl80211_event_link(
|
wpa_driver_nl80211_event_link(
|
||||||
drv, ctx,
|
drv,
|
||||||
((char *) attr) + rta_len,
|
((char *) attr) + rta_len,
|
||||||
attr->rta_len - rta_len, 1);
|
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,
|
static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
|
||||||
const u8 *frame, size_t len)
|
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
|
* wpa_driver_nl80211_init - Initialize nl80211 driver interface
|
||||||
* @ctx: context to be used when calling wpa_supplicant functions,
|
* @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)
|
static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
|
||||||
{
|
{
|
||||||
struct wpa_driver_nl80211_data *drv;
|
struct wpa_driver_nl80211_data *drv;
|
||||||
|
struct netlink_config *cfg;
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
drv = os_zalloc(sizeof(*drv));
|
||||||
if (drv == NULL)
|
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));
|
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||||
drv->monitor_ifidx = -1;
|
drv->monitor_ifidx = -1;
|
||||||
drv->monitor_sock = -1;
|
drv->monitor_sock = -1;
|
||||||
drv->link_event_sock = -1;
|
|
||||||
drv->ioctl_sock = -1;
|
drv->ioctl_sock = -1;
|
||||||
|
|
||||||
if (wpa_driver_nl80211_init_nl(drv, ctx)) {
|
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;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpa_driver_nl80211_init_link_events(drv) ||
|
cfg = os_zalloc(sizeof(*cfg));
|
||||||
wpa_driver_nl80211_finish_drv_init(drv))
|
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;
|
goto failed;
|
||||||
|
|
||||||
return drv;
|
return drv;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
if (drv->link_event_sock >= 0) {
|
netlink_deinit(drv->netlink);
|
||||||
eloop_unregister_read_sock(drv->link_event_sock);
|
|
||||||
close(drv->link_event_sock);
|
|
||||||
}
|
|
||||||
if (drv->ioctl_sock >= 0)
|
if (drv->ioctl_sock >= 0)
|
||||||
close(drv->ioctl_sock);
|
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))
|
if (wpa_driver_nl80211_capa(drv))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
netlink_send_oper_ifla(drv->link_event_sock, drv->ifindex,
|
netlink_send_oper_ifla(drv->netlink, drv->ifindex,
|
||||||
1, IF_OPER_DORMANT);
|
1, IF_OPER_DORMANT);
|
||||||
#endif /* HOSTAPD */
|
#endif /* HOSTAPD */
|
||||||
|
|
||||||
@ -1389,13 +1299,8 @@ static void wpa_driver_nl80211_deinit(void *priv)
|
|||||||
wpa_driver_nl80211_free_bss(drv);
|
wpa_driver_nl80211_free_bss(drv);
|
||||||
#endif /* HOSTAPD */
|
#endif /* HOSTAPD */
|
||||||
|
|
||||||
netlink_send_oper_ifla(drv->link_event_sock, drv->ifindex,
|
netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
|
||||||
0, IF_OPER_UP);
|
netlink_deinit(drv->netlink);
|
||||||
|
|
||||||
if (drv->link_event_sock >= 0) {
|
|
||||||
eloop_unregister_read_sock(drv->link_event_sock);
|
|
||||||
close(drv->link_event_sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
|
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)",
|
wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
|
||||||
__func__, drv->operstate, state, state ? "UP" : "DORMANT");
|
__func__, drv->operstate, state, state ? "UP" : "DORMANT");
|
||||||
drv->operstate = state;
|
drv->operstate = state;
|
||||||
return netlink_send_oper_ifla(drv->link_event_sock, drv->ifindex,
|
return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
|
||||||
-1,
|
|
||||||
state ? IF_OPER_UP : IF_OPER_DORMANT);
|
state ? IF_OPER_UP : IF_OPER_DORMANT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
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;
|
struct iw_event iwe_buf, *iwe = &iwe_buf;
|
||||||
char *pos, *end, *custom, *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;
|
drv->assoc_req_ies = NULL;
|
||||||
os_free(drv->assoc_resp_ies);
|
os_free(drv->assoc_resp_ies);
|
||||||
drv->assoc_resp_ies = NULL;
|
drv->assoc_resp_ies = NULL;
|
||||||
wpa_supplicant_event(ctx, EVENT_DISASSOC,
|
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
wpa_driver_wext_event_assoc_ies(drv);
|
wpa_driver_wext_event_assoc_ies(drv);
|
||||||
wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
|
wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IWEVMICHAELMICFAILURE:
|
case IWEVMICHAELMICFAILURE:
|
||||||
@ -482,7 +483,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wpa_driver_wext_event_wireless_michaelmicfailure(
|
wpa_driver_wext_event_wireless_michaelmicfailure(
|
||||||
ctx, custom, iwe->u.data.length);
|
drv->ctx, custom, iwe->u.data.length);
|
||||||
break;
|
break;
|
||||||
case IWEVCUSTOM:
|
case IWEVCUSTOM:
|
||||||
if (custom + iwe->u.data.length > end) {
|
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;
|
return;
|
||||||
os_memcpy(buf, custom, iwe->u.data.length);
|
os_memcpy(buf, custom, iwe->u.data.length);
|
||||||
buf[iwe->u.data.length] = '\0';
|
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);
|
os_free(buf);
|
||||||
break;
|
break;
|
||||||
case SIOCGIWSCAN:
|
case SIOCGIWSCAN:
|
||||||
drv->scan_complete_events = 1;
|
drv->scan_complete_events = 1;
|
||||||
eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
|
eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
|
||||||
drv, ctx);
|
drv, drv->ctx);
|
||||||
wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
|
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
|
||||||
|
NULL);
|
||||||
break;
|
break;
|
||||||
case IWEVASSOCREQIE:
|
case IWEVASSOCREQIE:
|
||||||
if (custom + iwe->u.data.length > end) {
|
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,
|
static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
|
||||||
void *ctx, char *buf, size_t len,
|
char *buf, size_t len, int del)
|
||||||
int del)
|
|
||||||
{
|
{
|
||||||
union wpa_event_data event;
|
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;
|
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,
|
static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct nlmsghdr *h,
|
||||||
void *ctx, struct nlmsghdr *h,
|
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
|
struct wpa_driver_wext_data *drv = ctx;
|
||||||
struct ifinfomsg *ifi;
|
struct ifinfomsg *ifi;
|
||||||
int attrlen, nlmsg_len, rta_len;
|
int attrlen, nlmsg_len, rta_len;
|
||||||
struct rtattr * attr;
|
struct rtattr *attr;
|
||||||
|
|
||||||
if (len < sizeof(*ifi))
|
if (len < sizeof(*ifi))
|
||||||
return;
|
return;
|
||||||
@ -653,7 +654,7 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
|
|||||||
if (drv->operstate == 1 &&
|
if (drv->operstate == 1 &&
|
||||||
(ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
|
(ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
|
||||||
!(ifi->ifi_flags & IFF_RUNNING))
|
!(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);
|
-1, IF_OPER_UP);
|
||||||
|
|
||||||
nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
|
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)) {
|
while (RTA_OK(attr, attrlen)) {
|
||||||
if (attr->rta_type == IFLA_WIRELESS) {
|
if (attr->rta_type == IFLA_WIRELESS) {
|
||||||
wpa_driver_wext_event_wireless(
|
wpa_driver_wext_event_wireless(
|
||||||
drv, ctx, ((char *) attr) + rta_len,
|
drv, ((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_wext_event_link(drv, ctx,
|
wpa_driver_wext_event_link(drv,
|
||||||
((char *) attr) + rta_len,
|
((char *) attr) + rta_len,
|
||||||
attr->rta_len - rta_len, 0);
|
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,
|
static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct nlmsghdr *h,
|
||||||
void *ctx, struct nlmsghdr *h,
|
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
|
struct wpa_driver_wext_data *drv = ctx;
|
||||||
struct ifinfomsg *ifi;
|
struct ifinfomsg *ifi;
|
||||||
int attrlen, nlmsg_len, rta_len;
|
int attrlen, nlmsg_len, rta_len;
|
||||||
struct rtattr * attr;
|
struct rtattr *attr;
|
||||||
|
|
||||||
if (len < sizeof(*ifi))
|
if (len < sizeof(*ifi))
|
||||||
return;
|
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));
|
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_wext_event_link(drv, ctx,
|
wpa_driver_wext_event_link(drv,
|
||||||
((char *) attr) + rta_len,
|
((char *) attr) + rta_len,
|
||||||
attr->rta_len - rta_len, 1);
|
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,
|
static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv,
|
||||||
const char *ifname, int *flags)
|
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)
|
void * wpa_driver_wext_init(void *ctx, const char *ifname)
|
||||||
{
|
{
|
||||||
int s;
|
|
||||||
struct sockaddr_nl local;
|
|
||||||
struct wpa_driver_wext_data *drv;
|
struct wpa_driver_wext_data *drv;
|
||||||
|
struct netlink_config *cfg;
|
||||||
|
|
||||||
drv = os_zalloc(sizeof(*drv));
|
drv = os_zalloc(sizeof(*drv));
|
||||||
if (drv == NULL)
|
if (drv == NULL)
|
||||||
@ -861,36 +794,29 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
|
|||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
cfg = os_zalloc(sizeof(*cfg));
|
||||||
if (s < 0) {
|
if (cfg == NULL)
|
||||||
perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
|
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;
|
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;
|
drv->mlme_sock = -1;
|
||||||
|
|
||||||
if (wpa_driver_wext_finish_drv_init(drv) < 0)
|
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);
|
wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
|
||||||
|
|
||||||
return drv;
|
return drv;
|
||||||
|
|
||||||
err4:
|
|
||||||
eloop_unregister_read_sock(drv->event_sock);
|
|
||||||
err3:
|
err3:
|
||||||
close(drv->event_sock);
|
netlink_deinit(drv->netlink);
|
||||||
err2:
|
err2:
|
||||||
close(drv->ioctl_sock);
|
close(drv->ioctl_sock);
|
||||||
err1:
|
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);
|
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);
|
1, IF_OPER_DORMANT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -994,16 +920,15 @@ void wpa_driver_wext_deinit(void *priv)
|
|||||||
*/
|
*/
|
||||||
wpa_driver_wext_disconnect(drv);
|
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)
|
if (drv->mlme_sock >= 0)
|
||||||
eloop_unregister_read_sock(drv->mlme_sock);
|
eloop_unregister_read_sock(drv->mlme_sock);
|
||||||
|
|
||||||
if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
|
if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
|
||||||
(void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
|
(void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
|
||||||
|
|
||||||
close(drv->event_sock);
|
|
||||||
close(drv->ioctl_sock);
|
close(drv->ioctl_sock);
|
||||||
if (drv->mlme_sock >= 0)
|
if (drv->mlme_sock >= 0)
|
||||||
close(drv->mlme_sock);
|
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)",
|
wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
|
||||||
__func__, drv->operstate, state, state ? "UP" : "DORMANT");
|
__func__, drv->operstate, state, state ? "UP" : "DORMANT");
|
||||||
drv->operstate = state;
|
drv->operstate = state;
|
||||||
return netlink_send_oper_ifla(drv->event_sock, drv->ifindex,
|
return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
|
||||||
-1,
|
|
||||||
state ? IF_OPER_UP : IF_OPER_DORMANT);
|
state ? IF_OPER_UP : IF_OPER_DORMANT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
struct wpa_driver_wext_data {
|
struct wpa_driver_wext_data {
|
||||||
void *ctx;
|
void *ctx;
|
||||||
int event_sock;
|
struct netlink_data *netlink;
|
||||||
int ioctl_sock;
|
int ioctl_sock;
|
||||||
int mlme_sock;
|
int mlme_sock;
|
||||||
char ifname[IFNAMSIZ + 1];
|
char ifname[IFNAMSIZ + 1];
|
||||||
|
@ -15,11 +15,138 @@
|
|||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "eloop.h"
|
||||||
#include "priv_netlink.h"
|
#include "priv_netlink.h"
|
||||||
#include "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 {
|
||||||
struct nlmsghdr hdr;
|
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",
|
wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d",
|
||||||
linkmode, operstate);
|
linkmode, operstate);
|
||||||
|
|
||||||
ret = send(sock, &req, req.hdr.nlmsg_len, 0);
|
ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
|
wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
|
||||||
"failed: %s (assume operstate is not supported)",
|
"failed: %s (assume operstate is not supported)",
|
||||||
|
@ -15,6 +15,17 @@
|
|||||||
#ifndef NETLINK_H
|
#ifndef NETLINK_H
|
||||||
#define 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 */
|
#endif /* NETLINK_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user