From cafe38cae01b0fcbc3b795ce02decf4ad93bee8f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Sep 2008 19:37:24 +0300 Subject: [PATCH] nl80211 hostapd driver: clean up netlink code Put it into a single place instead of having it all over. Signed-off-by: Johannes Berg --- hostapd/driver_nl80211.c | 421 +++++++++++++-------------------------- 1 file changed, 139 insertions(+), 282 deletions(-) diff --git a/hostapd/driver_nl80211.c b/hostapd/driver_nl80211.c index 515af765e..a09761710 100644 --- a/hostapd/driver_nl80211.c +++ b/hostapd/driver_nl80211.c @@ -135,15 +135,60 @@ static int have_ifidx(struct i802_driver_data *drv, int ifidx) } -/* helper for netlink get routines */ -static int ack_wait_handler(struct nl_msg *msg, void *arg) +/* nl80211 code */ +static int ack_handler(struct nl_msg *msg, void *arg) { - int *finished = arg; - - *finished = 1; + int *err = arg; + *err = 0; return NL_STOP; } +static int finish_handler(struct nl_msg *msg, void *arg) +{ + return NL_SKIP; +} + +static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, + void *arg) +{ + int *ret = arg; + *ret = err->error; + return NL_SKIP; +} + +static int send_and_recv_msgs(struct i802_driver_data *drv, + struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) +{ + struct nl_cb *cb; + int err = -ENOMEM; + + cb = nl_cb_clone(drv->nl_cb); + if (!cb) + goto out; + + err = nl_send_auto_complete(drv->nl_handle, msg); + if (err < 0) + goto out; + + err = 1; + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, NULL); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); + + if (valid_handler) + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, + valid_handler, valid_data); + + while (err > 0) + nl_recvmsgs(drv->nl_handle, cb); + out: + nl_cb_put(cb); + nlmsg_free(msg); + return err; +} static int hostapd_set_iface_flags(struct i802_driver_data *drv, const char *ifname, int dev_up) @@ -182,12 +227,11 @@ static int nl_set_encr(int ifindex, struct i802_driver_data *drv, size_t key_len, int txkey) { struct nl_msg *msg; - int ret = -1; - int err = 0; + int ret; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; if (strcmp(alg, "none") == 0) { genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, @@ -212,7 +256,8 @@ static int nl_set_encr(int ifindex, struct i802_driver_data *drv, else { wpa_printf(MSG_ERROR, "%s: Unsupported encryption " "algorithm '%s'", __func__, alg); - goto out; + nlmsg_free(msg); + return -1; } } @@ -221,28 +266,20 @@ static int nl_set_encr(int ifindex, struct i802_driver_data *drv, NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - (err = nl_wait_for_ack(drv->nl_handle)) < 0) { - if (err != -ENOENT) { - ret = 0; - goto out; - } - } + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == -ENOENT) + ret = 0; /* - * If we need to set the default TX key we do that below, - * otherwise we're done here. + * If we failed or don't need to set the default TX key (below), + * we're done here. */ - if (!txkey || addr) { - ret = 0; - goto out; - } - - nlmsg_free(msg); + if (ret || !txkey || addr) + return ret; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_KEY, 0); @@ -257,20 +294,12 @@ static int nl_set_encr(int ifindex, struct i802_driver_data *drv, NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); #endif /* NL80211_MFP_PENDING */ - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - (err = nl_wait_for_ack(drv->nl_handle)) < 0) { - if (err != -ENOENT) { - ret = 0; - goto out; - } - } - - ret = 0; - - out: - nla_put_failure: - nlmsg_free(msg); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == -ENOENT) + ret = 0; return ret; + nla_put_failure: + return -ENOBUFS; } @@ -329,14 +358,10 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, { struct i802_driver_data *drv = priv; struct nl_msg *msg; - struct nl_cb *cb = NULL; - int ret = -1; - int err = 0; - int finished = 0; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_GET_KEY, 0); @@ -346,33 +371,11 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - cb = nl_cb_clone(drv->nl_cb); - if (!cb) - goto out; - memset(seq, 0, 6); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0) - goto out; - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_key_handler, seq); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); - - err = nl_recvmsgs(drv->nl_handle, cb); - - if (!finished) - err = nl_wait_for_ack(drv->nl_handle); - - if (err < 0) - goto out; - - ret = 0; - - out: - nl_cb_put(cb); + return send_and_recv_msgs(drv, msg, get_key_handler, seq); nla_put_failure: - nlmsg_free(msg); - return ret; + return -ENOBUFS; } @@ -602,11 +605,10 @@ static int i802_flush(void *priv) { struct i802_driver_data *drv = priv; struct nl_msg *msg; - int ret = -1; msg = nlmsg_alloc(); if (!msg) - goto out; + return -1; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_DEL_STATION, 0); @@ -617,18 +619,9 @@ static int i802_flush(void *priv) NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - ret = 0; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - ret = -1; - } - + return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: - nlmsg_free(msg); - - out: - return ret; + return -ENOBUFS; } @@ -680,14 +673,10 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, { struct i802_driver_data *drv = priv; struct nl_msg *msg; - struct nl_cb *cb = NULL; - int ret = -1; - int err = 0; - int finished = 0; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_GET_STATION, 0); @@ -695,32 +684,9 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - cb = nl_cb_clone(drv->nl_cb); - if (!cb) - goto out; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0) - goto out; - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); - - err = nl_recvmsgs(drv->nl_handle, cb); - - if (!finished) - err = nl_wait_for_ack(drv->nl_handle); - - if (err < 0) - goto out; - - ret = 0; - - out: - nl_cb_put(cb); + return send_and_recv_msgs(drv, msg, get_sta_handler, data); nla_put_failure: - nlmsg_free(msg); - return ret; - + return -ENOBUFS; } @@ -797,11 +763,11 @@ static int i802_sta_add2(const char *ifname, void *priv, { struct i802_driver_data *drv = priv; struct nl_msg *msg; - int ret = -1; + int ret = -ENOBUFS; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_NEW_STATION, 0); @@ -825,19 +791,10 @@ static int i802_sta_add2(const char *ifname, void *priv, #endif /* NL80211_ATTR_HT_CAPABILITY */ #endif /* CONFIG_IEEE80211N */ - ret = nl_send_auto_complete(drv->nl_handle, msg); - if (ret < 0) - goto nla_put_failure; - - ret = nl_wait_for_ack(drv->nl_handle); - /* ignore EEXIST, this happens if a STA associates while associated */ - if (ret == -EEXIST || ret >= 0) + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == -EEXIST) ret = 0; - nla_put_failure: - nlmsg_free(msg); - - out: return ret; } @@ -846,11 +803,11 @@ static int i802_sta_remove(void *priv, const u8 *addr) { struct i802_driver_data *drv = priv; struct nl_msg *msg; - int ret = -1; + int ret; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_DEL_STATION, 0); @@ -859,18 +816,12 @@ static int i802_sta_remove(void *priv, const u8 *addr) if_nametoindex(drv->iface)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - ret = 0; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - ret = -1; - } - - nla_put_failure: - nlmsg_free(msg); - - out: + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == -ENOENT) + return 0; return ret; + nla_put_failure: + return -ENOBUFS; } @@ -879,15 +830,16 @@ static int i802_sta_set_flags(void *priv, const u8 *addr, { struct i802_driver_data *drv = priv; struct nl_msg *msg, *flags = NULL; - int ret = -1; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; flags = nlmsg_alloc(); - if (!flags) - goto free_msg; + if (!flags) { + nlmsg_free(msg); + return -ENOMEM; + } genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_STATION, 0); @@ -913,21 +865,12 @@ static int i802_sta_set_flags(void *priv, const u8 *addr, if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) goto nla_put_failure; - ret = 0; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - ret = -1; - } - - nla_put_failure: nlmsg_free(flags); - free_msg: - nlmsg_free(msg); - - out: - return ret; + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(flags); + return -ENOBUFS; } @@ -966,11 +909,11 @@ static void nl80211_remove_iface(struct i802_driver_data *drv, int ifidx) genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_DEL_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - nla_put_failure: - printf("Failed to remove interface.\n"); - nlmsg_free(msg); + + if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) + return; + nla_put_failure: + printf("Failed to remove interface.\n"); } @@ -983,6 +926,7 @@ static int nl80211_create_iface(struct i802_driver_data *drv, int ifidx; struct ifreq ifreq; struct iwreq iwr; + int ret = -ENOBUFS; msg = nlmsg_alloc(); if (!msg) @@ -1012,16 +956,13 @@ static int nl80211_create_iface(struct i802_driver_data *drv, goto nla_put_failure; } - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { nla_put_failure: printf("Failed to create interface %s.\n", ifname); - nlmsg_free(msg); - return -1; + return ret; } - nlmsg_free(msg); - ifidx = if_nametoindex(ifname); if (ifidx <= 0) @@ -1096,11 +1037,11 @@ static int i802_set_beacon(const char *iface, void *priv, struct i802_driver_data *drv = priv; struct nl_msg *msg; u8 cmd = NL80211_CMD_NEW_BEACON; - int ret = -1; + int ret; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; if (drv->beacon_set) cmd = NL80211_CMD_SET_BEACON; @@ -1116,44 +1057,30 @@ static int i802_set_beacon(const char *iface, void *priv, drv->dtim_period = 2; NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - goto out; - - ret = 0; - - drv->beacon_set = 1; - - out: - nla_put_failure: - nlmsg_free(msg); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (!ret) + drv->beacon_set = 1; return ret; + nla_put_failure: + return -ENOBUFS; } static int i802_del_beacon(struct i802_driver_data *drv) { struct nl_msg *msg; - int ret = -1; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_DEL_BEACON, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - goto out; - - ret = 0; - - out: + return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: - nlmsg_free(msg); - return ret; + return -ENOBUFS; } @@ -1197,7 +1124,6 @@ static int i802_set_beacon_int(void *priv, int value) { struct i802_driver_data *drv = priv; struct nl_msg *msg; - int ret = -1; drv->beacon_int = value; @@ -1206,7 +1132,7 @@ static int i802_set_beacon_int(void *priv, int value) msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_BEACON, 0); @@ -1214,16 +1140,9 @@ static int i802_set_beacon_int(void *priv, int value) NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - goto out; - - ret = 0; - - out: + return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: - nlmsg_free(msg); - return ret; + return -ENOBUFS; } @@ -1231,11 +1150,10 @@ static int i802_set_dtim_period(const char *iface, void *priv, int value) { struct i802_driver_data *drv = priv; struct nl_msg *msg; - int ret = -1; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_BEACON, 0); @@ -1244,16 +1162,9 @@ static int i802_set_dtim_period(const char *iface, void *priv, int value) drv->dtim_period = value; NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - goto out; - - ret = 0; - - out: + return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: - nlmsg_free(msg); - return ret; + return -ENOBUFS; } @@ -1262,11 +1173,10 @@ static int i802_set_bss(void *priv, int cts, int preamble, int slot) #ifdef NL80211_CMD_SET_BSS struct i802_driver_data *drv = priv; struct nl_msg *msg; - int ret = -1; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_BSS, 0); @@ -1278,21 +1188,12 @@ static int i802_set_bss(void *priv, int cts, int preamble, int slot) if (slot >= 0) NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); - ret = 0; - /* TODO: multi-BSS support */ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - ret = -1; - } - -nla_put_failure: - nlmsg_free(msg); - -out: - return ret; + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + return -ENOBUFS; #else /* NL80211_CMD_SET_BSS */ return -1; #endif /* NL80211_CMD_SET_BSS */ @@ -1358,7 +1259,6 @@ static int i802_if_remove(void *priv, enum hostapd_driver_if_type type, struct phy_info_arg { u16 *num_modes; struct hostapd_hw_modes *modes; - int error; }; static int phy_info_handler(struct nl_msg *msg, void *arg) @@ -1497,8 +1397,6 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) } } - phy_info->error = 0; - return NL_SKIP; } @@ -1508,13 +1406,9 @@ static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv, { struct i802_driver_data *drv = priv; struct nl_msg *msg; - int err = -1; - struct nl_cb *cb = NULL; - int finished = 0; struct phy_info_arg result = { .num_modes = num_modes, .modes = NULL, - .error = 1, }; *num_modes = 0; @@ -1529,33 +1423,10 @@ static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv, NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - cb = nl_cb_clone(drv->nl_cb); - if (!cb) - goto out; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0) - goto out; - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, phy_info_handler, &result); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); - - err = nl_recvmsgs(drv->nl_handle, cb); - - if (!finished) - err = nl_wait_for_ack(drv->nl_handle); - - if (err < 0 || result.error) { - hostapd_free_hw_features(result.modes, *num_modes); - result.modes = NULL; - } - - out: - nl_cb_put(cb); + if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) + return result.modes; nla_put_failure: - if (err) - fprintf(stderr, "failed to get information: %d\n", err); - nlmsg_free(msg); - return result.modes; + return NULL; } @@ -1564,11 +1435,10 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr, { struct i802_driver_data *drv = priv; struct nl_msg *msg; - int ret = -1; msg = nlmsg_alloc(); if (!msg) - goto out; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_STATION, 0); @@ -1579,18 +1449,9 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr, NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(ifname)); - ret = 0; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - (errno = nl_wait_for_ack(drv->nl_handle) < 0)) { - ret = -1; - } - + return send_and_recv_msgs(drv, msg, NULL, NULL); nla_put_failure: - nlmsg_free(msg); - - out: - return ret; + return -ENOBUFS; } @@ -1931,10 +1792,11 @@ static int nl80211_set_master_mode(struct i802_driver_data *drv, const char *ifname) { struct nl_msg *msg; + int ret = -ENOBUFS; msg = nlmsg_alloc(); if (!msg) - return -1; + return -ENOMEM; genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_INTERFACE, 0); @@ -1942,18 +1804,13 @@ static int nl80211_set_master_mode(struct i802_driver_data *drv, if_nametoindex(ifname)); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (!ret) + return 0; nla_put_failure: - wpa_printf(MSG_ERROR, "Failed to set interface %s to master " - "mode.", ifname); - nlmsg_free(msg); - return -1; - } - - nlmsg_free(msg); - - return 0; + wpa_printf(MSG_ERROR, "Failed to set interface %s to master " + "mode.", ifname); + return ret; }