}
-/* 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)
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,
else {
wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
"algorithm '%s'", __func__, alg);
- goto out;
+ nlmsg_free(msg);
+ return -1;
}
}
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);
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;
}
{
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);
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;
}
{
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);
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;
}
{
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);
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;
}
{
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);
#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;
}
{
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);
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;
}
{
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);
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;
}
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");
}
int ifidx;
struct ifreq ifreq;
struct iwreq iwr;
+ int ret = -ENOBUFS;
msg = nlmsg_alloc();
if (!msg)
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)
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;
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;
}
{
struct i802_driver_data *drv = priv;
struct nl_msg *msg;
- int ret = -1;
drv->beacon_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);
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;
}
{
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);
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;
}
#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);
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 */
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)
}
}
- phy_info->error = 0;
-
return NL_SKIP;
}
{
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;
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;
}
{
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);
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;
}
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);
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;
}