00001
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <stdint.h>
00030 #include <string.h>
00031 #include <glib.h>
00032 #include <glib-object.h>
00033 #include <errno.h>
00034 #include <unistd.h>
00035 #include <sys/types.h>
00036 #include <sys/socket.h>
00037 #include <linux/types.h>
00038 #include <wlancond-dbus.h>
00039 #include <eap-dbus.h>
00040 #include <libnetfilter_log/libnetfilter_log.h>
00041
00042 #include "common.h"
00043 #include "daemon.h"
00044 #include "dbus.h"
00045 #include "dbus-handler.h"
00046 #include "log.h"
00047 #include "dbus-helper.h"
00048 #include "wpa.h"
00049 #include "wapi.h"
00050
00051 #define DBUS_API_SUBJECT_TO_CHANGE
00052 #include <dbus/dbus.h>
00053
00054 extern struct wlan_status_t wlan_status;
00055
00056
00057
00058
00059
00060 typedef struct rt_link_mode
00061 {
00062 struct nlmsghdr nlh;
00063 struct ifinfomsg info;
00064 struct rtattr rta;
00065 char rta_data[4];
00066 } rt_link_mode;
00067
00069 static int netlink_socket = -1;
00071 static struct nflog_handle *nf_handle;
00072
00073 #define NFLOG_PACKET_SIZE 512
00074
00075
00076
00077 void print_mac(guint priority, const char *message, guchar* mac)
00078 {
00079 if (priority > WLANCOND_PRIO_MEDIUM)
00080 DLOG_INFO("%s %02x:%02x:%02x:%02x:%02x:%02x", message, mac[0],
00081 mac[1], mac[2], mac[3], mac[4], mac[5]);
00082 else {
00083 DLOG_DEBUG("%s %02x:%02x:%02x:%02x:%02x:%02x", message, mac[0],
00084 mac[1], mac[2], mac[3], mac[4], mac[5]);
00085 }
00086 }
00087 void clean_scan_results_item(gpointer data, gpointer user_data)
00088 {
00089 struct scan_results_t *scan_results = data;
00090 g_free(scan_results->wpa_ie);
00091 g_free(scan_results->uuid_e);
00092 g_slice_free(struct scan_results_t, scan_results);
00093 }
00094
00099 void clean_scan_results(GSList **scan_results_save)
00100 {
00101
00102
00103 g_slist_foreach(*scan_results_save, clean_scan_results_item, NULL);
00104 g_slist_free(*scan_results_save);
00105
00106 *scan_results_save = NULL;
00107
00108 }
00109
00116 void send_dbus_scan_results(GSList *scan_results_save, const char* sender,
00117 dbus_int32_t number_of_results)
00118 {
00119 DBusMessage *results;
00120 DBusMessageIter iter, sub;
00121 GSList *list;
00122 int list_count = 0;
00123 unsigned char* v;
00124 char* p;
00125
00126 if (sender == NULL || strnlen(sender, 5) == 0)
00127 return;
00128
00129 DLOG_INFO("Scan results (%d APs) to %s", number_of_results, sender);
00130
00131 results = new_dbus_signal(WLANCOND_SIG_PATH,
00132 WLANCOND_SIG_INTERFACE,
00133 WLANCOND_SCAN_RESULTS_SIG,
00134 sender);
00135
00136 dbus_message_iter_init_append(results, &iter);
00137
00138 if (number_of_results > WLANCOND_MAX_NETWORKS) {
00139 DLOG_DEBUG("Limiting result %d to %d", number_of_results,
00140 WLANCOND_MAX_NETWORKS);
00141 number_of_results = WLANCOND_MAX_NETWORKS;
00142 }
00143 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
00144 &number_of_results))
00145 die("Out of memory");
00146
00147 for (list = scan_results_save; list != NULL && list_count++ <=
00148 number_of_results; list = list->next) {
00149 struct scan_results_t *scan_results = list->data;
00150 DLOG_DEBUG("AP (%d) is %s, rssi:%d channel:%d cap:%08x",
00151 list_count,
00152 scan_results->ssid,
00153 scan_results->rssi, scan_results->channel,
00154 scan_results->cap_bits);
00155
00156 p = scan_results->ssid;
00157
00158 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
00159 "y", &sub))
00160 die("Out of memory");
00161 if (!dbus_message_iter_append_fixed_array(
00162 &sub, DBUS_TYPE_BYTE, &p,
00163 scan_results->ssid_len))
00164 die("Out of memory");
00165 if (!dbus_message_iter_close_container(&iter, &sub))
00166 die("Out of memory");
00167
00168 v = scan_results->bssid;
00169 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
00170 "y", &sub))
00171 die("Out of memory");
00172 if (!dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE,
00173 &v, ETH_ALEN))
00174 die("Out of memory");
00175 if (!dbus_message_iter_close_container(&iter, &sub))
00176 die("Out of memory");
00177 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
00178 &scan_results->rssi))
00179 die("Out of memory");
00180 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32,
00181 &scan_results->channel))
00182 die("Out of memory");
00183 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32,
00184 &scan_results->cap_bits))
00185 die("Out of memory");
00186 }
00187
00188 send_and_unref(get_dbus_connection(), results);
00189 }
00190
00194 void disconnected_signal(void)
00195 {
00196 DBusMessage *disconnected;
00197
00198 disconnected = new_dbus_signal(
00199 WLANCOND_SIG_PATH,
00200 WLANCOND_SIG_INTERFACE,
00201 WLANCOND_DISCONNECTED_SIG,
00202 NULL);
00203
00204 gchar* ifname = wlan_status.ifname;
00205
00206 append_dbus_args(disconnected,
00207 DBUS_TYPE_STRING, &ifname,
00208 DBUS_TYPE_INVALID);
00209
00210 send_and_unref(get_dbus_connection(), disconnected);
00211 }
00212
00217 void connected_signal(char* bssid)
00218 {
00219 DBusMessage *connected;
00220 dbus_int32_t auth_status = get_encryption_info();
00221 dbus_uint32_t wlan_mode = wlan_status.conn.mode;
00222
00223 if (!(wlan_mode & (WLANCOND_ADHOC | WLANCOND_INFRA))) {
00224 DLOG_ERR("WLAN mode unknown");
00225 return;
00226 }
00227
00228 connected = new_dbus_signal(
00229 WLANCOND_SIG_PATH,
00230 WLANCOND_SIG_INTERFACE,
00231 WLANCOND_CONNECTED_SIG,
00232 NULL);
00233
00234 gchar* ifname = wlan_status.ifname;
00235
00236 append_dbus_args(connected,
00237 DBUS_TYPE_STRING, &ifname,
00238 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &bssid, ETH_ALEN,
00239 DBUS_TYPE_INT32, &auth_status,
00240 DBUS_TYPE_UINT32, &wlan_mode,
00241 DBUS_TYPE_INVALID);
00242
00243 send_and_unref(get_dbus_connection(), connected);
00244 }
00245
00250 gboolean roam_scanning(void) {
00251 struct timeval tv;
00252
00253 if (gettimeofday(&tv, NULL) < 0)
00254 return FALSE;
00255
00256 if (tv.tv_sec > wlan_status.last_scan + WLANCOND_MIN_ROAM_SCAN_INTERVAL)
00257 return FALSE;
00258
00259 DLOG_DEBUG("Already roam scanning");
00260 return TRUE;
00261 }
00266 gboolean is_connected_state(void) {
00267 guint state_v = get_wlan_state();
00268
00269 if (state_v == WLAN_INITIALIZED_FOR_CONNECTION ||
00270 state_v == WLAN_NO_ADDRESS ||
00271 state_v == WLAN_CONNECTED)
00272 return TRUE;
00273 return FALSE;
00274 }
00279 static void handle_message(struct nlmsghdr *hdr)
00280 {
00281 struct ifinfomsg *infomsg;
00282 unsigned ifindex;
00283
00284 if (hdr->nlmsg_type != RTM_DELLINK && hdr->nlmsg_type != RTM_NEWLINK)
00285 return;
00286 if (hdr->nlmsg_len - sizeof(*hdr) < sizeof(*infomsg))
00287 return;
00288
00289 infomsg = NLMSG_DATA(hdr);
00290 ifindex = infomsg->ifi_index;
00291
00292 if (wlan_status.ifindex &&
00293 hdr->nlmsg_type == RTM_DELLINK &&
00294 ifindex == wlan_status.ifindex) {
00295
00296 DLOG_DEBUG("Current interface in use, disconnecting...");
00297
00298 wlan_status.ifindex = 0;
00299
00300 set_wlan_state(WLAN_NOT_INITIALIZED,
00301 DISCONNECTED_SIGNAL,
00302 FALSE);
00303
00304 clean_dbus_handler();
00305 }
00306 else if (hdr->nlmsg_type == RTM_NEWLINK) {
00307 if (ifindex == wlan_status.ifindex) {
00308
00309
00310 if ((infomsg->ifi_change & IFF_UP) &&
00311 !(infomsg->ifi_flags & IFF_UP)) {
00312
00313 if (wlan_status.if_down_self == TRUE) {
00314 wlan_status.if_down_self = FALSE;
00315 } else {
00316 DLOG_DEBUG("If down by someone else?");
00317 int signal = NO_SIGNAL;
00318
00319 if (is_connected_state() == TRUE)
00320 signal = DISCONNECTED_SIGNAL;
00321 set_wlan_state(WLAN_NOT_INITIALIZED,
00322 signal,
00323 FALSE);
00324 }
00325 }
00326 } else {
00327 char ifname[IFNAMSIZ+1];
00328
00329 if (if_indextoname(ifindex, ifname) == NULL)
00330 return;
00331 if (strncmp(wlan_status.ifname, ifname, sizeof(ifname)))
00332 return;
00333
00334 DLOG_DEBUG("Interface added");
00335
00336 clean_dbus_handler();
00337 run_calibration();
00338 wlan_status.ifindex = ifindex;
00339 }
00340 }
00341 }
00342
00347 static void handle_netlink_event(int fd)
00348 {
00349 char buf[1024];
00350 struct sockaddr_nl nl;
00351 socklen_t nl_len = sizeof(struct sockaddr_nl);
00352 int res;
00353
00354 while (1) {
00355 res = recvfrom (fd, buf, sizeof(buf), MSG_DONTWAIT,
00356 (struct sockaddr*)&nl, &nl_len);
00357
00358
00359 if (res < 0) {
00360 if (errno != EINTR && errno != EAGAIN) {
00361 DLOG_ERR("Error reading netlink socket");
00362 }
00363
00364 return;
00365 }
00366
00367
00368 if (res == 0) {
00369 return;
00370 }
00371 int len;
00372 struct nlmsghdr *hdr = (struct nlmsghdr*)buf;
00373
00374 while (res >= (int)sizeof(*hdr))
00375 {
00376 len = hdr->nlmsg_len;
00377
00378 if ((len - (int)sizeof(*hdr) < 0) || len > res) {
00379 DLOG_ERR("Error in netlink message length");
00380 break;
00381 }
00382
00383 handle_message(hdr);
00384
00385
00386 len = NLMSG_ALIGN(len);
00387 res -= len;
00388 hdr = (struct nlmsghdr*)((char*)hdr+len);
00389 }
00390 }
00391 }
00392
00398 static int init_wi (struct sockaddr_nl *rth)
00399 {
00400 unsigned int addr_len;
00401
00402 netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
00403 if (netlink_socket < 0) {
00404 DLOG_ERR("socket()");
00405 return -1;
00406 }
00407 memset(rth, 0, sizeof(struct sockaddr_nl));
00408
00409 rth->nl_family = AF_NETLINK;
00410 rth->nl_groups = RTMGRP_LINK;
00411
00412 if (bind(netlink_socket, (struct sockaddr*)rth,
00413 sizeof(struct sockaddr_nl)) < 0) {
00414 DLOG_ERR("bind()");
00415 return -1;
00416 }
00417 addr_len = sizeof(struct sockaddr_nl);
00418 if (getsockname(netlink_socket, (struct sockaddr*)rth, &addr_len) < 0) {
00419 DLOG_ERR("Cannot getsockname");
00420 return -1;
00421 }
00422 if (addr_len != sizeof(struct sockaddr_nl)) {
00423 DLOG_ERR("Wrong address length %d", addr_len);
00424 return -1;
00425 }
00426 if (rth->nl_family != AF_NETLINK) {
00427 DLOG_ERR("Wrong address family %d", rth->nl_family);
00428 return -1;
00429 }
00430
00431 return 0;
00432 }
00433
00441 static gboolean _monitor_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
00442 {
00443 int fd;
00444
00445 if (cond != G_IO_IN) {
00446 guint watch_id = *((guint *)data);
00447 DLOG_ERR("Error message from wireless interface");
00448 g_source_remove(watch_id);
00449 g_io_channel_unref(chan);
00450 return FALSE;
00451 }
00452
00453 fd = g_io_channel_unix_get_fd(chan);
00454 if (fd >= 0) {
00455 handle_netlink_event(fd);
00456 }
00457
00458 return TRUE;
00459 }
00460
00468 static gboolean _monitor_nflog_cb(GIOChannel *chan, GIOCondition cond,
00469 gpointer data)
00470 {
00471 int fd;
00472 int len;
00473 char buf[NFLOG_PACKET_SIZE];
00474
00475 if (cond != G_IO_IN) {
00476 guint watch_id = *((guint *)data);
00477 DLOG_ERR("Error message from NFLOG interface");
00478 g_source_remove(watch_id);
00479 g_io_channel_unref(chan);
00480 return FALSE;
00481 }
00482
00483 fd = g_io_channel_unix_get_fd(chan);
00484 if (fd >= 0) {
00485 len = recv(fd, &buf, sizeof(buf), 0);
00486 if (len >= 0) {
00487 nflog_handle_packet(nf_handle, buf, len);
00488 }
00489 }
00490 return TRUE;
00491 }
00492
00493 static int nflog_cb(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg,
00494 struct nflog_data *nfa, void *data) {
00495
00496 if (!nfa)
00497 return 0;
00498
00499 const char* p = nflog_get_prefix(nfa);
00500 if (p) {
00501 DLOG_DEBUG("NFLOG CB: %s", p);
00502 if (strncmp(p, "ABOVE", 5) == 0) {
00503 wlan_status.high_traffic = TRUE;
00504 } else if (strncmp(p, "BELOW", 5) == 0) {
00505 wlan_status.high_traffic = FALSE;
00506 } else {
00507 return 0;
00508 }
00509
00510 if (get_wlan_state() == WLAN_CONNECTED)
00511 set_power_state(wlan_status.powersave);
00512 }
00513 return 0;
00514 }
00519 static int init_nflog(void) {
00520 static guint nflog_watch_id = 0;
00521 struct nflog_g_handle *group;
00522 GIOChannel *gio;
00523 int fd;
00524
00525 nf_handle = nflog_open();
00526 if (!nf_handle)
00527 return -1;
00528
00529 group = nflog_bind_group(nf_handle, 0);
00530 if (!group) {
00531 nflog_close(nf_handle);
00532 return -1;
00533 }
00534
00535 if (nflog_set_mode(group, NFULNL_COPY_NONE, NFLOG_PACKET_SIZE) < 0) {
00536 nflog_unbind_group(group);
00537 nflog_close(nf_handle);
00538 return -1;
00539 }
00540
00541 nflog_callback_register(group, &nflog_cb, NULL);
00542
00543 fd = nflog_fd(nf_handle);
00544 gio = g_io_channel_unix_new(fd);
00545 g_io_channel_set_close_on_unref(gio, TRUE);
00546 nflog_watch_id = g_io_add_watch(gio, G_IO_IN | G_IO_PRI | G_IO_ERR |
00547 G_IO_HUP, _monitor_nflog_cb,
00548 &nflog_watch_id);
00549
00550 return 0;
00551 }
00552
00553 #define WLAN_IPTABLES "/etc/network/wlan_iptables.sh"
00554 #define ENABLE_IPTABLES "/proc/net/nf_condition/enable_throughput"
00555
00559 static void set_iptables_state(unsigned int state) {
00560 char buf[4];
00561
00562 memset(&buf, 0, sizeof(buf));
00563
00564 DLOG_DEBUG("Setting iptables to %s", state==1?"ON":"OFF");
00565
00566 if (wlan_status.iptables_file == NULL) {
00567 wlan_status.iptables_file = fopen(ENABLE_IPTABLES, "w");
00568 if (wlan_status.iptables_file == NULL) {
00569 DLOG_DEBUG("Cannot open: %s", ENABLE_IPTABLES);
00570 return;
00571 }
00572 }
00573
00574 snprintf(buf, 2, "%d", state);
00575
00576 if (fwrite(buf, 2, 1, wlan_status.iptables_file) != 1) {
00577 DLOG_ERR("Could not write to: %s", ENABLE_IPTABLES);
00578 }
00579
00580 fflush(wlan_status.iptables_file);
00581 }
00585 void remove_iptables(void) {
00586
00587
00588 set_iptables_state(0);
00589 }
00593 int set_iptables(void) {
00594 if (wlan_status.iptables_loaded == FALSE) {
00595
00596
00597
00598
00599 FILE *file = fopen(ENABLE_IPTABLES, "r");
00600 if (file == NULL) {
00601
00602 DLOG_DEBUG("Loading new rules");
00603
00604 if (system("sh " WLAN_IPTABLES) < 0) {
00605 DLOG_ERR("Running iptables failed");
00606 return -1;
00607 }
00608 wlan_status.iptables_loaded = TRUE;
00609 } else {
00610 fclose(file);
00611 }
00612 }
00613
00614 set_iptables_state(1);
00615
00616 return 0;
00617 }
00618
00623 gboolean monitor_wi(void) {
00624 static guint watch_id = 0;
00625 GIOChannel *gio;
00626 struct sockaddr_nl rth;
00627
00628 if (init_wi(&rth) < 0)
00629 return FALSE;
00630
00631 if (init_nflog() < 0)
00632 DLOG_ERR("NFLOG init failed");
00633
00634 gio = g_io_channel_unix_new(netlink_socket);
00635 g_io_channel_set_close_on_unref(gio, TRUE);
00636 watch_id = g_io_add_watch(gio, G_IO_IN | G_IO_PRI | G_IO_ERR |
00637 G_IO_HUP, _monitor_cb, &watch_id);
00638 return TRUE;
00639 }
00640
00646 int netlink_send_linkmode(int lmode)
00647 {
00648 struct rt_link_mode msg;
00649 static int seq;
00650 int ret;
00651
00652 memset(&msg, 0, sizeof(msg));
00653
00654 msg.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
00655 msg.nlh.nlmsg_type = RTM_SETLINK;
00656 msg.nlh.nlmsg_flags = NLM_F_REQUEST;
00657 msg.nlh.nlmsg_seq = ++seq;
00658 msg.nlh.nlmsg_pid = 0;
00659
00660 msg.info.ifi_family = AF_UNSPEC;
00661 msg.info.ifi_type = 0;
00662 msg.info.ifi_index = wlan_status.ifindex;
00663 msg.info.ifi_flags = 0;
00664 msg.info.ifi_change = 0;
00665
00666
00667 msg.rta.rta_len = RTA_LENGTH(sizeof(char));
00668 *((char *)RTA_DATA(&msg.rta)) = lmode;
00669 msg.nlh.nlmsg_len = NLMSG_ALIGN(msg.nlh.nlmsg_len) +
00670 RTA_LENGTH(sizeof(char));
00671
00672 if (lmode == WLANCOND_IF_DORMANT) {
00673 msg.rta.rta_type = IFLA_LINKMODE;
00674 } else {
00675 msg.rta.rta_type = IFLA_OPERSTATE;
00676 }
00677
00678 DLOG_DEBUG("Linkmode set to: \"%s\"",
00679 lmode==WLANCOND_IF_DORMANT?"Dormant":"Up");
00680
00681 ret = send(netlink_socket, &msg, msg.nlh.nlmsg_len, 0);
00682 if (ret < 0) {
00683 DLOG_ERR("Sending link mode failed:"
00684 " %d (%s)", ret, strerror(-ret));
00685 return -1;
00686 }
00687
00688 return 0;
00689 }
00690
00699 static void monitor_full_ps_cb(ConnSettingsType type,
00700 const char *id,
00701 const char *key,
00702 ConnSettingsValue *value,
00703 void *user_data) {
00704
00705 if (value != NULL && key != NULL) {
00706 if (strcmp(key, FULL_PSM_SETTING) == 0) {
00707 if (value->type == CONN_SETTINGS_VALUE_BOOL) {
00708 wlan_status.full_psm_enabled =
00709 value->value.bool_val;
00710 DLOG_DEBUG("Full power save flag is %s",
00711 value->value.bool_val==TRUE?
00712 "enabled":"disabled");
00713
00714 if (can_adjust_psm())
00715 set_power_state(wlan_status.powersave);
00716 }
00717 }
00718 }
00719 }
00720
00725 gboolean monitor_iap_keys() {
00726
00727 gboolean error;
00728
00729 wlan_status.full_psm_enabled = get_setting_bool(
00730 FULL_PSM_SETTING, &error);
00731
00732 if (conn_settings_add_notify(
00733 wlan_status.setting,
00734 (ConnSettingsNotifyFunc*) monitor_full_ps_cb,
00735 NULL) != TRUE) {
00736 DLOG_ERR("Adding notifier for full ps failed");
00737 return FALSE;
00738 }
00739
00740 return TRUE;
00741 }