00001
00023 #include <sys/types.h>
00024 #include <sys/socket.h>
00025 #include <linux/types.h>
00026 #include <linux/netlink.h>
00027 #include <linux/rtnetlink.h>
00028 #include <linux/if_ether.h>
00029 #include <dbus/dbus.h>
00030 #include <wlancond.h>
00031 #include <eap-dbus.h>
00032
00033 #include <glib.h>
00034 #include <glib-object.h>
00035 #include <unistd.h>
00036 #include <fcntl.h>
00037 #include <errno.h>
00038
00039 #include "wpa.h"
00040 #include "wapi.h"
00041 #include "daemon.h"
00042 #include "dbus-handler.h"
00043 #include "log.h"
00044 #include "libnl-handler.h"
00045
00046 static int nl80211_scan_result_handler(struct nl_msg *msg, void* arg);
00047 static int nl80211_parse_ies(unsigned char* const ie, size_t ie_len, scan_results_t* const scan_result);
00048 static void save_caps(struct scan_results_t *, struct ap_info_t *, unsigned char *, unsigned int);
00049
00051 static struct nl_handle *nl_handle = NULL;
00052 static struct nl_handle *nl_event_handle = NULL;
00053 static struct nl_cache *nl_cache = NULL;
00054 static struct nl_cache *nl_event_cache = NULL;
00055 static struct genl_family *nl80211 = NULL;
00056 static struct nl_cb *nl_cb = NULL;
00057 static unsigned int nl_family_id;
00058 static wlan_status_t * scan_wlan_status = NULL;
00059
00066 static int get_family_cb(struct nl_msg *msg, void *arg)
00067 {
00068 struct get_family_t *data = arg;
00069 struct nlattr *tb[CTRL_ATTR_MAX + 1];
00070 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
00071 struct nlattr *grp;
00072 int index;
00073
00074 if (nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
00075 genlmsg_attrlen(gnlh, 0), NULL)) {
00076 DLOG_ERR("nl80211: Failed to parse get family attributes!");
00077 return NL_SKIP;
00078 }
00079
00080 if (!tb[CTRL_ATTR_MCAST_GROUPS])
00081 return NL_SKIP;
00082
00083 nla_for_each_nested(grp, tb[CTRL_ATTR_MCAST_GROUPS], index) {
00084 struct nlattr *tbg[CTRL_ATTR_MCAST_GRP_MAX + 1];
00085 if (nla_parse(tbg, CTRL_ATTR_MCAST_GRP_MAX, nla_data(grp),
00086 nla_len(grp), NULL)) {
00087 DLOG_ERR("nl80211: Failed to parse nested get "
00088 "family attributes!");
00089 return NL_SKIP;
00090 }
00091
00092 if (!tbg[CTRL_ATTR_MCAST_GRP_NAME] ||
00093 !tbg[CTRL_ATTR_MCAST_GRP_ID] ||
00094 strncmp(nla_data(tbg[CTRL_ATTR_MCAST_GRP_NAME]),
00095 data->group_name,
00096 nla_len(tbg[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
00097 continue;
00098
00099 data->id = nla_get_u32(tbg[CTRL_ATTR_MCAST_GRP_ID]);
00100 break;
00101 };
00102
00103 return NL_SKIP;
00104 }
00105
00112 static int nl80211_get_family(const char *family_name, const char *group_name)
00113 {
00114 struct get_family_t data = { group_name, -ENOENT };
00115 struct nl_msg *msg;
00116 int ret = -1;
00117 void *hdr;
00118
00119 int id = genl_ctrl_resolve(nl_event_handle, "nlctrl");
00120 if (id < 0) {
00121 DLOG_ERR("nl80211: Failed to put nl80211 message");
00122 return ret;
00123 }
00124
00125 msg = nlmsg_alloc();
00126 if (!msg)
00127 return ret;
00128
00129 hdr = genlmsg_put(msg, getpid(), 0, id, 0, 0, CTRL_CMD_GETFAMILY, 0);
00130 if (hdr == NULL) {
00131 DLOG_ERR("nl80211: Failed to put nl80211 message");
00132 goto nla_put_failure;
00133 }
00134
00135 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family_name);
00136
00137 ret = nl_send_recv_msgs(msg, get_family_cb, &data);
00138 if (ret) {
00139 DLOG_ERR("nl80211: failed to send get family ret=%d (%s)", ret,
00140 strerror(-ret));
00141 goto nla_put_failure;
00142 }
00143
00144 if (ret == 0)
00145 ret = data.id;
00146
00147 nla_put_failure:
00148 nlmsg_free(msg);
00149 return ret;
00150 }
00151
00157 static void handle_netlink_wap_event(unsigned char *sa_data)
00158 {
00159 print_mac(WLANCOND_PRIO_HIGH, "nl80211: BSSID:", sa_data);
00160
00161
00162 if (memcmp(sa_data, NULL_BSSID, ETH_ALEN)) {
00163
00164 if (get_wlan_state() == WLAN_INITIALIZED_FOR_SCAN ||
00165 get_wlan_state() == WLAN_NOT_INITIALIZED) {
00166 DLOG_DEBUG("Connection opened while not initialized?");
00167 nl80211_get_phy_info(wlan_status.ifindex);
00168 connected_signal((char *)sa_data);
00169 return;
00170 }
00171
00172 remove_connect_timer();
00173
00174 set_wlan_signal(WLANCOND_HIGH);
00175
00176 connected_signal((char *)sa_data);
00177
00178 if (get_wpa_mode() == TRUE ||
00179 wlan_status.conn.authentication_type ==
00180 EAP_AUTH_TYPE_WFA_SC) {
00181 if (wpa_ie_push((char *) sa_data) < 0) {
00182 set_wlan_state(WLAN_NOT_INITIALIZED,
00183 DISCONNECTED_SIGNAL,
00184 FALSE);
00185 return;
00186 }
00187 } else {
00188
00189
00190
00191
00192
00193 wlan_status.retry_count = 0;
00194
00195 if (netlink_send_linkmode(WLANCOND_IF_READY) != 0) {
00196 DLOG_ERR("Setting oper state to "
00197 "ready failed");
00198 }
00199 }
00200
00201
00202 if (wlan_status.ip_ok == FALSE) {
00203
00204 if (get_inactivity_status() == TRUE) {
00205 if (set_iptables() < 0)
00206 DLOG_ERR("Setting iptables failed");
00207 }
00208 set_wlan_state(WLAN_NO_ADDRESS, NO_SIGNAL, TRUE);
00209 } else {
00210 set_wlan_state(WLAN_CONNECTED, NO_SIGNAL, TRUE);
00211 }
00212
00213
00214 wlan_status.conn.flags &= ~WLANCOND_AUTOCONNECT;
00215 } else {
00216 if (get_wlan_state() == WLAN_INITIALIZED_FOR_CONNECTION &&
00217 get_scan_state() == SCAN_ACTIVE) {
00218
00219 return;
00220 }
00221 if (get_wlan_state() != WLAN_CONNECTED &&
00222 get_wlan_state() != WLAN_NO_ADDRESS &&
00223 get_wlan_state() != WLAN_INITIALIZED_FOR_CONNECTION) {
00224 DLOG_ERR("nl80211: Not even connected?!?");
00225 disconnected_signal();
00226 return;
00227 }
00228
00229 if (wlan_status.conn.authentication_type ==
00230 EAP_AUTH_TYPE_WFA_SC) {
00231 return;
00232 }
00233
00234
00235 if (get_wpa_mode() == TRUE &&
00236 (get_wlan_state() == WLAN_CONNECTED ||
00237 get_wlan_state() == WLAN_NO_ADDRESS)) {
00238 disassociate_eap();
00239 }
00240
00241 DLOG_DEBUG("nl80211: Trying to find a new connection");
00242
00243 if (is_connected_state()) {
00244 DLOG_DEBUG("Disconnecting previous connection");
00245 mlme_command(wlan_status.conn.bssid,
00246 WLANCOND_NL80211_MLME_DISCONNECT,
00247 WLANCOND_REASON_LEAVING);
00248 }
00249
00250
00251
00252 roam_cache_key_t key = { wlan_status.conn.bssid, wlan_status.conn.channel };
00253 decrease_signal_in_roam_cache(&key);
00254
00255 set_wlan_state(WLAN_INITIALIZED_FOR_CONNECTION, NO_SIGNAL,
00256 TRUE);
00257
00258 int ret = find_connection_and_associate(wlan_status.roam_cache,
00259 FALSE, FALSE, FALSE);
00260 if (ret == 0)
00261 return;
00262
00263 if (ret == ESUPPLICANT) {
00264 set_wlan_state(WLAN_NOT_INITIALIZED,
00265 DISCONNECTED_SIGNAL, FALSE);
00266 return;
00267 }
00268
00269 if (scan_retries_left() == FALSE) {
00270 DLOG_ERR("nl80211: Too many failures: %d",
00271 wlan_status.retry_count);
00272 set_wlan_state(WLAN_NOT_INITIALIZED,
00273 DISCONNECTED_SIGNAL,
00274 FALSE);
00275 return;
00276 }
00277
00278
00279 scan(wlan_status.conn.ssid, wlan_status.conn.ssid_len, TRUE);
00280 }
00281 }
00282
00283 static int ignore_seq_check(struct nl_msg *msg, void *arg)
00284 {
00285 return NL_OK;
00286 }
00287
00292 static void process_cqm_event(struct nlattr *tb[])
00293 {
00294 struct nlattr *monitor[NL80211_ATTR_CQM_MAX + 1];
00295 struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
00296 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
00297 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
00298 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
00299 };
00300
00301 if (nla_parse_nested(monitor, NL80211_ATTR_CQM_MAX,
00302 tb[NL80211_ATTR_CQM], cqm_policy)) {
00303 DLOG_ERR("nl80211: Failed to parse nested cqm attributes!");
00304 return;
00305 }
00306
00307 if (monitor[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) {
00308 if (nla_get_u32(monitor[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) ==
00309 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
00310 DLOG_INFO("High signal");
00311 set_wlan_signal(WLANCOND_HIGH);
00312 } else {
00313 DLOG_INFO("Low signal");
00314 set_wlan_signal(WLANCOND_LOW);
00315 if (get_wlan_state() == WLAN_CONNECTED) {
00316 if (roam_scanning())
00317
00318 schedule_scan(WLANCOND_MIN_ROAM_SCAN_INTERVAL);
00319 else
00320 schedule_scan(WLANCOND_INITIAL_ROAM_SCAN_DELAY);
00321 }
00322 }
00323 }
00324 }
00325
00332 static int print_netlink_event_token(struct nl_msg *msg, void *arg)
00333 {
00334 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
00335 struct nlattr *tb[NL80211_ATTR_MAX + 1];
00336
00337 if (nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
00338 genlmsg_attrlen(gnlh, 0), NULL)) {
00339 DLOG_ERR("nl80211: Failed to parse netlink event attributes!");
00340 return NL_SKIP;
00341 }
00342
00343 if (tb[NL80211_ATTR_IFINDEX]) {
00344 if (nla_get_u32(tb[NL80211_ATTR_IFINDEX]) != wlan_status.ifindex) {
00345 DLOG_DEBUG("nl80211: Ignoring, not a wireless event.");
00346 return NL_SKIP;
00347 }
00348 }
00349
00350 switch (gnlh->cmd) {
00351 case NL80211_CMD_TRIGGER_SCAN:
00352 DLOG_DEBUG("nl80211: scan triggered");
00353 break;
00354 case NL80211_CMD_NEW_SCAN_RESULTS:
00355 case NL80211_CMD_SCAN_ABORTED:
00356 nl80211_scan_ready();
00357 break;
00358 case NL80211_CMD_AUTHENTICATE:
00359 case NL80211_CMD_ASSOCIATE:
00360 if (tb[NL80211_ATTR_TIMED_OUT]) {
00361 DLOG_ERR("authentication/association timed out");
00362 handle_netlink_wap_event(NULL_BSSID);
00363 }
00364 break;
00365 case NL80211_CMD_DEAUTHENTICATE:
00366 case NL80211_CMD_DISASSOCIATE:
00367 break;
00368 case NL80211_CMD_CONNECT:
00369 case NL80211_CMD_ROAM:
00370 if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0) {
00371 unsigned char *bssid = nla_data(tb[NL80211_ATTR_MAC]);
00372 handle_netlink_wap_event(bssid);
00373 } else {
00374 DLOG_DEBUG("nl80211: Failed to connect. reason: %d",
00375 nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]));
00376 handle_netlink_wap_event(NULL_BSSID);
00377 }
00378 break;
00379 case NL80211_CMD_DISCONNECT:
00380 if (tb[NL80211_ATTR_DISCONNECTED_BY_AP]) {
00381 DLOG_DEBUG("nl80211: Disconnected by the access point.");
00382 handle_netlink_wap_event(NULL_BSSID);
00383 } else {
00384 if (tb[NL80211_ATTR_REASON_CODE]) {
00385 DLOG_DEBUG("nl80211: Disconnected by local choice due to reason: %d",
00386 nla_get_u16(tb[NL80211_ATTR_REASON_CODE]));
00387 } else {
00388 DLOG_DEBUG("nl80211: Disconnected");
00389 if (get_wlan_state() == WLAN_NO_ADDRESS ||
00390 get_wlan_state() == WLAN_CONNECTED)
00391 handle_netlink_wap_event(NULL_BSSID);
00392 }
00393 }
00394 break;
00395 case NL80211_CMD_MICHAEL_MIC_FAILURE:
00396 DLOG_DEBUG("nl80211: MIC failure event received.");
00397 dbus_bool_t key_type = TRUE;
00398
00399 if (tb[NL80211_ATTR_KEY_TYPE]) {
00400 enum nl80211_key_type type = nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
00401
00402 if (type == NL80211_KEYTYPE_PAIRWISE)
00403 key_type = FALSE;
00404 }
00405 DLOG_DEBUG("MIC failure event for %s key",
00406 key_type==FALSE?"unicast":"group");
00407 if ((wlan_status.conn.encryption & WLANCOND_ENCRYPT_METHOD_MASK)
00408 != WLANCOND_WAPI_PSK &&
00409 (wlan_status.conn.encryption & WLANCOND_ENCRYPT_METHOD_MASK)
00410 != WLANCOND_WAPI_CERT) {
00411 handle_mic_failure(key_type, wlan_status.conn.bssid);
00412 }
00413 break;
00414 case NL80211_CMD_JOIN_IBSS:
00415 if (tb[NL80211_ATTR_MAC]) {
00416 unsigned char *bssid = nla_data(tb[NL80211_ATTR_MAC]);
00417 handle_netlink_wap_event(bssid);
00418 } else {
00419 DLOG_ERR("nl80211: Joined adhoc with no address.");
00420 }
00421 break;
00422 case NL80211_CMD_GET_STATION:
00423 case NL80211_CMD_SET_STATION:
00424 case NL80211_CMD_NEW_STATION:
00425 case NL80211_CMD_DEL_STATION:
00426 break;
00427 case NL80211_CMD_NOTIFY_CQM:
00428 process_cqm_event(tb);
00429 break;
00430 default:
00431 DLOG_DEBUG("nl80211: unknown event cmd (%d)", gnlh->cmd);
00432 break;
00433 }
00434 return NL_SKIP;
00435 }
00436
00444 static gboolean event_receive(GIOChannel *chan, GIOCondition cond, gpointer data)
00445 {
00446 struct nl_cb *cb;
00447 int ret;
00448
00449 cb = nl_cb_clone(nl_cb);
00450
00451 if (!cb) {
00452 DLOG_ERR("nl80211: event receive cb clone fail");
00453 return TRUE;
00454 }
00455
00456 if (cond != G_IO_IN) {
00457 DLOG_INFO("nl80211: received event is not g_io_in");
00458 guint watch_id = *((guint *)data);
00459 g_source_remove(watch_id);
00460 g_io_channel_unref(chan);
00461 goto nla_put_failure;
00462 }
00463
00464 ret = nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, ignore_seq_check, NULL);
00465 if (ret) {
00466 DLOG_ERR("nl80211: ignore seq cb set returned error: %d", ret);
00467 goto nla_put_failure;
00468 }
00469 ret = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_netlink_event_token, NULL);
00470 if (ret) {
00471 DLOG_ERR("nl80211: print netlink event cb set returned error: %d", ret);
00472 goto nla_put_failure;
00473 }
00474 if (fcntl(nl_socket_get_fd(nl_event_handle), F_SETFL, O_NONBLOCK) == -1) {
00475 DLOG_ERR("nl80211: failed to set receive netlink message");
00476 goto nla_put_failure;
00477 }
00478 if (nl_recvmsgs(nl_event_handle, cb)) {
00479 DLOG_ERR("nl80211: failed to receive netlink message");
00480 goto nla_put_failure;
00481 }
00482 nl_cb_put(cb);
00483 return TRUE;
00484
00485 nla_put_failure:
00486 nl_cb_put(cb);
00487 return FALSE;
00488 }
00489
00494 int init_nl80211(void)
00495 {
00496 int ret = -1;
00497 static guint watch_id = 0;
00498 GIOChannel *gio;
00499
00500
00501
00502 nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
00503 if (!nl_cb) {
00504 DLOG_ERR("nl80211: failed to allocate netlink callbacks");
00505 return ret;
00506 }
00507
00508 nl_handle = nl_handle_alloc();
00509 if (!nl_handle) {
00510 DLOG_ERR("nl80211: failed to allocate netlink handle");
00511 goto out_cb_clear;
00512 }
00513
00514 nl_event_handle = nl_handle_alloc_cb(nl_cb);
00515 if (!nl_event_handle) {
00516 DLOG_ERR("nl80211: failed to allocate netlink event handle");
00517 goto out_handle_destroy_b;
00518 }
00519
00520 if (genl_connect(nl_handle)) {
00521 DLOG_ERR("nl80211: failed to connect netlink");
00522 goto out_handle_destroy_a;
00523 }
00524
00525 nl_disable_sequence_check(nl_event_handle);
00526
00527 if (genl_connect(nl_event_handle)) {
00528 DLOG_ERR("nl80211: failed to connect netlink event");
00529 goto out_handle_destroy_a;
00530 }
00531
00532 nl_cache = genl_ctrl_alloc_cache(nl_handle);
00533 if (!nl_cache) {
00534 DLOG_ERR("nl80211: failed to allocate netlink control cache");
00535 goto out_handle_destroy_a;
00536 }
00537
00538 nl_event_cache = genl_ctrl_alloc_cache(nl_event_handle);
00539 if (!nl_event_cache) {
00540 DLOG_ERR("nl80211: failed to allocate netlink event control cache");
00541 goto out_clean_cache_b;
00542 }
00543
00544 nl80211 = genl_ctrl_search_by_name(nl_cache, "nl80211");
00545 if (!nl80211) {
00546 DLOG_ERR("nl80211: didn't find nl80211 netlink control");
00547 goto out_clean_cache_a;
00548 }
00549
00550 ret = nl80211_get_family("nl80211", "scan");
00551 if (ret >= 0) {
00552 ret = nl_socket_add_membership(nl_event_handle, ret);
00553 } else {
00554 DLOG_ERR("nl80211: couldn't add multicast membership"
00555 " for scan events: %d (%s)", ret, strerror(-ret));
00556 goto out_clean_cache_a;
00557 }
00558
00559 ret = nl80211_get_family("nl80211", "mlme");
00560 if (ret >= 0) {
00561 ret = nl_socket_add_membership(nl_event_handle, ret);
00562 } else {
00563 DLOG_ERR("nl80211: couldn't add multicast membership"
00564 " for mlme events: %d (%s)", ret, strerror(-ret));
00565 goto out_clean_cache_a;
00566 }
00567
00568 nl_family_id = genl_family_get_id(nl80211);
00569 DLOG_DEBUG("nl80211: netlink family id %d", nl_family_id);
00570
00571 gio = g_io_channel_unix_new(nl_socket_get_fd(nl_event_handle));
00572 g_io_channel_set_close_on_unref(gio, TRUE);
00573 watch_id = g_io_add_watch(gio, G_IO_IN | G_IO_PRI | G_IO_ERR |
00574 G_IO_HUP, event_receive, &watch_id);
00575
00576 return 0;
00577
00578 out_clean_cache_a:
00579 nl_cache_free(nl_event_cache);
00580
00581 out_clean_cache_b:
00582 nl_cache_free(nl_cache);
00583
00584 out_handle_destroy_a:
00585 nl_handle_destroy(nl_event_handle);
00586
00587 out_handle_destroy_b:
00588 nl_handle_destroy(nl_handle);
00589
00590 out_cb_clear:
00591 nl_cb_put(nl_cb);
00592
00593 return ret;
00594 }
00595
00596 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
00597 void *arg)
00598 {
00599 int *ret = arg;
00600 DLOG_DEBUG("nl80211: %s() %d\n", __func__, err->error);
00601 *ret = err->error;
00602 return NL_SKIP;
00603 }
00604
00605 static int finish_handler(struct nl_msg *msg, void *arg)
00606 {
00607 int *ret = arg;
00608 DLOG_DEBUG("nl80211: %s()\n", __func__);
00609 *ret = 0;
00610 return NL_SKIP;
00611 }
00612
00613 static int ack_handler(struct nl_msg *msg, void *arg)
00614 {
00615 int *ret = arg;
00616
00617 *ret = 0;
00618 return NL_STOP;
00619 }
00620
00628 int nl_send_recv_msgs(struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data)
00629 {
00630 struct nl_cb *cb;
00631 int ret;
00632
00633 cb = nl_cb_clone(nl_cb);
00634
00635 if (!cb) {
00636 DLOG_ERR("nl80211: failed to alloc netlink callback");
00637 ret = -nl_get_errno();
00638 return ret;
00639 }
00640 ret = nl_send_auto_complete(nl_handle, msg);
00641
00642 if (ret < 0) {
00643 DLOG_ERR("nl80211: failed to send netlink message");
00644 goto end_func;
00645 }
00646
00647 ret = 1;
00648
00649 if (nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret)) {
00650 DLOG_DEBUG("nl80211: send and recv nl_cb_err returned error");
00651 ret = -1;
00652 goto end_func;
00653 }
00654 if (nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &ret)) {
00655 DLOG_DEBUG("nl80211: send and recv set finnish handler returned error");
00656 ret = -1;
00657 goto end_func;
00658 }
00659 if (nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret)) {
00660 DLOG_DEBUG("nl80211: send and recv set ack handler returned error");
00661 ret = -1;
00662 goto end_func;
00663 }
00664
00665 if (valid_handler) {
00666 if (nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler,
00667 valid_data)) {
00668 DLOG_DEBUG("nl80211: send and recv set valid handler error");
00669 ret = -1;
00670 goto end_func;
00671 }
00672 }
00673
00674 while (ret > 0) {
00675 if (nl_recvmsgs(nl_handle, cb)) {
00676 DLOG_ERR("nl80211: failed to receive netlink message"
00677 " after command");
00678 goto end_func;
00679 }
00680 }
00681
00682 end_func:
00683 nl_cb_put(cb);
00684 return ret;
00685 }
00686
00690 void nl80211_cleanup(void)
00691 {
00692 DLOG_DEBUG("nl80211: cleanup destroying all");
00693
00694 if (nl80211)
00695 genl_family_put(nl80211);
00696
00697 if (nl_cache)
00698 nl_cache_free(nl_cache);
00699
00700 if (nl_handle)
00701 nl_handle_destroy(nl_handle);
00702 }
00703
00710 static int nl80211_set_wep_keys(struct connect_params_t *conn, struct nl_msg *msg)
00711 {
00712 int i, privacy = 0;
00713 struct nlattr *nl_keys, *nl_key;
00714
00715 for (i = 0; i < 4; i++) {
00716 if (conn->key_len[i] == 0)
00717 continue;
00718
00719 privacy = 1;
00720 break;
00721 }
00722 if (!privacy)
00723 return 0;
00724
00725 DLOG_DEBUG("nl80211: setting wep keys");
00726 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
00727 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
00728
00729 if (!nl_keys)
00730 goto nla_put_failure;
00731
00732 for (i = 0; i < 4; i++) {
00733 if (conn->key_len[i] == 0)
00734 continue;
00735
00736 char *key_phrase;
00737 nl_key = nla_nest_start(msg, i);
00738 if (!nl_key)
00739 goto nla_put_failure;
00740
00741 NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
00742
00743 if (conn->key_len[i] == 5)
00744 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
00745 WLANCOND_CIPHER_SUITE_WEP40);
00746 else
00747 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
00748 WLANCOND_CIPHER_SUITE_WEP104);
00749
00750 key_phrase = (caddr_t) &conn->key[i][0];
00751
00752 NLA_PUT(msg, NL80211_KEY_DATA, conn->key_len[i], key_phrase);
00753
00754
00755
00756
00757
00758 if (conn->default_key == i+1) {
00759 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
00760 DLOG_DEBUG("nl80211: default key: %d",
00761 conn->default_key);
00762 }
00763 nla_nest_end(msg, nl_key);
00764 }
00765 nla_nest_end(msg, nl_keys);
00766 return 0;
00767
00768 nla_put_failure:
00769 return -ENOBUFS;
00770 }
00776 static guint32 channel_to_freq(guint32 channel) {
00777 guint32 freq;
00778
00779 if (channel < 14) {
00780 freq = 2407 + (5 * channel);
00781 } else if (channel == 14) {
00782 freq = 2484;
00783 } else {
00784 freq = 5 * (channel + 1000);
00785 }
00786 return freq;
00787 }
00793 static guint32 freq_to_channel(guint32 freq)
00794 {
00795 if (freq < 2484)
00796 return (freq - 2407) / 5;
00797
00798 if (freq == 2484)
00799 return 14;
00800
00801 return freq / 5 - 1000;
00802 }
00808 int nl80211_connect(struct scan_results_t *scan_results, struct wlan_status_t *wlan_status)
00809 {
00810 struct connect_params_t *conn = &wlan_status->conn;
00811 struct nl_msg *msg;
00812 void *hdr;
00813 gint ret = -1;
00814 guint mode = NL80211_CMD_CONNECT;
00815
00816
00817 enum nl80211_auth_type type = NL80211_AUTHTYPE_OPEN_SYSTEM;
00818
00819 DLOG_DEBUG("nl80211: Starting the nl80211_connect");
00820
00821 msg = nlmsg_alloc();
00822
00823 if (msg == NULL) {
00824 return -ENOMEM;
00825 }
00826 if (get_mode() == WLANCOND_ADHOC)
00827 mode = NL80211_CMD_JOIN_IBSS;
00828
00829 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0, mode, 0);
00830 if (hdr == NULL) {
00831 DLOG_ERR("nl80211: Failed to put nl80211 connect message");
00832 goto nla_put_failure;
00833 }
00834
00835 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wlan_status->ifindex);
00836
00837 NLA_PUT(msg, NL80211_ATTR_SSID, conn->ssid_len-1, conn->ssid);
00838 DLOG_DEBUG("nl80211: ESSID: %s", conn->ssid);
00839
00840 if (memcmp(conn->bssid, "\0\0\0\0\0\0", ETH_ALEN)) {
00841 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, conn->bssid);
00842 print_mac(WLANCOND_PRIO_HIGH, "nl80211: BSSID", conn->bssid);
00843 }
00844
00845 if (scan_results->channel) {
00846 guint32 freq = channel_to_freq(scan_results->channel);
00847
00848 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
00849 DLOG_DEBUG("nl80211: Channel: %d", scan_results->channel);
00850 }
00851
00852 if ((conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WEP) {
00853 DLOG_DEBUG("nl80211: WEP selected");
00854
00855 if (get_mode() == WLANCOND_INFRA) {
00856 if (wlan_status->conn.wep_try_open_mode_first == TRUE) {
00857 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
00858 DLOG_DEBUG("nl80211: open system");
00859 wlan_status->conn.wep_try_open_mode_first = FALSE;
00860 } else {
00861 type = NL80211_AUTHTYPE_SHARED_KEY;
00862 DLOG_DEBUG("nl80211: shared key");
00863 wlan_status->conn.wep_try_open_mode_first = TRUE;
00864 }
00865 }
00866
00867 ret = nl80211_set_wep_keys(conn, msg);
00868 if (ret) {
00869 DLOG_DEBUG("nl80211: set key failure");
00870 goto nla_put_failure;
00871 }
00872 }
00873
00874 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
00875
00876 if (get_wpa_mode() == TRUE ||
00877 conn->authentication_type == EAP_AUTH_TYPE_WFA_SC) {
00878 struct wpa_ie_save_t *wpa_ie = &wlan_status->wpa_ie;
00879
00880 NLA_PUT(msg, NL80211_ATTR_IE, wpa_ie->ie_len, wpa_ie->ie);
00881
00882 if (get_wpa_mode() == TRUE ||
00883 (conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WEP) {
00884 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
00885 }
00886 DLOG_DEBUG("nl80211: Setting IE, len %d", wpa_ie->ie_len);
00887 }
00888
00889 if (scan_results->wpa_ie_len && scan_results->wpa_ie &&
00890 (conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) != WLANCOND_WAPI_PSK &&
00891 (conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) != WLANCOND_WAPI_CERT) {
00892
00893 enum nl80211_wpa_versions ver;
00894
00895 if (conn->encryption & WLANCOND_ENCRYPT_WPA2_MASK)
00896 ver = NL80211_WPA_VERSION_2;
00897 else
00898 ver = NL80211_WPA_VERSION_1;
00899
00900 DLOG_DEBUG("nl80211: %s", ver==NL80211_WPA_VERSION_2?
00901 "WPA2":"WPA1");
00902
00903 NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
00904 }
00905
00906 if ((conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WPA_PSK ||
00907 (conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WPA_EAP) {
00908
00909 switch (wlan_status->pairwise_cipher) {
00910 case CIPHER_SUITE_TKIP:
00911 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, WLANCOND_CIPHER_SUITE_TKIP);
00912 DLOG_DEBUG("nl80211: TKIP pairwise");
00913 break;
00914 case CIPHER_SUITE_CCMP:
00915 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, WLANCOND_CIPHER_SUITE_CCMP);
00916 DLOG_DEBUG("nl80211: AES pairwise");
00917 break;
00918 case CIPHER_SUITE_WEP104:
00919 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, WLANCOND_CIPHER_SUITE_WEP104);
00920 DLOG_DEBUG("nl80211: WEP104 pairwise");
00921 break;
00922 case CIPHER_SUITE_WEP40:
00923 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, WLANCOND_CIPHER_SUITE_WEP40);
00924 DLOG_DEBUG("nl80211: WEP40 pairwise");
00925 break;
00926 default:
00927 DLOG_ERR("NL80211: Not supported unicast encryption");
00928 nlmsg_free(msg);
00929 return -1;
00930 }
00931
00932 switch (wlan_status->group_cipher) {
00933 case CIPHER_SUITE_TKIP:
00934 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLANCOND_CIPHER_SUITE_TKIP);
00935 DLOG_DEBUG("nl80211: TKIP group");
00936 break;
00937 case CIPHER_SUITE_CCMP:
00938 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLANCOND_CIPHER_SUITE_CCMP);
00939 DLOG_DEBUG("nl80211: AES group");
00940 break;
00941 case CIPHER_SUITE_WEP104:
00942 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLANCOND_CIPHER_SUITE_WEP104);
00943 DLOG_DEBUG("nl80211: WEP104 group");
00944 break;
00945 case CIPHER_SUITE_WEP40:
00946 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, WLANCOND_CIPHER_SUITE_WEP40);
00947 DLOG_DEBUG("nl80211: WEP40 group");
00948 break;
00949 default:
00950 DLOG_ERR("nl80211: Not supported multicast encryption");
00951 nlmsg_free(msg);
00952 return -1;
00953 }
00954
00955 if ((conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WPA_PSK) {
00956 NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, WLANCOND_KEY_MGMT_PSK);
00957 DLOG_DEBUG("nl80211: PSK");
00958 }
00959 else if ((conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WPA_EAP) {
00960 NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, WLANCOND_KEY_MGMT_802_1X);
00961 DLOG_DEBUG("nl80211: EAP");
00962 }
00963 else {
00964 DLOG_ERR("nl80211: unsupported AKM ");
00965 goto nla_put_failure;
00966 }
00967 }
00968 else if ((conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WAPI_PSK ||
00969 (conn->encryption & WLANCOND_ENCRYPT_METHOD_MASK) == WLANCOND_WAPI_CERT) {
00970 NLA_PUT_U16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, 0x88B4);
00971 DLOG_DEBUG("nl80211: WAPI");
00972 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
00973 }
00974
00975
00976 if (get_mode() == WLANCOND_ADHOC) {
00977 if (scan_results->channel <= 14) {
00978
00979 const unsigned char rates[] = {
00980 2,
00981 4,
00982 11,
00983 22
00984 };
00985 if (sizeof(rates) / sizeof(rates[0]) <=
00986 NL80211_MAX_SUPP_RATES)
00987 NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES,
00988 sizeof(rates) / sizeof(rates[0]),
00989 rates);
00990 } else {
00991
00992 const unsigned char rates[] = {
00993 12,
00994 24,
00995 48
00996 };
00997 if (sizeof(rates) / sizeof(rates[0]) <=
00998 NL80211_MAX_SUPP_RATES)
00999 NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES,
01000 sizeof(rates) / sizeof(rates[0]),
01001 rates);
01002 }
01003 }
01004
01005 ret = nl_send_recv_msgs(msg, NULL, NULL);
01006 if (ret) {
01007 DLOG_ERR("nl80211: MLME connect failed: ret=%d (%s)",
01008 ret, strerror(-ret));
01009 goto nla_put_failure;
01010 }
01011
01012 ret = 0;
01013 DLOG_DEBUG("nl80211: Connect request send successfully");
01014
01015 nla_put_failure:
01016 nlmsg_free(msg);
01017 return ret;
01018 }
01019
01026 int nl80211_set_op_mode(guint32 ifindex, guint32 mode)
01027 {
01028 struct nl_msg *msg;
01029 gint ret = -1;
01030 void *hdr;
01031 enum nl80211_iftype nlmode;
01032
01033 msg = nlmsg_alloc();
01034 if (!msg)
01035 return -ENOMEM;
01036
01037 switch (mode) {
01038
01039 case WLANCOND_ADHOC:
01040 nlmode = NL80211_IFTYPE_ADHOC;
01041 DLOG_DEBUG("nl80211: selecting mode: ADHOC");
01042 break;
01043 case WLANCOND_INFRA:
01044 nlmode = NL80211_IFTYPE_STATION;
01045 DLOG_DEBUG("nl80211: selecting mode: INFRA");
01046 break;
01047 default:
01048 DLOG_ERR("Operating mode undefined");
01049 goto nla_put_failure;
01050 }
01051 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01052 NL80211_CMD_SET_INTERFACE, 0);
01053 if (hdr == NULL) {
01054 DLOG_ERR("nl80211: Failed to put set interface message");
01055 goto nla_put_failure;
01056 }
01057 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
01058 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode);
01059
01060 ret = nl_send_recv_msgs(msg, NULL, NULL);
01061
01062 if (ret) {
01063 DLOG_ERR("nl80211: failed to send set interface ret=%d (%s)",
01064 ret, strerror(-ret));
01065 goto nla_put_failure;
01066 }
01067 ret = 0;
01068
01069 nla_put_failure:
01070 nlmsg_free(msg);
01071 return ret;
01072 }
01079 static int phy_info_handler(struct nl_msg *msg, void *arg)
01080 {
01081 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
01082 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
01083
01084 if (nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
01085 genlmsg_attrlen(gnlh, 0), NULL))
01086 return NL_SKIP;
01087
01088 if (tb_msg[NL80211_ATTR_IFTYPE]) {
01089 switch (nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE])) {
01090 case NL80211_IFTYPE_ADHOC:
01091 wlan_status.conn.mode = WLANCOND_ADHOC;
01092 break;
01093 case NL80211_IFTYPE_STATION:
01094 wlan_status.conn.mode = WLANCOND_INFRA;
01095 break;
01096 default:
01097 break;
01098 }
01099 }
01100 return NL_SKIP;
01101 }
01107 int nl80211_get_phy_info(guint32 ifindex)
01108 {
01109 struct nl_msg *msg;
01110 gint ret = -1;
01111 void *hdr;
01112
01113 msg = nlmsg_alloc();
01114 if (!msg)
01115 return -ENOMEM;
01116
01117 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01118 NL80211_CMD_GET_INTERFACE, 0);
01119 if (hdr == NULL) {
01120 goto nla_put_failure;
01121 }
01122
01123 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
01124
01125 ret = nl_send_recv_msgs(msg, phy_info_handler, NULL);
01126
01127 if (ret)
01128 DLOG_ERR("nl80211: failed to send get phy info ret=%d (%s)",
01129 ret, strerror(-ret));
01130
01131 nla_put_failure:
01132 nlmsg_free(msg);
01133 return ret;
01134 }
01141 int nl80211_set_channel(guint32 ifindex, guint32 channel)
01142 {
01143 struct nl_msg *msg;
01144 gint ret = -1;
01145 void *hdr;
01146
01147 msg = nlmsg_alloc();
01148 if (!msg)
01149 return -ENOMEM;
01150
01151 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01152 NL80211_CMD_SET_WIPHY, 0);
01153 if (hdr == NULL) {
01154 goto nla_put_failure;
01155 }
01156 guint32 freq = channel_to_freq(channel);
01157
01158 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
01159 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
01160
01161 ret = nl_send_recv_msgs(msg, NULL, NULL);
01162
01163 if (ret)
01164 DLOG_ERR("nl80211: failed to send set channel ret=%d (%s)",
01165 ret, strerror(-ret));
01166
01167 nla_put_failure:
01168 nlmsg_free(msg);
01169 return ret;
01170 }
01176 int nl80211_leave_adhoc(guint32 ifindex)
01177 {
01178 struct nl_msg *msg;
01179 gint ret = -1;
01180 void *hdr;
01181
01182 msg = nlmsg_alloc();
01183 if (!msg)
01184 return -ENOMEM;
01185
01186 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0, NL80211_CMD_LEAVE_IBSS, 0);
01187 if (hdr == NULL) {
01188 DLOG_ERR("nl80211: Failed to put leave ibss message");
01189 goto nla_put_failure;
01190 }
01191 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
01192 ret = nl_send_recv_msgs(msg, NULL, NULL);
01193 if (ret) {
01194 DLOG_ERR("nl80211: Leave IBSS failed: ret=%d (%s)", ret,
01195 strerror(-ret));
01196 goto nla_put_failure;
01197 }
01198 ret = 0;
01199 DLOG_DEBUG("nl80211: Leave IBSS request sent successfully");
01200
01201 nla_put_failure:
01202 nlmsg_free(msg);
01203 return ret;
01204 }
01213 int nl80211_mlme_command(guchar* addr, guint16 cmd, guint16 reason_code, guint32 ifindex)
01214 {
01215 gint ret = -1;
01216 struct nl_msg *msg;
01217 void *hdr;
01218
01219 msg = nlmsg_alloc();
01220 if (!msg)
01221 return -ENOMEM;
01222
01223 switch (cmd)
01224 {
01225 case WLANCOND_MLME_DEAUTH:
01226 DLOG_INFO("nl80211: Deauthenticating");
01227 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01228 NL80211_CMD_DEAUTHENTICATE, 0);
01229 if (hdr == NULL) {
01230 DLOG_ERR("nl80211: Failed to deauthenticate");
01231 goto nla_put_failure;
01232 }
01233 break;
01234 case WLANCOND_MLME_DISASSOC:
01235 DLOG_INFO("nl80211: Disassociating");
01236 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01237 NL80211_CMD_DISASSOCIATE, 0);
01238 if (hdr == NULL) {
01239 DLOG_ERR("nl80211: Failed to disassociate");
01240 goto nla_put_failure;
01241 }
01242 break;
01243 case WLANCOND_NL80211_MLME_DISCONNECT:
01244 DLOG_INFO("nl80211: Disconnecting");
01245 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01246 NL80211_CMD_DISCONNECT, 0);
01247 if (hdr == NULL) {
01248 DLOG_ERR("nl80211: Failed to disconnect");
01249 goto nla_put_failure;
01250 }
01251 break;
01252 default:
01253 DLOG_ERR("nl80211: Invalid mlme command");
01254 goto nla_put_failure;
01255 }
01256
01257 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
01258 NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
01259 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
01260
01261 ret = nl_send_recv_msgs(msg, NULL, NULL);
01262 if (ret) {
01263 DLOG_DEBUG("nl80211: MLME command failed in %s: ret=%d (%s)",
01264 __FUNCTION__, ret, strerror(-ret));
01265 goto nla_put_failure;
01266 }
01267 ret = 0;
01268
01269 nla_put_failure:
01270 nlmsg_free(msg);
01271 return ret;
01272 }
01273
01280 static int nl80211_signal_power_handler(struct nl_msg *msg, void *arg)
01281 {
01282 struct nlattr *tb[NL80211_ATTR_MAX + 1];
01283 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
01284 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
01285 guint8 *power = arg;
01286 *power = 0;
01287
01288 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
01289 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
01290 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
01291 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
01292 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
01293 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
01294 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
01295 [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
01296 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
01297 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
01298 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
01299 };
01300
01301 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
01302 genlmsg_attrlen(gnlh, 0), NULL);
01303
01304 if (!tb[NL80211_ATTR_STA_INFO]) {
01305 DLOG_ERR("nl80211: sta stats missing!");
01306 return NL_SKIP;
01307 }
01308 if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
01309 tb[NL80211_ATTR_STA_INFO],
01310 stats_policy)) {
01311 DLOG_ERR("nl80211: Failed to parse nested info attributes!");
01312 return NL_SKIP;
01313 }
01314
01315 if (sinfo[NL80211_STA_INFO_SIGNAL])
01316 *power = (guint8)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
01317
01318 return NL_SKIP;
01319 }
01320
01327 int nl80211_get_signal_info(guint8 *power, struct wlan_status_t *wlan_status)
01328 {
01329 struct nl_msg *msg;
01330 gint ret = -1;
01331 void *hdr;
01332 struct connect_params_t *conn = &wlan_status->conn;
01333
01334 msg = nlmsg_alloc();
01335 if (!msg)
01336 return ret;
01337
01338 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01339 NL80211_CMD_GET_STATION, 0);
01340 if (hdr == NULL) {
01341 DLOG_ERR("nl80211: Failed to put get station message");
01342 goto nla_put_failure;
01343 }
01344
01345 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wlan_status->ifindex);
01346 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, conn->bssid);
01347
01348 ret = nl_send_recv_msgs(msg, nl80211_signal_power_handler, power);
01349 if (ret) {
01350 DLOG_ERR("nl80211: MLME command failed in %s: ret=%d (%s)",
01351 __FUNCTION__, ret, strerror(-ret));
01352 goto nla_put_failure;
01353 }
01354 ret = 0;
01355
01356 nla_put_failure:
01357 nlmsg_free(msg);
01358 return ret;
01359 }
01360
01367 int nl80211_set_power_save(gboolean new_state, guint32 ifindex)
01368 {
01369 struct nl_msg *msg;
01370 gint ret = -1;
01371 void *hdr;
01372 enum nl80211_ps_state ps_state;
01373
01374 msg = nlmsg_alloc();
01375 if (!msg)
01376 return ret;
01377
01378 if (new_state)
01379 ps_state = NL80211_PS_ENABLED;
01380 else
01381 ps_state = NL80211_PS_DISABLED;
01382
01383 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01384 NL80211_CMD_SET_POWER_SAVE, 0);
01385 if (hdr == NULL) {
01386 DLOG_ERR("nl80211: Failed to put set power save message");
01387 goto nla_put_failure;
01388 }
01389
01390 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
01391 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
01392
01393 ret = nl_send_recv_msgs(msg, NULL, NULL);
01394 if (ret) {
01395 DLOG_ERR("nl80211: MLME command failed in %s: ret=%d (%s)",
01396 __FUNCTION__, ret, strerror(-ret));
01397 goto nla_put_failure;
01398 }
01399 ret = 0;
01400
01401 nla_put_failure:
01402 nlmsg_free(msg);
01403 return ret;
01404 }
01405
01413 int nl80211_scan(wlan_status_t* const wlan_status, int ssid_len, char* const ssid)
01414 {
01415 struct nl_msg *msg;
01416 struct nl_msg *ssid_attr = NULL;
01417
01418 void *hdr;
01419 gint ret = -ENOBUFS;
01420
01421 msg = nlmsg_alloc();
01422 if (!msg) {
01423 nl_perror(__func__);
01424 return -ENOMEM;
01425 }
01426
01427 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01428 NL80211_CMD_TRIGGER_SCAN, 0);
01429 if (!hdr) {
01430 DLOG_ERR("nl80211: Failed to put nl80211 message");
01431 nlmsg_free(msg);
01432 return -ENOMEM;
01433 }
01434
01435 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wlan_status->ifindex);
01436
01437 ssid_attr = nlmsg_alloc();
01438 if (ssid_attr == NULL) {
01439 nl_perror(__func__);
01440 nlmsg_free(msg);
01441 return -ENOMEM;
01442 }
01443
01444 if (ssid_len && ssid)
01445 NLA_PUT(ssid_attr, 1, ssid_len, ssid);
01446 else
01447 NLA_PUT(ssid_attr, 1, 0, "");
01448
01449 if (nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssid_attr)) {
01450 ret = -ENOMEM;
01451 goto nla_put_failure;
01452 }
01453
01454 ret = nl_send_recv_msgs(msg, NULL, NULL);
01455
01456 nla_put_failure:
01457 nlmsg_free(ssid_attr);
01458 nlmsg_free(msg);
01459 return ret;
01460 }
01461
01468 int nl80211_send_get_scan_results(wlan_status_t* const wlan_status, GSList** const scan_results)
01469 {
01470 struct nl_msg *msg;
01471
01472 void *hdr;
01473 gint ret = -ENOBUFS;
01474
01475 msg = nlmsg_alloc();
01476 if (!msg) {
01477 nl_perror(__func__);
01478 return -ENOMEM;
01479 }
01480
01481 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, NLM_F_DUMP,
01482 NL80211_CMD_GET_SCAN, 0);
01483 if (!hdr) {
01484 DLOG_ERR("nl80211: Failed to put nl80211 message");
01485 nlmsg_free(msg);
01486 return -ENOMEM;
01487 }
01488
01489 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wlan_status->ifindex);
01490
01491 scan_wlan_status = wlan_status;
01492
01493 ret = nl_send_recv_msgs(msg, nl80211_scan_result_handler, scan_results);
01494
01495 nla_put_failure:
01496 nlmsg_free(msg);
01497 return ret;
01498 }
01499
01506 static int nl80211_scan_result_handler(struct nl_msg *msg, void* arg)
01507 {
01508 struct nlattr *tb[NL80211_ATTR_MAX + 1];
01509 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
01510 struct nlattr *bss[NL80211_BSS_MAX + 1];
01511
01512 GSList **scan_results = (GSList**) arg;
01513 struct scan_results_t *scan_result;
01514 int ret = 0;
01515
01516 static const struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
01517 [NL80211_BSS_TSF] = { .type = NLA_U64 },
01518 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
01519 [NL80211_BSS_BSSID] = { },
01520 [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
01521 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
01522 [NL80211_BSS_INFORMATION_ELEMENTS] = { },
01523 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
01524 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
01525 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
01526 [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
01527 [NL80211_BSS_BEACON_IES] = { },
01528 };
01529
01530 unsigned char *ie;
01531 size_t ie_len;
01532 guint16 capabilities;
01533
01534 if (nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
01535 genlmsg_attrlen(gnlh, 0), NULL))
01536 return NL_SKIP;
01537
01538 if (!tb[NL80211_ATTR_BSS])
01539 return NL_SKIP;
01540
01541 if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
01542 (struct nla_policy *) bss_policy))
01543 return NL_SKIP;
01544
01545 if (!bss[NL80211_BSS_BSSID]
01546 || !bss[NL80211_BSS_INFORMATION_ELEMENTS]
01547 || !bss[NL80211_BSS_CAPABILITY]
01548 || !bss[NL80211_BSS_SIGNAL_MBM]
01549 || !bss[NL80211_BSS_FREQUENCY])
01550 return NL_SKIP;
01551
01552 int signal = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
01553 if (signal > 0 || signal < WLANCOND_MINIMUM_SIGNAL * 100)
01554 return NL_SKIP;
01555
01556 scan_result = g_slice_new0(struct scan_results_t);
01557
01558 capabilities = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
01559 if (capabilities & 0x10)
01560 scan_result->cap_bits |= WLANCOND_WEP;
01561
01562 scan_result->channel = freq_to_channel(
01563 nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
01564
01565 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
01566 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
01567 ret = nl80211_parse_ies(ie, ie_len, scan_result);
01568
01569 if (ret == 0) {
01570 memcpy(scan_result->bssid, nla_data(bss[NL80211_BSS_BSSID]),
01571 ETH_ALEN);
01572 print_mac(WLANCOND_PRIO_LOW, "BSSID:", scan_result->bssid);
01573
01574 scan_result->rssi = signal / 100;
01575
01576 if (capabilities & 0x02)
01577 scan_result->cap_bits |= WLANCOND_ADHOC;
01578 else
01579 scan_result->cap_bits |= WLANCOND_INFRA;
01580
01581 if (!(scan_result->cap_bits & WLANCOND_ENCRYPT_METHOD_MASK))
01582 scan_result->cap_bits |= WLANCOND_OPEN;
01583
01584 *scan_results = g_slist_prepend(*scan_results, scan_result);
01585 } else {
01586
01587 if (ret != -2)
01588 DLOG_DEBUG("Scan result discarded");
01589 clean_scan_results_item(scan_result, NULL);
01590 }
01591
01592 return NL_SKIP;
01593 }
01594
01600 static gboolean nl80211_is_supported_data_rate(guint8 data_rate) {
01601
01602 switch (data_rate) {
01603 case 108:
01604 case 96:
01605 case 72:
01606 case 48:
01607 case 36:
01608 case 24:
01609 case 22:
01610 case 18:
01611 case 12:
01612 case 11:
01613 case 4:
01614 case 2:
01615 return TRUE;
01616 default:
01617 return FALSE;
01618 }
01619 }
01620
01628 static int nl80211_parse_ies(unsigned char* const ie, size_t ie_len, scan_results_t* const scan_result)
01629 {
01630 struct ap_info_t ap_info;
01631 unsigned char *ie_last_byte = ie + ie_len - 1;
01632 unsigned char *current_ie = ie;
01633 guchar* security_ie = NULL;
01634 guint security_ie_len = 0;
01635 unsigned int i;
01636 const guint32 WMM_QOS_OFFSET = 8;
01637 const guint8 WMM_OUI[] = { 0x00, 0x50, 0xF2, 0x02, 0x01 };
01638 const guint8 WMM_UAPSD_MASK = 0x80;
01639 const guint8 WPA1_OUI[] = { 0x00, 0x50, 0xf2, 1 };
01640 const guint8 WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
01641 gboolean wapi_ie = FALSE;
01642 guint8 max_rate = 0;
01643 guint8 data_rate = 0;
01644
01645
01646 while (current_ie + 1 + current_ie[1] <= ie_last_byte) {
01647
01648 switch (current_ie[0]) {
01649
01650 case 0:
01651 if (scan_result->ssid_len)
01652 break;
01653
01654 if (current_ie[1] > WLANCOND_MAX_SSID_SIZE)
01655 return -1;
01656
01657 scan_result->ssid_len = current_ie[1] + 1;
01658
01659 if (scan_wlan_status->scan_ssid_len - 1 > 0 &&
01660 ((gint) scan_result->ssid_len != scan_wlan_status->scan_ssid_len
01661 || memcmp(current_ie + 2, scan_wlan_status->scan_ssid, scan_result->ssid_len - 1) != 0))
01662 return -2;
01663
01664 strncpy(scan_result->ssid, (char*) current_ie + 2, current_ie[1]);
01665 scan_result->ssid[current_ie[1]] = '\0';
01666 DLOG_DEBUG("SSID: %s", scan_result->ssid);
01667 break;
01668
01669 case 1:
01670 case 50:
01671 for (i = 0; i < current_ie[1]; i++ ) {
01672 data_rate = current_ie[2 + i];
01673 if (nl80211_is_supported_data_rate(data_rate & 0x7F)) {
01674 if ((data_rate & 0x7F) > max_rate)
01675 max_rate = data_rate & 0x7F;
01676 }
01677 else if (data_rate & 0x80) {
01678
01679 scan_result->cap_bits |= WLANCOND_UNSUPPORTED_NETWORK;
01680 DLOG_ERR("Basic data rate %u.%u Mbps not supported", (data_rate & 0x7F), data_rate % 2 ? 5 : 0);
01681 }
01682 }
01683 break;
01684
01685 case 45:
01686 scan_result->cap_bits |= WLANCOND_RATE_HT_SUPPORT;
01687 DLOG_DEBUG("HT supported");
01688 break;
01689
01690 case 48:
01691 if (current_ie[1] < 3)
01692 break;
01693 security_ie_len = current_ie[1] + 2;
01694 security_ie = current_ie;
01695 scan_result->cap_bits |= WLANCOND_WPA2;
01696 break;
01697
01698 case 68:
01699 if (current_ie[2] != WAPI_VERSION)
01700 break;
01701 security_ie_len = current_ie[1] + 2;
01702 security_ie = current_ie;
01703 wapi_ie = TRUE;
01704 break;
01705
01706 case 221:
01707 if (current_ie[1] < 6)
01708 break;
01709
01710 if (!memcmp(¤t_ie[2], WMM_OUI, sizeof(WMM_OUI))
01711 && (current_ie[WMM_QOS_OFFSET] & WMM_UAPSD_MASK)) {
01712
01713 scan_result->extra_cap_bits |= WLANCOND_UAPSD_SUPPORTED;
01714 DLOG_DEBUG("U-APSD supported");
01715 }
01716 else if (!(scan_result->cap_bits & WLANCOND_ENCRYPT_WPA2_MASK)
01717 && memcmp(¤t_ie[2], WPA1_OUI,
01718 sizeof(WPA1_OUI)) == 0) {
01719 security_ie_len = current_ie[1] + 2;
01720 security_ie = current_ie;
01721 }
01722 else if (memcmp(¤t_ie[2], WPS_OUI,
01723 sizeof(WPS_OUI)) == 0) {
01724 handle_wps_ie(¤t_ie[6], scan_result,
01725 current_ie[1] + 2);
01726 }
01727 break;
01728
01729 default:
01730 break;
01731 }
01732
01733 current_ie += (current_ie[1] + 2);
01734 }
01735
01736 if (scan_result->ssid_len == 0)
01737 return -1;
01738
01739
01740
01741 switch (max_rate) {
01742 case 108:
01743 scan_result->cap_bits |= WLANCOND_RATE_540;
01744 break;
01745 case 22:
01746 scan_result->cap_bits |= WLANCOND_RATE_110;
01747 break;
01748 case 96:
01749 scan_result->cap_bits |= WLANCOND_RATE_480;
01750 break;
01751 case 72:
01752 scan_result->cap_bits |= WLANCOND_RATE_360;
01753 break;
01754 case 48:
01755 scan_result->cap_bits |= WLANCOND_RATE_240;
01756 break;
01757 case 36:
01758 scan_result->cap_bits |= WLANCOND_RATE_180;
01759 break;
01760 case 24:
01761 scan_result->cap_bits |= WLANCOND_RATE_120;
01762 break;
01763 case 18:
01764 scan_result->cap_bits |= WLANCOND_RATE_90;
01765 break;
01766 case 12:
01767 scan_result->cap_bits |= WLANCOND_RATE_60;
01768 break;
01769 case 11:
01770 scan_result->cap_bits |= WLANCOND_RATE_55;
01771 break;
01772 case 4:
01773 scan_result->cap_bits |= WLANCOND_RATE_20;
01774 break;
01775 case 2:
01776 scan_result->cap_bits |= WLANCOND_RATE_10;
01777 break;
01778 default:
01779 DLOG_ERR("Invalid max rate: %d", max_rate);
01780 return -1;
01781 }
01782
01783 if (security_ie) {
01784 memset(&ap_info, 0, sizeof(ap_info));
01785
01786 if (wapi_ie == TRUE) {
01787 if (parse_wapi_ie(security_ie, security_ie_len, &ap_info) < 0) {
01788 return -1;
01789 }
01790 } else if (scan_result->cap_bits & WLANCOND_ENCRYPT_WPA2_MASK) {
01791 if (parse_rsn_ie(security_ie, security_ie_len, &ap_info) < 0) {
01792 return -1;
01793 }
01794 } else {
01795 if (parse_wpa_ie(security_ie, security_ie_len, &ap_info) < 0) {
01796 return -1;
01797 }
01798 }
01799
01800 save_caps(scan_result, &ap_info, security_ie, security_ie_len);
01801 }
01802
01803 return 0;
01804 }
01805
01812 int nl80211_set_cqm(guint32 threshold, guint32 hyst)
01813 {
01814 struct nl_msg *msg;
01815 struct nl_msg *cqm_msg;
01816 int ret = -1;
01817 void *hdr;
01818
01819
01820 if (get_mode() == WLANCOND_ADHOC)
01821 return 0;
01822
01823 msg = nlmsg_alloc();
01824 if (!msg)
01825 return ret;
01826
01827 cqm_msg = nlmsg_alloc();
01828 if (!cqm_msg) {
01829 nlmsg_free(msg);
01830 return ret;
01831 }
01832
01833 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01834 NL80211_CMD_SET_CQM, 0);
01835 if (hdr == NULL) {
01836 DLOG_ERR("nl80211: Failed to put set cqm message");
01837 goto nla_put_failure;
01838 }
01839
01840 NLA_PUT_U32(cqm_msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
01841 NLA_PUT_U32(cqm_msg, NL80211_ATTR_CQM_RSSI_HYST, hyst);
01842
01843 if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm_msg)) {
01844 ret = -ENOMEM;
01845 goto nla_put_failure;
01846 }
01847
01848 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wlan_status.ifindex);
01849
01850 ret = nl_send_recv_msgs(msg, NULL, NULL);
01851 if (ret) {
01852 DLOG_ERR("nl80211: set cqm failed: err=%d %s)", ret,
01853 strerror(-ret));
01854 goto nla_put_failure;
01855 }
01856
01857 ret = 0;
01858
01859 nla_put_failure:
01860 nlmsg_free(msg);
01861 nlmsg_free(cqm_msg);
01862 return ret;
01863 }
01864
01872 static void save_caps(struct scan_results_t *scan_results,
01873 struct ap_info_t *ap_info, unsigned char *p,
01874 unsigned int length)
01875 {
01876 scan_results->wpa_ie = g_memdup(p, length);
01877 scan_results->wpa_ie_len = length;
01878
01879
01880 scan_results->cap_bits |=
01881 ap_info->key_mgmt & WLANCOND_ENCRYPT_METHOD_MASK;
01882
01883
01884 if ((ap_info->key_mgmt & WLANCOND_ENCRYPT_METHOD_MASK) ==
01885 WLANCOND_WPA_PSK ||
01886 (ap_info->key_mgmt & WLANCOND_ENCRYPT_METHOD_MASK) ==
01887 WLANCOND_WPA_EAP) {
01888 if ((ap_info->key_mgmt & WLANCOND_ENCRYPT_METHOD_MASK) ==
01889 WLANCOND_WPA_EAP) {
01890
01891 scan_results->cap_bits &= ~WLANCOND_WPS_MASK;
01892 }
01893
01894 scan_results->cap_bits &= ~WLANCOND_WEP;
01895
01896 DLOG_DEBUG("%s %s supported",
01897 (scan_results->cap_bits & WLANCOND_WPA2) ?
01898 "WPA2":"WPA",
01899 (ap_info->key_mgmt & WLANCOND_WPA_PSK) ?
01900 "PSK":"EAP");
01901
01902
01903
01904 if (ap_info->pairwise_cipher & CIPHER_SUITE_CCMP)
01905 scan_results->cap_bits |= WLANCOND_WPA_AES;
01906
01907 if (ap_info->pairwise_cipher & CIPHER_SUITE_TKIP)
01908 scan_results->cap_bits |= WLANCOND_WPA_TKIP;
01909
01910 if (wlan_status.allow_all_ciphers == TRUE) {
01911 if (ap_info->pairwise_cipher & CIPHER_SUITE_WEP40) {
01912 scan_results->extra_cap_bits |= WLANCOND_WEP40;
01913 }
01914 if (ap_info->pairwise_cipher & CIPHER_SUITE_WEP104) {
01915 scan_results->extra_cap_bits |= WLANCOND_WEP104;
01916 }
01917 if (ap_info->group_cipher & CIPHER_SUITE_WEP40) {
01918 scan_results->extra_cap_bits |= WLANCOND_WEP40_GROUP;
01919 }
01920 if (ap_info->group_cipher & CIPHER_SUITE_WEP104) {
01921 scan_results->extra_cap_bits |= WLANCOND_WEP104_GROUP;
01922 }
01923 } else {
01924 if (ap_info->pairwise_cipher & CIPHER_SUITE_WEP40 ||
01925 ap_info->pairwise_cipher & CIPHER_SUITE_WEP104 ||
01926 ap_info->group_cipher & CIPHER_SUITE_WEP40 ||
01927 ap_info->group_cipher & CIPHER_SUITE_WEP104) {
01928 DLOG_DEBUG("In WPA mode WEP is not allowed");
01929 scan_results->cap_bits |=
01930 WLANCOND_UNSUPPORTED_NETWORK;
01931 }
01932 }
01933 DLOG_DEBUG("%s/%s/%s/%s for unicast",
01934 (ap_info->pairwise_cipher & CIPHER_SUITE_CCMP)?"AES":"-",
01935 (ap_info->pairwise_cipher & CIPHER_SUITE_TKIP)?"TKIP":"-",
01936 (ap_info->pairwise_cipher & CIPHER_SUITE_WEP104)?"WEP104":"-",
01937 (ap_info->pairwise_cipher & CIPHER_SUITE_WEP40)?"WEP40":"-");
01938
01939 if (ap_info->group_cipher & CIPHER_SUITE_CCMP)
01940 scan_results->cap_bits |= WLANCOND_WPA_AES_GROUP;
01941
01942 if (ap_info->group_cipher & CIPHER_SUITE_TKIP)
01943 scan_results->cap_bits |= WLANCOND_WPA_TKIP_GROUP;
01944
01945 DLOG_DEBUG("%s/%s/%s/%s for multicast",
01946 (ap_info->group_cipher & CIPHER_SUITE_CCMP)?"AES":"-",
01947 (ap_info->group_cipher & CIPHER_SUITE_TKIP)?"TKIP":"-",
01948 (ap_info->group_cipher & CIPHER_SUITE_WEP104)?"WEP104":"-",
01949 (ap_info->group_cipher & CIPHER_SUITE_WEP40)?"WEP40":"-");
01950
01951 }
01952
01953
01954 else if ((ap_info->key_mgmt & WLANCOND_ENCRYPT_METHOD_MASK) ==
01955 WLANCOND_WAPI_PSK ||
01956 (ap_info->key_mgmt & WLANCOND_ENCRYPT_METHOD_MASK) ==
01957 WLANCOND_WAPI_CERT) {
01958
01959 DLOG_DEBUG("WAPI %s supported",
01960 ((ap_info->key_mgmt & WLANCOND_ENCRYPT_METHOD_MASK)
01961 == WLANCOND_WAPI_PSK) ? "PSK":"CERT");
01962
01963 if (ap_info->pairwise_cipher & CIPHER_SUITE_SMS4)
01964 scan_results->cap_bits |= WLANCOND_WAPI_SMS4;
01965 if (ap_info->group_cipher & CIPHER_SUITE_SMS4)
01966 scan_results->cap_bits |= WLANCOND_WAPI_SMS4_GROUP;
01967
01968 DLOG_DEBUG("%s/%s ciphers",
01969 (ap_info->pairwise_cipher & CIPHER_SUITE_SMS4)?
01970 "SMS4":"-",
01971 (ap_info->group_cipher & CIPHER_SUITE_SMS4)?
01972 "SMS4":"-");
01973 }
01974 }
01975
01982 int nl80211_set_tx_power(int tx_power, guint32 ifindex)
01983 {
01984 struct nl_msg *msg;
01985 gint ret = -1;
01986 enum nl80211_tx_power_setting type = NL80211_TX_POWER_LIMITED;
01987 void *hdr;
01988
01989 msg = nlmsg_alloc();
01990 if (!msg)
01991 return ret;
01992
01993 hdr = genlmsg_put(msg, getpid(), 0, nl_family_id, 0, 0,
01994 NL80211_CMD_SET_WIPHY, 0);
01995 if (hdr == NULL) {
01996 DLOG_ERR("nl80211: Failed to put set tx power message");
01997 goto nla_put_failure;
01998 }
01999
02000 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
02001 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
02002 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, tx_power);
02003
02004 ret = nl_send_recv_msgs(msg, NULL, NULL);
02005 if (ret) {
02006 DLOG_ERR("nl80211: set tx power command failed: ret=%d (%s)",
02007 ret, strerror(-ret));
02008 goto nla_put_failure;
02009 }
02010
02011 nla_put_failure:
02012 nlmsg_free(msg);
02013 return ret;
02014 }
02015