int dhd_nl_sock_connect(struct dhd_netlink_info *dhd_nli) { dhd_nli->nl = nl_socket_alloc(); if (dhd_nli->nl == NULL) return -1; if (genl_connect(dhd_nli->nl) < 0) { fprintf(stderr, "netlink connection failed\n"); goto err; } dhd_nli->nl_id = genl_ctrl_resolve(dhd_nli->nl, "nl80211"); if (dhd_nli->nl_id < 0) { fprintf(stderr, "'nl80211' netlink not found\n"); goto err; } dhd_nli->cb = nl_cb_alloc(NL_CB_DEBUG); if (dhd_nli->cb == NULL) goto err; nl_socket_set_cb(dhd_nli->nl, dhd_nli->cb); return 0; err: nl_cb_put(dhd_nli->cb); nl_socket_free(dhd_nli->nl); fprintf(stderr, "nl80211 connection failed\n"); return -1; }
static int go_offchan_freq(struct nl80211_state *state, int devidx, int freq) { struct nl_cb *cb; struct nl_cb *s_cb; struct nl_msg *msg; int err; msg = nlmsg_alloc(); if (!msg) { fprintf(stderr, "failed to allocate netlink message\n"); return 2; } cb = nl_cb_alloc(nl_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); s_cb = nl_cb_alloc(nl_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); if (!cb || !s_cb) { fprintf(stderr, "failed to allocate netlink callbacks\n"); err = 2; goto out_free_msg; } genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_REMAIN_ON_CHANNEL, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); /* 5 seconds is the max allowed, values passed are in ms */ NLA_PUT_U32(msg, NL80211_ATTR_DURATION, 60); nl_socket_set_cb(state->nl_sock, s_cb); err = nl_send_auto_complete(state->nl_sock, 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, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); while (err > 0) nl_recvmsgs(state->nl_sock, cb); out: nl_cb_put(cb); out_free_msg: nlmsg_free(msg); return err; nla_put_failure: fprintf(stderr, "building message failed\n"); return 2; }
// Retrieve monitor interface for a given physical interface int ret_mon_IF(struct nl80211_state *state) { struct nl_msg *msg; struct nl_cb *cb, *s_cb; int err = 1; msg = nlmsg_alloc(); if (!msg) { fprintf(stderr, "failed to allocate netlink message\n"); return 2; } // Allocate a new callback handle. cb = nl_cb_alloc(NL_CB_DEFAULT); s_cb = nl_cb_alloc(NL_CB_DEFAULT); if (!cb || !s_cb) { fprintf(stderr, "failed to allocate netlink callbacks\n"); err = 2; goto out_free_msg; } // Add Generic Netlink header (i.e. NL80211_CMD_GET_INTERFACE) to Netlink message genlmsg_put(msg, 0, 0, state->nl80211_id, 0, 768, NL80211_CMD_GET_INTERFACE, 0); // Set up a valid callback function if (nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, iface_handler, NULL)) goto out; // Attach the callback function to a netlink socket nl_socket_set_cb(state->nl_sock, s_cb); // Finalize and transmit Netlink message if(nl_send_auto_complete(state->nl_sock, msg) < 0) goto out; // Set up error, finish and acknowledgment callback function nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); while (err > 0) nl_recvmsgs(state->nl_sock, cb); out: nl_cb_put(cb); out_free_msg: nlmsg_free(msg); return err; }
static int call_survey_freq(struct nl80211_state *state, int devidx, int freq) { struct nl_cb *cb; struct nl_cb *s_cb; struct nl_msg *msg; int err; msg = nlmsg_alloc(); if (!msg) { fprintf(stderr, "failed to allocate netlink message\n"); return 2; } cb = nl_cb_alloc(nl_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); s_cb = nl_cb_alloc(nl_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); if (!cb || !s_cb) { fprintf(stderr, "failed to allocate netlink callbacks\n"); err = 2; goto out_free_msg; } genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handle_survey_dump, (void *) &freq); nl_socket_set_cb(state->nl_sock, s_cb); err = nl_send_auto_complete(state->nl_sock, 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, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); while (err > 0) nl_recvmsgs(state->nl_sock, cb); out: nl_cb_put(cb); out_free_msg: nlmsg_free(msg); return err; nla_put_failure: fprintf(stderr, "building message failed\n"); return 2; }
static int send_recv_nlcmd(void *nla, size_t nla_len) { int err, nla_offset = 0; struct nl_cb *cb; struct nl_cb *s_cb; struct nl_msg *msg; if (cur_cmd <= NL80211_CMD_UNSPEC) { LOG_ERR_("Unsupported nl command: %d\n", cur_cmd); return 1; } if (devidx_set) /* Since devidx is a uint32_t the attribute will consume 8 * bytes. The nla input stream must be appended after this * attribute. */ nla_offset = 8; LOG_DBG_("%s: Allocating %d bytes for nlmsg\n", __func__, nla_len + nla_offset + NLMSG_HDRLEN + GENL_HDRLEN); msg = nlmsg_alloc_size(nla_len + nla_offset + NLMSG_HDRLEN + GENL_HDRLEN); if (!msg) { LOG_ERR_("failed to allocate netlink message\n"); return 2; } cb = nl_cb_alloc((log_level > LOG_WARNING) ? NL_CB_DEBUG : NL_CB_DEFAULT); s_cb = nl_cb_alloc((log_level > LOG_WARNING) ? NL_CB_DEBUG : NL_CB_DEFAULT); if (!cb || !s_cb) { LOG_ERR_("failed to allocate netlink callbacks\n"); err = 2; goto out; } genlmsg_put(msg, 0, 0, state.nl80211_id, 0, 0, cur_cmd, 0); if (devidx_set) { LOG_DBG_("%s: Adding devidx %d attribute\n", __func__, devidx); if (dev_by_phy) NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); else NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); } add_nla_stream_to_msg(msg, nla, nla_len); nl_socket_set_cb(state.nl_sock, s_cb); err = nl_send_auto_complete(state.nl_sock, msg); if (err < 0) { LOG_ERR_("nl_send_auto_complete %d\n", err); 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, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, NULL); while (err > 0) nl_recvmsgs(state.nl_sock, cb); out: nl_cb_put(cb); nl_cb_put(s_cb); nlmsg_free(msg); return err; nla_put_failure: LOG_ERR_("building message failed\n"); return 2; }