• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

dbus-signal.c

Go to the documentation of this file.
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 /* This structure has required fields for
00057    making a message to send the link mode 
00058    signal to the kernel.
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 /* Local functions */
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         //DLOG_DEBUG("Cleaning scan results");
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                         /* Check if the interface state has changed and if it
00309                            was not up */
00310                         if ((infomsg->ifi_change & IFF_UP) && 
00311                             !(infomsg->ifi_flags & IFF_UP)) {
00312                                 /* ifconfig wlan0 down */
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                 /* Error */
00359                 if (res < 0) {
00360                         if (errno != EINTR && errno != EAGAIN) {
00361                                 DLOG_ERR("Error reading netlink socket");
00362                         }
00363                         /* Don't do anything */
00364                         return;
00365                 }
00366 
00367                 /* EOF */
00368                 if (res == 0) {
00369                         return;
00370                 }
00371                 int len;
00372                 struct nlmsghdr *hdr = (struct nlmsghdr*)buf;
00373                 /* real handling in this loop */
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                         /* Ok, we have good message */
00383                         handle_message(hdr);
00384 
00385                         /* Get ready for next message */
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         /* Currently we just set the enabler to zero */
00588         set_iptables_state(0);
00589 }
00593 int set_iptables(void) {
00594         if (wlan_status.iptables_loaded == FALSE) {
00595                 /* Also check that the file does not exist.
00596                    If wlancond crashed the rules are already
00597                    loaded.
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         /* let's happily mix operstate and linkmode...*/
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 }

Generated on Wed Aug 10 2011 16:02:33 for WLAN Connection Daemon by  doxygen 1.7.1