From: Javier S. Pedro Date: Fri, 4 Sep 2009 21:54:03 +0000 (+0200) Subject: initial import X-Git-Tag: libicd_network_wpa_0_0_1^0 X-Git-Url: http://git.maemo.org/git/?p=libicd-wpa;a=commitdiff_plain;h=40dfec5157a34bdef21fd068802e445131468fab;hp=3a9cdc82c4162ac0884f71fa15c61fa49bcd0541 initial import --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..c3fddc9 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ +Javier S. Pedro + +osso-wlan: +Janne Ylälehto +Johan Hedberg + +wpa_supplicant: +Jouni Malinen and contributors diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..acd2cab --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +LIBTOOL=libtool + +CFLAGS += -Wall -O2 -DDEBUG -DOSSOLOG_STDERR -shared +LDFLAGS += -shared -module + +# Library flags +PKG_CFLAGS := $(shell pkg-config --cflags glib-2.0 gconf-2.0 dbus-1 dbus-glib-1 osso-ic) +PKG_LDFLAGS := $(shell pkg-config --libs glib-2.0 gconf-2.0 dbus-1 dbus-glib-1) +CFLAGS += $(PKG_CFLAGS) +LDFLAGS += $(PKG_LDFLAGS) + +LTFLAGS = -shared + +BINARY = libicd_network_wpa.so +OBJS = icd.o wlan.o networks.o gconf.o \ + dbus.o dbus-helper.o dbus-handler.o supp.o + +all: $(BINARY) + +$(BINARY): $(OBJS) + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $^ + +%.o: %.c + $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) -c $< -o $@ + +clean: + $(LIBTOOL) --mode=clean $(RM) libicd_network_wpa.so *.o + +install: $(BINARY) + $(LIBTOOL) --mode=install install -c --strip --mode=644 \ + $(BINARY) $(DESTDIR)/usr/lib/icd2/ + $(LIBTOOL) --mode=finish $(DESTDIR)/usr/lib/icd2/ + + +.PHONY: all clean install + diff --git a/README b/README new file mode 100644 index 0000000..566c4f8 --- /dev/null +++ b/README @@ -0,0 +1,18 @@ +This won't work at all without patching some system components first: + +- The cx3110 kernel module & wpa_supplicant + I am including a modified version of Lauro Ramos' cx3110x.patch + (makes cx3110x implement WE18) which enables a modified version of + wpa_supplicant to work with the driver without disabling + libicd-network-wlan in the process. + See patches/cx3110-module-src and patches/wpasupplicant. + +- "wlancond" + Implements a "I'm already reading wireless events by + myself, no need to bother me with d-bus events and no need to take + down the wireless interface for me, just set powersave" mode. + See patches/osso-wlan. + +See also +http://maemo.org/community/maemo-developers/libicd-network-wpa/ + diff --git a/TODO b/TODO new file mode 100644 index 0000000..755823c --- /dev/null +++ b/TODO @@ -0,0 +1,5 @@ +- Discover why can't I just pass the bssid to icd's search results + Right now it just terminates if I do. + +- Intra-ESS roaming seems to be slow when using WPA2. Needs testing. + diff --git a/common.h b/common.h new file mode 100644 index 0000000..3f3fca3 --- /dev/null +++ b/common.h @@ -0,0 +1,45 @@ +/** + @file common.h + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#define WPA_IFACE "wlan0" + +#define WPA_NETWORK_TYPE "WLAN_WPA" + +#define WPA_GCONF_NETWORK_TYPE "/type" +#define WPA_GCONF_NETWORK_TYPE_VALUE WPA_NETWORK_TYPE + +#define WPA_GCONF_SSID "/wpa_ssid" + +#define WPA_GCONF_SETTING_PREFIX "wpa_" +#define WPA_GCONF_SETTING_PREFIX_LEN 4 + +#define SEARCH_CONTINUE 0 +#define SEARCH_FINISHED 1 +#define SEARCH_STOPPED 2 + +#endif diff --git a/dbus-handler.c b/dbus-handler.c new file mode 100644 index 0000000..02ce44e --- /dev/null +++ b/dbus-handler.c @@ -0,0 +1,202 @@ +/** + @file dbus-helper.c + + Copyright (C) 2004 Nokia Corporation. All rights reserved. + + Copyright (C) 2009 Javier S. Pedro + + @author Janne Ylalehto + @author Johan Hedberg + + @author Javier S. Pedro + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include + +#include + +#include "dbus-helper.h" +#include "dbus-handler.h" +#include "wlan.h" +#include "supp.h" +#include "log.h" + +static DBusHandlerResult wlancond_scan_results_handler(DBusMessage *message) { + DBusMessageIter iter; + gint32 number_of_results, i; + + if (!wlan_is_scanning()) { + DLOG_DEBUG("Received scan results we didn't ask for"); + // TODO: Somehow use them + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + dbus_message_iter_init(message, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) + goto param_err; + + dbus_message_iter_get_basic(&iter, &number_of_results); + + dbus_message_iter_next(&iter); + + for (i = 0; i < number_of_results; i++) { + DBusMessageIter array_iter; + gint32 ssid_len, bssid_len; + gchar * ssid, * bssid; + gint32 rssi; + guint32 channel, cap_bits; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE) { + + goto param_err; + } + + dbus_message_iter_recurse(&iter, &array_iter); + dbus_message_iter_get_fixed_array(&array_iter, &ssid, &ssid_len); + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE) { + + goto param_err; + } + + dbus_message_iter_recurse(&iter, &array_iter); + dbus_message_iter_get_fixed_array(&array_iter, &bssid, &bssid_len); + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) + goto param_err; + dbus_message_iter_get_basic(&iter, &rssi); + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) + goto param_err; + dbus_message_iter_get_basic(&iter, &channel); + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) + goto param_err; + dbus_message_iter_get_basic(&iter, &cap_bits); + dbus_message_iter_next(&iter); + + DLOG_INFO("Scan result with %s.", ssid); + wlan_notify_ap(ssid, bssid, + rssi, channel, cap_bits); + } + + DLOG_DEBUG("Handled scan result, results=%ld.", + (long) number_of_results); + + wlan_notify_end_of_search(); + + return DBUS_HANDLER_RESULT_HANDLED; +param_err: + DLOG_WARN("Parameter error in scan request"); + + wlan_notify_end_of_search(); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult supp_state_change_handler(DBusMessage *message) { + gchar *old_state, *new_state; + + if (!dbus_message_get_args( + message, NULL, + DBUS_TYPE_STRING, &new_state, + DBUS_TYPE_STRING, &old_state, + DBUS_TYPE_INVALID)) + { + DLOG_WARN("Supplicant StateChange signal format error"); + return DBUS_HANDLER_RESULT_HANDLED; + } + + supp_handle_signal(old_state, new_state); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult wlancond_sig_handler(DBusConnection *connection, + DBusMessage *message, + void *user_data) { + if (dbus_message_is_signal(message, + WLANCOND_SIG_INTERFACE, + WLANCOND_SCAN_RESULTS_SIG)) + return wlancond_scan_results_handler(message); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult supp_sig_handler(DBusConnection *connection, + DBusMessage *message, + void *user_data) { + if (dbus_message_is_signal(message, + WPAS_DBUS_IFACE_INTERFACE, + WPAS_STATE_CHANGE_SIG)) + return supp_state_change_handler(message); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +/** + Create bindings for D-BUS handlers. + @param connection DBUS connection. +*/ +void init_dbus_handlers(DBusConnection *connection) { + gboolean ret; + /*dbus_bool_t ret; + ret = dbus_connection_register_object_path(connection, + WLANCOND_REQ_PATH, + &wlancond_req_vtable, + NULL); + if (ret == FALSE) { + DLOG_ERR("dbus_connection_register_object_path failed"); + }*/ + + dbus_bus_add_match(connection, + "interface=" WLANCOND_SIG_INTERFACE + ",member=" WLANCOND_SCAN_RESULTS_SIG, NULL); + + ret = dbus_connection_add_filter(connection, + (DBusHandleMessageFunction)wlancond_sig_handler, NULL, NULL); + + if (!ret) { + DLOG_ERR("dbus_connection_add_filter failed"); + } + + dbus_bus_add_match(connection, + "interface=" WPAS_DBUS_IFACE_INTERFACE + ",member=" WPAS_STATE_CHANGE_SIG, NULL); + + ret = dbus_connection_add_filter(connection, + (DBusHandleMessageFunction)supp_sig_handler, NULL, NULL); + + if (!ret) { + DLOG_ERR("dbus_connection_add_filter failed"); + } +} + +/** + Destroy D-BUS handlers. + @param connection DBUS connection. +*/ +void destroy_dbus_handlers(DBusConnection *connection) { + //dbus_connection_unregister_object_path(connection, WLANCOND_REQ_PATH); +} diff --git a/dbus-handler.h b/dbus-handler.h new file mode 100644 index 0000000..a274b6a --- /dev/null +++ b/dbus-handler.h @@ -0,0 +1,43 @@ +/** + @file dbus-helper.c + + Copyright (C) 2004 Nokia Corporation. All rights reserved. + + @author Janne Ylalehto + @author Johan Hedberg + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _DBUS_HANDLER_H_ +#define _DBUS_HANDLER_H_ + +#ifndef DBUS_API_SUBJECT_TO_CHANGE +# define DBUS_API_SUBJECT_TO_CHANGE +# include +#endif + +/** Bind functions to corresponding D-Bus messages + * @param connection D-Bus connection + */ +void init_dbus_handlers(DBusConnection *connection); + +/** Free memory allocated to handlers + * @param connection D-Bus connection + */ +void destroy_dbus_handlers(DBusConnection *connection); + +#endif /* _DBUS_HANDLER_H_ */ diff --git a/dbus-helper.c b/dbus-helper.c new file mode 100644 index 0000000..4d3d025 --- /dev/null +++ b/dbus-helper.c @@ -0,0 +1,308 @@ +/** + @file dbus-helper.c + + Copyright (C) 2004 Nokia Corporation. All rights reserved. + Copyright (C) 2003-2009, Jouni Malinen and contributors. + Copyright (C) 2009 Javier S. Pedro + + @author Janne Ylalehto + @author Johan Hedberg + @author Jouni Malinen and contributors + @author Javier S. Pedro + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +*/ +#include +#include +#include + +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include "log.h" +#include "dbus-helper.h" + +DBusMessage *new_dbus_signal(const char *path, + const char *interface, + const char *name, + const char *destination) { + DBusMessage *signal; + + signal = dbus_message_new_signal(path, interface, name); + if (signal == NULL) { + die("Out of memory during dbus_message_new_error()"); + } + + if (destination) { + if (!dbus_message_set_destination(signal, destination)) { + die("Out of memory during dbus_message_set_destination()"); + } + } + + dbus_message_set_no_reply(signal, TRUE); + + return signal; +} + +DBusMessage *new_dbus_method_call(const char *service, + const char *path, + const char *interface, + const char *method) { + DBusMessage *message; + + message = dbus_message_new_method_call(service, path, interface, method); + if (message == NULL) { + die("Out of memory during dbus_message_new_method_call()"); + } + + return message; +} + +DBusMessage *new_dbus_method_return(DBusMessage *message) { + DBusMessage *reply; + + reply = dbus_message_new_method_return(message); + if (reply == NULL) { + die("Out of memory during dbus_message_new_method_return()"); + } + + return reply; +} + +DBusMessage *new_dbus_error(DBusMessage *message, const char *name) { + DBusMessage *error; + + error = dbus_message_new_error(message, name, NULL); + if (error == NULL) { + die("Out of memory during dbus_message_new_error()"); + } + + return error; +} + +int send_and_unref(DBusConnection *connection, DBusMessage *message) { + if (!dbus_connection_send(connection, message, NULL)) { + dbus_message_unref(message); + return -1; + } + + dbus_connection_flush(connection); + dbus_message_unref(message); + + return 0; +} + +int send_invalid_args(DBusConnection *connection, DBusMessage *message) { + DBusMessage *reply; + + reply = new_dbus_error(message, DBUS_ERROR_INVALID_ARGS); + + return send_and_unref(connection, reply); +} + +void append_dbus_args(DBusMessage *message, int first_arg_type, ...) { + dbus_bool_t ret; + va_list ap; + + va_start(ap, first_arg_type); + ret = dbus_message_append_args_valist(message, first_arg_type, ap); + va_end(ap); + + if (ret == FALSE) { + die("dbus_message_append_args failed"); + } +} + +/** + * Start a dict in a dbus message. Should be paired with a call to + * {@link wpa_dbus_dict_close_write}. + * + * @param iter A valid dbus message iterator + * @param iter_dict (out) A dict iterator to pass to further dict functions + * @return 0 on success, -1 on failure + * + */ +int dbus_dict_open_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + dbus_bool_t result; + + if (!iter || !iter_dict) + return FALSE; + + result = dbus_message_iter_open_container( + iter, + DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + iter_dict); + + return (result ? 0 : -1); +} + +/** + * End a dict element in a dbus message. Should be paired with + * a call to {@link wpa_dbus_dict_open_write}. + * + * @param iter valid dbus message iterator, same as passed to + * wpa_dbus_dict_open_write() + * @param iter_dict a dbus dict iterator returned from + * {@link wpa_dbus_dict_open_write} + * @return 0 on success, -1 on failure + * + */ +int dbus_dict_close_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + if (!iter || !iter_dict) + return FALSE; + + return dbus_message_iter_close_container(iter, iter_dict) ? 0 : -1; +} + +static const char * _get_type_as_string_from_type(const int type) +{ + switch(type) { + case DBUS_TYPE_BYTE: + return DBUS_TYPE_BYTE_AS_STRING; + case DBUS_TYPE_BOOLEAN: + return DBUS_TYPE_BOOLEAN_AS_STRING; + case DBUS_TYPE_INT16: + return DBUS_TYPE_INT16_AS_STRING; + case DBUS_TYPE_UINT16: + return DBUS_TYPE_UINT16_AS_STRING; + case DBUS_TYPE_INT32: + return DBUS_TYPE_INT32_AS_STRING; + case DBUS_TYPE_UINT32: + return DBUS_TYPE_UINT32_AS_STRING; + case DBUS_TYPE_INT64: + return DBUS_TYPE_INT64_AS_STRING; + case DBUS_TYPE_UINT64: + return DBUS_TYPE_UINT64_AS_STRING; + case DBUS_TYPE_DOUBLE: + return DBUS_TYPE_DOUBLE_AS_STRING; + case DBUS_TYPE_STRING: + return DBUS_TYPE_STRING_AS_STRING; + case DBUS_TYPE_OBJECT_PATH: + return DBUS_TYPE_OBJECT_PATH_AS_STRING; + case DBUS_TYPE_ARRAY: + return DBUS_TYPE_ARRAY_AS_STRING; + default: + return NULL; + } +} + +static int _dbus_add_dict_entry_start( + DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, + const char *key, const int value_type) +{ + if (!dbus_message_iter_open_container(iter_dict, + DBUS_TYPE_DICT_ENTRY, NULL, + iter_dict_entry)) + return FALSE; + + if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING, + &key)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _dbus_add_dict_entry_end( + DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val) +{ + if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val)) + return FALSE; + if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry)) + return FALSE; + + return TRUE; +} + +static dbus_bool_t _dbus_add_dict_entry_basic(DBusMessageIter *iter_dict, + const char *key, + const int value_type, + const void *value) +{ + DBusMessageIter iter_dict_entry, iter_dict_val; + const char *type_as_string = NULL; + + type_as_string = _get_type_as_string_from_type(value_type); + if (!type_as_string) + return FALSE; + + if (!_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, + key, value_type)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_entry, + DBUS_TYPE_VARIANT, + type_as_string, &iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value)) + return FALSE; + + if (!_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, + &iter_dict_val)) + return FALSE; + + return TRUE; +} + +/** + * Add a string entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The string value + * @return TRUE on success, FALSE on failure + * + */ +int dbus_dict_append_string(DBusMessageIter *iter_dict, + const char *key, const char *value) +{ + if (!key || !value) + return FALSE; + return _dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING, + &value) ? 0 : -1; +} + +/** + * Add a 32-bit signed integer to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * {@link wpa_dbus_dict_open_write} + * @param key The key of the dict item + * @param value The 32-bit signed integer value + * @return TRUE on success, FALSE on failure + * + */ +int dbus_dict_append_int32(DBusMessageIter *iter_dict, + const char *key, + const dbus_int32_t value) +{ + if (!key) + return FALSE; + return _dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32, + &value) ? 0 : -1; +} + diff --git a/dbus-helper.h b/dbus-helper.h new file mode 100644 index 0000000..094ce0c --- /dev/null +++ b/dbus-helper.h @@ -0,0 +1,65 @@ +/** + @file dbus-helper.h + + Copyright (C) 2004 Nokia Corporation. All rights reserved. + + @author Janne Ylälehto + @author Jouni Malinen and contributors + @author Javier S. Pedro + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef _DBUS_HELPER_H_ +#define _DBUS_HELPER_H_ + +#ifndef DBUS_API_SUBJECT_TO_CHANGE +# define DBUS_API_SUBJECT_TO_CHANGE +# include +#endif + +void append_dbus_args(DBusMessage *message, int first_arg_type, ...); + +int send_and_unref(DBusConnection *connection, DBusMessage *message); + +int send_invalid_args(DBusConnection *connection, DBusMessage *message); + +DBusMessage *new_dbus_signal(const char *path, + const char *interface, + const char *name, + const char *destination); + +DBusMessage *new_dbus_method_call(const char *service, + const char *path, + const char *interface, + const char *method); + +DBusMessage *new_dbus_method_return(DBusMessage *message); + +DBusMessage *new_dbus_error(DBusMessage *message, const char *name); + +int dbus_dict_open_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict); +int dbus_dict_close_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +int dbus_dict_append_string(DBusMessageIter *iter_dict, + const char *key, const char *value); + +int dbus_dict_append_int32(DBusMessageIter *iter_dict, + const char *key, + const dbus_int32_t value); + +#endif /* _DBUD_HELPER_H_ */ diff --git a/dbus.c b/dbus.c new file mode 100644 index 0000000..cd14973 --- /dev/null +++ b/dbus.c @@ -0,0 +1,81 @@ +/** + @file dbus.c + + Copyright (C) 2004 Nokia Corporation. All rights reserved. + + @author Johan Hedberg + @author Janne Ylälehto + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include +#include +#include + +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include +#include + +#include "log.h" +#include "dbus.h" + +static DBusConnection *_dbus_connection = NULL; + +DBusConnection *get_dbus_connection(void) { + return _dbus_connection; +} + +int setup_dbus_connection(const char *service, + void (*handler_init)(DBusConnection *connection)) { + DBusError derror; + + g_assert(_dbus_connection == NULL); + + dbus_error_init(&derror); + _dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &derror); + if (_dbus_connection == NULL) { + DLOG_ERR("System DBus connection failed: %s", derror.message); + dbus_error_free(&derror); + return -1; + } + dbus_connection_setup_with_g_main(_dbus_connection, NULL); + + if (service) { + int ret = dbus_bus_request_name(_dbus_connection, service, 0, + &derror); + if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + DLOG_ERR("Could not aquire D-BUS name '%s' (ret: %d)", + service, ret); + if (dbus_error_is_set(&derror)) { + DLOG_DEBUG("%s", derror.message); + dbus_error_free(&derror); + } + return -1; + } + } + + if (handler_init) + handler_init(_dbus_connection); + + return 0; +} + +void close_dbus_connection(void) { + g_assert(_dbus_connection != NULL); + dbus_connection_unref(_dbus_connection); + _dbus_connection = NULL; +} diff --git a/dbus.h b/dbus.h new file mode 100644 index 0000000..ba53f24 --- /dev/null +++ b/dbus.h @@ -0,0 +1,42 @@ +/** + @file dbus.h + + Copyright (C) 2004 Nokia Corporation. All rights reserved. + + @author Johan Hedberg + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef _DBUS_H_ +#define _DBUS_H_ + +#ifndef DBUS_API_SUBJECT_TO_CHANGE +# define DBUS_API_SUBJECT_TO_CHANGE +# include +#endif + +/** Connect to the system D-Bus + * @returns 0 on success, -1 on failure + */ +int setup_dbus_connection(const char *service, + void (*handler_init)(DBusConnection *connection)); + +/** Disconnect from the system D-Bus */ +void close_dbus_connection(void); + +DBusConnection *get_dbus_connection(void); + +#endif /* _DBUS_H_ */ diff --git a/gconf.c b/gconf.c new file mode 100644 index 0000000..f08e567 --- /dev/null +++ b/gconf.c @@ -0,0 +1,51 @@ +/** + @file gconf.c + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include +#include + +#include "log.h" + +gchar * gconf_get_string(GConfClient *client, gchar * path) +{ + GError *error = NULL; + gchar *value = gconf_client_get_string(client, path, &error); + + if (error) { + DLOG_ERR("Could not get setting:%s, error:%s", path, + error->message); + + g_clear_error(&error); + value = NULL; + } else if (!value) { + DLOG_ERR("Could not get setting:%s", path); + } + + g_free(path); + + return value; +} diff --git a/gconf.h b/gconf.h new file mode 100644 index 0000000..4c52dee --- /dev/null +++ b/gconf.h @@ -0,0 +1,31 @@ +/** + @file gconf.h + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _GCONF_H_ +#define _GCONF_H_ + +gchar * gconf_get_string(GConfClient *client, gchar * path); + +#endif diff --git a/gconf/network-type.xml b/gconf/network-type.xml new file mode 100644 index 0000000..98b9f1c --- /dev/null +++ b/gconf/network-type.xml @@ -0,0 +1,55 @@ + + + + gettext_catalog + /schemas/system/osso/connectivity/network_type/WLAN_WPA/gettext_catalog + + osso-connectivity-ui + + + + icon_name + /schemas/system/osso/connectivity/network_type/WLAN_WPA/icon_name + + qgn_list_connectivity_iaptype_adhocwlan + + + + idle_timeout + + 0 + + + + name + /schemas/system/osso/connectivity/network_type/WLAN_WPA/name + + conn_mngr_fi_type_wlan_adhoc + + + + network_modules + /schemas/system/osso/connectivity/network_type/WLAN_WPA/network_modules + + + + libicd_network_wpa.so + + + libicd_network_ipv4.so + + + libicd_network_ipv6.so + + + + + + statusbar_icon_name + /schemas/system/osso/connectivity/network_type/WLAN_WPA/statusbar_icon_name + + qgn_stat_internetconn_adhocwlan + + + + diff --git a/icd.c b/icd.c new file mode 100644 index 0000000..4b07322 --- /dev/null +++ b/icd.c @@ -0,0 +1,531 @@ +/** + @file icd.c + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include +#include + +#include "common.h" +#include "dbus.h" +#include "dbus-handler.h" +#include "log.h" +#include "supp.h" +#include "networks.h" +#include "icd.h" + +/** time in seconds a found network is kept cached by icd2 */ +#define ICD_SEARCH_LIFETIME (5 * 60) +/** time in seconds after which a new network scan is to be triggered */ +#define ICD_SEARCH_INTERVAL (2 * 60) + +/** time (in milliseconds) to wait after a wpa_supplicant disconnected event + * before calling it a day and shutting down the interface */ +#define ICD_DISCONNECTED_TIMEOUT (60 * 1000) + +/** icd flags to use */ +#define ICD_WPA_FLAGS (ICD_NW_ATTR_AUTOCONNECT | ICD_NW_ATTR_IAPNAME) + + +/** equivalent to signal level 0 */ +#define RSSI_MIN (-85) +/** equivalent to signal level max */ +#define RSSI_MAX (-30) +/* guaranteed to be random, chosen by fair dice roll :) */ + + +static icd_nw_watch_pid_fn icd_watch_fn; +static gpointer icd_watch_token; +static icd_nw_close_fn icd_close_fn; +static icd_nw_status_change_fn icd_status_change_fn; +static icd_nw_renew_fn icd_renew_fn; + +static gchar * cur_network_id = NULL; + +/** @see ICD_DISCONNECTED_TIMEOUT */ +static guint connect_timeout = 0; + +static inline gint rssi_to_signal(gint rssi) +{ + gint signal = rssi - RSSI_MIN + ICD_NW_LEVEL_NONE; + signal *= ICD_NW_LEVEL_10; + signal /= (RSSI_MAX - RSSI_MIN); + + if (signal < ICD_NW_LEVEL_NONE) return ICD_NW_LEVEL_NONE; + else if (signal > ICD_NW_LEVEL_10) return ICD_NW_LEVEL_10; + else return signal; +} + +static gboolean disconnected_timeout_cb(gpointer data) +{ + // If connect_timeout is 0, we have been disabled. + if (!connect_timeout) return FALSE; + + // Disconnected for too long + DLOG_DEBUG("Disconnected for way too long"); + icd_close(ICD_NW_ERROR, ICD_DBUS_ERROR_NETWORK_ERROR); + connect_timeout = 0; + return FALSE; +} + +/** Supplicant callback while fully connected */ +static void icd_supp_cb(enum supp_status status, const char * error_str, + gpointer user_data) +{ + DLOG_DEBUG("%s: %d", __func__, status); + + switch (status) { + case SUPP_STATUS_ERROR: + DLOG_WARN_L("Unexpected supplicant error"); + + // Fall through + case SUPP_STATUS_KILLED: + // Close connection + icd_close(ICD_NW_ERROR, ICD_DBUS_ERROR_SYSTEM_ERROR); + + break; + case SUPP_STATUS_DISCONNECTED: + if (!connect_timeout) { + DLOG_DEBUG("Disconnected, starting timeout"); + connect_timeout = g_timeout_add( + ICD_DISCONNECTED_TIMEOUT, + disconnected_timeout_cb, + NULL + ); + } + break; + case SUPP_STATUS_CONNECTED: + if (connect_timeout) { + DLOG_DEBUG("Connected, removing timeout"); + g_source_remove(connect_timeout); + connect_timeout = 0; + } + break; + } + + // TODO Disable PSM while roaming (dis/asociating)? +} + +struct pre_down_data { + icd_nw_link_pre_down_cb_fn link_pre_down_cb; + gpointer link_pre_down_cb_token; +}; + +/** Supplicant callback in link_pre_down mode */ +static void icd_down_supp_cb(enum supp_status status, const char * error_str, + gpointer user_data) +{ + struct pre_down_data *data = (struct pre_down_data *) user_data; + DLOG_DEBUG("%s: %d", __func__, status); + + if (status == SUPP_STATUS_KILLED) { + // Everything was fine + supp_set_callback(NULL, NULL); + data->link_pre_down_cb(ICD_NW_SUCCESS, + data->link_pre_down_cb_token); + } +} + +static void +icd_pre_down (const gchar *network_type, + const guint network_attrs, + const gchar *network_id, + const gchar *interface_name, + icd_nw_link_pre_down_cb_fn link_pre_down_cb, + const gpointer link_pre_down_cb_token, + gpointer *private) +{ + DLOG_DEBUG(__func__); + + + struct pre_down_data *data = g_new(struct pre_down_data, 1); + data->link_pre_down_cb = link_pre_down_cb; + data->link_pre_down_cb_token = link_pre_down_cb_token; + + if (supp_is_active()) { + supp_set_callback(icd_down_supp_cb, data); + + // Kill the supplicant, + supp_disable(); + // but wait for the "child exit" event. + } else { + // Supplicant is already dead, no need to wait. + supp_set_callback(NULL, NULL); + supp_disable(); // Clears status info + + link_pre_down_cb(ICD_NW_SUCCESS, link_pre_down_cb_token); + } +} + +struct post_up_data { + icd_nw_link_post_up_cb_fn link_post_up_cb; + gpointer link_post_up_cb_token; +}; + +/** Supplicant callback in link_post_up status */ +static void icd_up_supp_cb(enum supp_status status, const char * error_str, + gpointer user_data) +{ + struct post_up_data *data = (struct post_up_data *) user_data; + DLOG_DEBUG("%s: %d", __func__, status); + + switch (status) { + case SUPP_STATUS_CONNECTED: + data->link_post_up_cb(ICD_NW_SUCCESS_NEXT_LAYER, + NULL, + data->link_post_up_cb_token, NULL); + + supp_set_callback(icd_supp_cb, NULL); + g_free(data); + break; + case SUPP_STATUS_DISCONNECTED: + error_str = ICD_DBUS_ERROR_WLAN_AUTH_FAILED; + + // Fall through + case SUPP_STATUS_ERROR: + + // An error happened + // kill the supplicant before everything crashes. + supp_set_callback(NULL, NULL); + supp_disable(); + + // Fall through + case SUPP_STATUS_KILLED: + data->link_post_up_cb(ICD_NW_ERROR, + error_str, + data->link_post_up_cb_token, NULL); + + g_free(data); + break; + + } +} + +static void icd_post_up(const gchar *network_type, + const guint network_attrs, + const gchar *network_id, + const gchar *interface_name, + icd_nw_link_post_up_cb_fn link_post_up_cb, + const gpointer link_post_up_cb_token, + gpointer *private) +{ + DLOG_DEBUG(__func__); + + struct post_up_data *data = g_new(struct post_up_data, 1); + data->link_post_up_cb = link_post_up_cb; + data->link_post_up_cb_token = link_post_up_cb_token; + + supp_set_callback(icd_up_supp_cb, data); + + if (supp_enable() != 0) + { + icd_up_supp_cb(-1, ICD_DBUS_ERROR_SYSTEM_ERROR, data); + } + + supp_set_interface(interface_name); + supp_set_network_id(network_id); +} + +static void icd_link_down(const gchar *network_type, + const guint network_attrs, + const gchar *network_id, + const gchar *interface_name, + icd_nw_link_down_cb_fn link_down_cb, + const gpointer link_down_cb_token, + gpointer *private) +{ + DLOG_DEBUG(__func__); + + networks_disconnect(network_id); + + g_free(cur_network_id); + cur_network_id = NULL; + + // TODO: Maybe wait for wlancond->disconnect callback? + + link_down_cb(ICD_NW_SUCCESS, link_down_cb_token); +} + +struct link_up_data { + icd_nw_link_up_cb_fn link_up_cb; + gpointer link_up_cb_token; +}; + +static void icd_link_up_done(int status, const char *error, gpointer user_data) +{ + DLOG_DEBUG("%s: %d", __func__, status); + + struct link_up_data *data = (struct link_up_data *) user_data; + + if (status) { + g_free(cur_network_id); + cur_network_id = NULL; + data->link_up_cb(ICD_NW_ERROR, + error, + WPA_IFACE, data->link_up_cb_token, + NULL); + + } else { + data->link_up_cb(ICD_NW_SUCCESS_NEXT_LAYER, + NULL, + WPA_IFACE, data->link_up_cb_token, + NULL); + } + + g_free(data); +} + +static void icd_link_up(const gchar *network_type, + const guint network_attrs, + const gchar *network_id, + icd_nw_link_up_cb_fn link_up_cb, + const gpointer link_up_cb_token, + gpointer *private) +{ + DLOG_DEBUG("%s: %s", __func__, network_id); + + struct link_up_data *data = g_new(struct link_up_data, 1); + data->link_up_cb = link_up_cb; + data->link_up_cb_token = link_up_cb_token; + + if (cur_network_id) { + DLOG_WARN_L("Double link up"); + + data->link_up_cb(ICD_NW_TOO_MANY_CONNECTIONS, + NULL, + WPA_IFACE, data->link_up_cb_token, + NULL); + + return; + } + cur_network_id = g_strdup(network_id); + + networks_connect(network_id, icd_link_up_done, data); +} + +struct stats_data { + icd_nw_link_stats_cb_fn cb; + gpointer token; +}; + +static void icd_link_stats_done + (int status, const char * strdata, int rssi, gpointer user_data) +{ + DLOG_DEBUG("%s: %d", __func__, status); + + struct stats_data * data = (struct stats_data *) user_data; + + gint signal = rssi_to_signal(rssi); + + DLOG_DEBUG("status: rssi=%d, signal=%d", rssi, signal); + + data->cb(data->token, + WPA_NETWORK_TYPE, + ICD_WPA_FLAGS, + cur_network_id, + /*time_active*/ 0, + /*signal*/ signal, + /*station_id*/ NULL, + /*dB*/ rssi, + /*tx*/0, + /*rx*/0); + + // IPv[46] module will fill time_active, rx & tx values. + // TODO station_id + + g_free(data); +} + +static void icd_link_stats(const gchar *network_type, + const guint network_attrs, + const gchar *network_id, + gpointer *private, + icd_nw_link_stats_cb_fn cb, + const gpointer link_stats_cb_token) +{ + DLOG_DEBUG("%s", __func__); + + struct stats_data *data = g_new(struct stats_data, 1); + data->cb = cb; + data->token = link_stats_cb_token; + + networks_status(icd_link_stats_done, data); +} + +struct search_data { + icd_nw_search_cb_fn search_cb; + gpointer search_cb_token; +}; + +static void icd_send_search_result(int status, const char * id, + const char * ssid, const char * ap, int rssi, gpointer user_data) +{ + DLOG_DEBUG("%s: %d", __func__, status); + + struct search_data * data = (struct search_data *) user_data; + gint signal; + + switch (status) { + case SEARCH_CONTINUE: + signal = rssi_to_signal(rssi); + + data->search_cb(ICD_NW_SEARCH_CONTINUE, + (gchar *) ssid, + WPA_NETWORK_TYPE, + ICD_WPA_FLAGS, + (gchar *) id, + signal, + /*ap*/"ap", + signal, + data->search_cb_token); + break; + case SEARCH_FINISHED: + data->search_cb(ICD_NW_SEARCH_COMPLETE, + NULL, + WPA_NETWORK_TYPE, + 0, + NULL, + ICD_NW_LEVEL_NONE, + NULL, + 0, + data->search_cb_token); + // Fall through + case SEARCH_STOPPED: + g_free(user_data); + break; + } +} + +static void icd_start_search(const gchar *network_type, + guint search_scope, + icd_nw_search_cb_fn search_cb, + const gpointer search_cb_token, + gpointer *private) +{ + DLOG_DEBUG(__func__); + + struct search_data *data = g_new(struct search_data, 1); + data->search_cb = search_cb; + data->search_cb_token = search_cb_token; + + networks_search_start(icd_send_search_result, data); +} + +static void icd_stop_search(gpointer *private) +{ + DLOG_DEBUG(__func__); + + // Never seen this called. + + networks_search_stop(); +} + +static void icd_child_exit(const pid_t pid, + const gint exit_value, + gpointer *private) +{ + DLOG_DEBUG(__func__); + + /*// Supplicant crashed/exited! + if (killed_supp_cb) { + // We have killed it, notify auth layer is now down. + + g_free(killed_supp_cb); + killed_supp_cb = 0; + } else { + DLOG_WARN("Supplicant exited, but we didn't expect it"); + icd_close(ICD_NW_ERROR, ICD_DBUS_ERROR_SYSTEM_ERROR); + }*/ + supp_handle_killed(); +} + +static void icd_network_destruct(gpointer *private) +{ + DLOG_DEBUG(__func__); + + // Fortunately, icd kills the supplicant for us. + + close_dbus_connection(); + networks_free(); +} + +gboolean icd_nw_init ( + struct icd_nw_api *network_api, + icd_nw_watch_pid_fn watch_fn, + gpointer watch_fn_token, + icd_nw_close_fn close_fn, + icd_nw_status_change_fn status_change_fn, + icd_nw_renew_fn renew_fn ) +{ + network_api->version = ICD_NW_MODULE_VERSION; + network_api->private = NULL; + + network_api->link_pre_down = icd_pre_down; + network_api->link_post_up = icd_post_up; + + network_api->link_down = icd_link_down; + network_api->link_up = icd_link_up; + network_api->link_stats = icd_link_stats; + + network_api->search_lifetime = ICD_SEARCH_LIFETIME; + network_api->search_interval = ICD_SEARCH_INTERVAL; + + network_api->start_search = icd_start_search; + network_api->stop_search = icd_stop_search; + + network_api->child_exit = icd_child_exit; + + network_api->network_destruct = icd_network_destruct; + + icd_watch_fn = watch_fn; + icd_watch_token = watch_fn_token; + icd_close_fn = close_fn; + icd_status_change_fn = status_change_fn; + icd_renew_fn = renew_fn; + + if (networks_initialize() != 0) { + DLOG_ERR_L("Network list failed!"); + return FALSE; + } + + if (setup_dbus_connection(NULL, init_dbus_handlers) != 0) { + DLOG_ERR_L("D-BUS connection setup failed!"); + return FALSE; + } + + return TRUE; +} + +void icd_watch_pid(const pid_t pid) +{ + icd_watch_fn(pid, icd_watch_token); +} + +void icd_close(enum icd_nw_status status, + const gchar *err_str) +{ + icd_close_fn(status, err_str, WPA_NETWORK_TYPE, ICD_WPA_FLAGS, cur_network_id); +} + diff --git a/icd.h b/icd.h new file mode 100644 index 0000000..467fbb7 --- /dev/null +++ b/icd.h @@ -0,0 +1,36 @@ +/** + @file icd.h + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _ICD_H_ +#define _ICD_H_ + +#include + +void icd_watch_pid(const pid_t pid); + +void icd_close(enum icd_nw_status status, + const gchar *err_str); + +#endif diff --git a/include/wlancond-supp.h b/include/wlancond-supp.h new file mode 100644 index 0000000..97b95f3 --- /dev/null +++ b/include/wlancond-supp.h @@ -0,0 +1,29 @@ +/* + libicd-network-wpa-dev + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License version 2.1 as + published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** + @file wlancond.h + + @author Javier S. Pedro +*/ + +#ifndef _WLANCOND_SUPP_H_ +#define _WLANCOND_SUPP_H_ + +#define WLANCOND_USE_SUPPLICANT (1 << 20) + +#endif diff --git a/log.h b/log.h new file mode 100644 index 0000000..9c45895 --- /dev/null +++ b/log.h @@ -0,0 +1,35 @@ +/** + @file log.h + + Copyright (C) 2004 Nokia Corporation. All rights reserved. + + @author Johan Hedberg + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef _LOG_H_ +#define _LOG_H_ + +#include +#include + +/** Print error message and exit */ +#define die(...) do { \ + DLOG_ERR(__VA_ARGS__); \ + exit(EXIT_FAILURE); \ +} while (0) + +#endif /* _LOG_H_ */ diff --git a/networks.c b/networks.c new file mode 100644 index 0000000..0761948 --- /dev/null +++ b/networks.c @@ -0,0 +1,408 @@ +/** + @file networks.c + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include +#include + +#include +#include + +#include +#include + +#include "common.h" +#include "log.h" +#include "wlan.h" +#include "networks.h" +#include "gconf.h" + +#define FAILED_SCAN_RETRY_WAIT 3 * 1000 +#define FAILED_SCAN_RETRY_TRIES 3 + +#define GCONF_NETWORK_TYPE "/type" + +static GSList *net_list = NULL; + +int networks_initialize() +{ + DLOG_DEBUG(__func__); + GConfClient *client = gconf_client_get_default(); + GError *error = NULL; + + net_list = NULL; + + if (!client) { + DLOG_ERR("Cannot get gconf client"); + return -1; + } + + net_list = gconf_client_all_dirs(client, ICD_GCONF_PATH, &error); + if (error) { + DLOG_ERR("Could not get setting:%s, error:%s", ICD_GCONF_PATH, + error->message); + g_clear_error(&error); + g_object_unref(client); + return -1; + } + + // Now, filter networks + GSList *prev = NULL; + GSList *cur = net_list; + while (cur) { + gchar* path = g_strconcat(cur->data, WPA_GCONF_NETWORK_TYPE, NULL); + gchar* type = gconf_client_get_string(client, path, &error); + + g_free(path); + + if (error) { + DLOG_ERR("Could not get setting:%s, error:%s", path, + error->message); + g_clear_error(&error); + + goto initialize_error; + } else if (!type) { + DLOG_ERR("Could not get setting:%s", path); + + goto initialize_error; + } + + if (strcmp(type, WPA_GCONF_NETWORK_TYPE_VALUE) != 0) { + // Remove this network from the list + DLOG_DEBUG("Ignoring %s from IAP (type is %s)", + (gchar*)cur->data, type); + g_free(cur->data); + if (prev) { + GSList *del = cur; + cur = g_slist_next(cur); + g_slist_free1(del); + prev->next = cur; + } else { + net_list = g_slist_next(cur); + g_slist_free1(cur); + cur = net_list; + } + } else { + DLOG_DEBUG("Added network %s from IAP", (gchar*)cur->data); + + prev = cur; + cur = g_slist_next(cur); + } + + g_free(type); + } + + return 0; + +initialize_error: + g_object_unref(client); + networks_free(); + + return -1; +} + +static void free_list_item(gpointer data, gpointer user_data) +{ + g_free(data); +} + +void networks_free() +{ + DLOG_DEBUG(__func__); + if (!net_list) return; + + g_slist_foreach(net_list, free_list_item, NULL); + + g_slist_free(net_list); + net_list = NULL; +} + + +/* Scanning networks */ + +static GSList *scan_cur_net = NULL; +static gchar *scan_cur_ssid = NULL; +static int scan_tries = 0; +static guint scan_retry_timer = 0; +static networks_search_found scan_found_cb = NULL; +static gpointer scan_found_cb_data = NULL; + +static void networks_search_iteration(); + +static void networks_search_finished() +{ + DLOG_DEBUG(__func__); + + scan_found_cb(SEARCH_FINISHED, NULL, + NULL, NULL, 0, scan_found_cb_data); + scan_cur_net = NULL; + + scan_found_cb = NULL; + scan_found_cb_data = NULL; + // Usually a new network_search will not happen on the FINISED cb, + // but if you do, you'll have to take care of the pseudorace here. + + networks_search_stop(); +} + +static void networks_search_scan_ap_found(int status, + const char * ssid, const char * ap, int dB) +{ + DLOG_DEBUG(__func__); + + if (!scan_cur_net) return; + if (scan_retry_timer) return; // Interface was already scanning + + if (status == SEARCH_FINISHED) { + DLOG_DEBUG("Searching for %s done, iterating", scan_cur_ssid); + // Go to next network + scan_cur_net = g_slist_next(scan_cur_net); + if (scan_cur_net) { + g_free(scan_cur_ssid); + scan_cur_ssid = NULL; + scan_tries = 0; + networks_search_iteration(); + } else { + // No more networks to search + networks_search_finished(); + } + } else if (status == SEARCH_CONTINUE) { + DLOG_DEBUG("Found ssid %s", ssid); + if (strcmp(ssid, scan_cur_ssid) == 0) + { + // This is our man + gchar *full_name = g_strdup(scan_cur_net->data); + + gchar *base_name = g_strdup(basename(full_name)); + + DLOG_INFO("%s (%s) was found", + base_name, ssid); + + scan_found_cb(SEARCH_CONTINUE, base_name, + ssid, ap, dB, scan_found_cb_data); + + g_free(base_name); + g_free(full_name); + } + } +} + +static gboolean networks_search_retry(gpointer data) +{ + DLOG_DEBUG(__func__); + + scan_retry_timer = 0; + if (scan_cur_net) networks_search_iteration(); + // Always disable this timeout, + // _search_iteration() will put a newer one if needed + return FALSE; +} + +static void networks_search_iteration() +{ + DLOG_DEBUG(__func__); + + GConfClient *client = gconf_client_get_default(); + GError *error = NULL; + + if (!client) { + DLOG_ERR("Cannot get gconf client"); + goto get_gconf_error; + } + + DLOG_DEBUG("Test if %s is active", (gchar*)scan_cur_net->data); + + gchar *path = g_strconcat(scan_cur_net->data, WPA_GCONF_SSID, NULL); + scan_cur_ssid = gconf_client_get_string(client, path, &error); + + g_object_unref(client); + + if (error) { + DLOG_ERR("Could not get setting:%s, error:%s", path, + error->message); + g_clear_error(&error); + + goto get_ssid_error; + } + else if (!scan_cur_ssid) { + DLOG_ERR("Could not get setting:%s", path); + + goto get_ssid_error; + } + + scan_retry_timer = 0; + + int result = wlan_scan(scan_cur_ssid, networks_search_scan_ap_found); + + if (result != 0) { + // Something went wront scanning this network, set timeout and + // try again + scan_tries++; + if (scan_tries >= FAILED_SCAN_RETRY_TRIES) { + // Give up + goto scan_error; + } else { + scan_retry_timer = g_timeout_add(FAILED_SCAN_RETRY_WAIT, + networks_search_retry, + NULL); + } + } + + return; +get_ssid_error: + g_free(path); + +get_gconf_error: +scan_error: + networks_search_finished(); +} + +void networks_search_start(networks_search_found found_cb, gpointer user_data) +{ + DLOG_DEBUG(__func__); + + if (scan_cur_net) + return; // Already active + + scan_cur_net = net_list; + scan_tries = 0; + scan_found_cb = found_cb; + scan_found_cb_data = user_data; + + if (scan_cur_net) + networks_search_iteration(); + else // No networks to scan? + networks_search_finished(); +} + +void networks_search_stop() +{ + DLOG_DEBUG(__func__); + + if (scan_found_cb) + scan_found_cb(SEARCH_STOPPED, + NULL, NULL, NULL, 0, scan_found_cb_data); + scan_cur_net = NULL; + + scan_found_cb = NULL; + scan_found_cb_data = NULL; + + g_free(scan_cur_ssid); + scan_cur_ssid = NULL; + + DLOG_DEBUG("Search stopped"); +} + +/* Connecting to networks */ + +static networks_connect_result connect_result_cb = NULL; +static gpointer connect_result_cb_data = NULL; + +static void networks_connected(int status, const char *error) +{ + DLOG_DEBUG("%s: %d", __func__, status); + + if (!connect_result_cb) return; + + if (status) { + connect_result_cb(status, ICD_DBUS_ERROR_NETWORK_ERROR, + connect_result_cb_data); + } else { + connect_result_cb(0, NULL, + connect_result_cb_data); + } + + connect_result_cb = NULL; +} + +void networks_connect(const char * id, + networks_connect_result result_cb, gpointer user_data) +{ + DLOG_DEBUG("%s: %s", __func__, id); + GConfClient *client = gconf_client_get_default(); + + connect_result_cb = result_cb; + connect_result_cb_data = user_data; + + gchar *net = g_strconcat(ICD_GCONF_PATH, "/", id, NULL); + gchar *path, *value; + + // Get ICD network type + path = g_strconcat(net, WPA_GCONF_NETWORK_TYPE, NULL); + value = gconf_get_string(client, path); + + if (!value || strcmp(value, WPA_GCONF_NETWORK_TYPE_VALUE) != 0) { + result_cb(-1, ICD_DBUS_ERROR_INVALID_IAP, user_data); + goto connect_error; + } + + g_free(value); + + path = g_strconcat(net, WPA_GCONF_SSID, NULL); + value = gconf_get_string(client, path); + + if (!value) { + result_cb(-1, ICD_DBUS_ERROR_INVALID_IAP, user_data); + goto connect_error; + } + + wlan_connect(value, networks_connected); + +connect_error: + if (value) g_free(value); +} + +void networks_disconnect(const char * id) +{ + wlan_disconnect(); +} + +/* -- STATUS -- */ + +static networks_status_result status_result_cb = NULL; +static gpointer status_result_cb_data = NULL; + +static void networks_status_reply(int status, + const char * essid, int essid_len, + const char * bssid, int bssid_len, + int qual, int channel, unsigned long security, unsigned long capability, + const char * data) +{ + if (!status_result_cb) return; + + if (status == 0) { + status_result_cb(status, essid, qual, status_result_cb_data); + } else { + status_result_cb(status, data, 0, status_result_cb_data); + } +} + +void networks_status(networks_status_result result_cb, gpointer user_data) +{ + status_result_cb = result_cb; + status_result_cb_data = user_data; + + wlan_get_status(networks_status_reply); +} + diff --git a/networks.h b/networks.h new file mode 100644 index 0000000..c06c41e --- /dev/null +++ b/networks.h @@ -0,0 +1,50 @@ +/** + @file networks.h + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _NETWORKS_H_ +#define _NETWORKS_H_ + +int networks_initialize(); +void networks_free(); + +// NULL, NULL, 0 if search ended +typedef void (*networks_search_found) + (int status, const char * id, + const char * ssid, const char * ap, int dB, gpointer user_data); + +void networks_search_start(networks_search_found found_cb, gpointer user_data); +void networks_search_stop(); + +typedef void (*networks_connect_result) + (int status, const char * error, gpointer user_data); +void networks_connect(const char * id, + networks_connect_result result_cb, gpointer user_data); +void networks_disconnect(const char * id); + +typedef void (*networks_status_result) + (int status, const char * data, int rssi, gpointer user_data); +void networks_status(networks_status_result result_cb, gpointer user_data); + +#endif diff --git a/patches/cx3110-module-src-2.0.15.patch b/patches/cx3110-module-src-2.0.15.patch new file mode 100644 index 0000000..4745894 --- /dev/null +++ b/patches/cx3110-module-src-2.0.15.patch @@ -0,0 +1,454 @@ +diff -rup src.orig/sm_drv_ioctl_umac.c src/sm_drv_ioctl_umac.c +--- src.orig/sm_drv_ioctl_umac.c 2009-02-16 23:51:34.000000000 +0100 ++++ src/sm_drv_ioctl_umac.c 2009-02-23 00:19:10.000000000 +0100 +@@ -1928,6 +1928,435 @@ static int sm_drv_set_pmk(struct net_dev + (void *)&key, sizeof(struct obj_stakey)); + } + ++static int sm_drv_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct net_local *priv = netdev_priv(dev); ++ struct iw_param *param = &wrqu->param; ++ u32 authen = 0, dot1x = 0; ++ u32 exunencrypt = 0, privinvoked = 0, wpa = 0; ++ u32 old_wpa; ++ int ret = 0; ++ ++ DEBUG(DBG_IOCTL, "SET AUTH\n"); ++ ++ /* first get the flags */ ++ down(&priv->wpa_sem); ++ wpa = old_wpa = priv->wpa; ++ up(&priv->wpa_sem); ++ ret = sm_drv_oid_get(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&privinvoked, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_DOT1XENABLE, ++ (void *)&dot1x, sizeof(uint32_t)); ++ ++ if (ret < 0) ++ goto out; ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ /* Do the same thing as IW_AUTH_WPA_VERSION */ ++ if (param->value) { ++ wpa = DOT11_PRIV_INV_TKIP; ++ privinvoked = 1; /* For privacy invoked */ ++ exunencrypt = 1; /* Filter out all unencrypted frames */ ++ dot1x = 0x01; /* To enable eap filter */ ++ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ ++ } else { ++ wpa = DOT11_PRIV_INV_NONE; ++ privinvoked = 0; ++ exunencrypt = 0; /* Do not filter un-encrypted data */ ++ dot1x = 0; ++ } ++ break; ++ ++ case IW_AUTH_WPA_VERSION: ++ if (param->value & IW_AUTH_WPA_VERSION_DISABLED) { ++ wpa = DOT11_PRIV_INV_NONE; ++ privinvoked = 0; ++ exunencrypt = 0; /* Do not filter un-encrypted data */ ++ dot1x = 0; ++ } else { ++ if (param->value & IW_AUTH_WPA_VERSION_WPA) ++ wpa = DOT11_PRIV_INV_TKIP; ++ else if (param->value & IW_AUTH_WPA_VERSION_WPA2) ++ wpa = DOT11_PRIV_INV_AES_CCMP; ++ privinvoked = 1; /* For privacy invoked */ ++ exunencrypt = 1; /* Filter out all unencrypted frames */ ++ dot1x = 0x01; /* To enable eap filter */ ++ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ ++ } ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ /* dot1x should be the opposite of RX_UNENCRYPTED_EAPOL; ++ * turn off dot1x when allowing receipt of unencrypted EAPOL ++ * frames, turn on dot1x when receipt should be disallowed ++ */ ++ dot1x = param->value ? 0 : 0x01; ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ privinvoked = param->value ? 1 : 0; ++ break; ++ ++ case IW_AUTH_DROP_UNENCRYPTED: ++ exunencrypt = param->value ? 1 : 0; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ if (param->value & IW_AUTH_ALG_SHARED_KEY) { ++ /* Only WEP uses _SK and _BOTH */ ++ if (wpa > 0) { ++ ret = -EINVAL; ++ goto out; ++ } ++ authen = DOT11_AUTH_SK; ++ } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { ++ authen = DOT11_AUTH_OS; ++ } else { ++ ret = -EINVAL; ++ goto out; ++ } ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ /* Set all the values */ ++ down(&priv->wpa_sem); ++ priv->wpa = wpa; ++ up(&priv->wpa_sem); ++ ++ sm_drv_oid_set(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&privinvoked, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_DOT1XENABLE, ++ (void *)&dot1x, sizeof(uint32_t)); ++ ++ out: ++ return ret; ++} ++ ++static int sm_drv_get_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct net_local *priv = netdev_priv(dev); ++ struct iw_param *param = &wrqu->param; ++ u32 authen = 0, dot1x = 0; ++ u32 exunencrypt = 0, privinvoked = 0, wpa = 0; ++ int ret = 0; ++ ++ DEBUG(DBG_IOCTL, "GET AUTH\n"); ++ ++ /* first get the flags */ ++ down(&priv->wpa_sem); ++ wpa = priv->wpa; ++ up(&priv->wpa_sem); ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ /* ++ * wpa_supplicant will control these internally ++ */ ++ ret = -EOPNOTSUPP; ++ break; ++ ++ case IW_AUTH_WPA_VERSION: ++ switch (wpa) { ++ case DOT11_PRIV_INV_TKIP: ++ param->value = IW_AUTH_WPA_VERSION_WPA; ++ break; ++ case DOT11_PRIV_INV_AES_CCMP: ++ param->value = IW_AUTH_WPA_VERSION_WPA2; ++ break; ++ default: ++ param->value = IW_AUTH_WPA_VERSION_DISABLED; ++ break; ++ } ++ break; ++ ++ case IW_AUTH_DROP_UNENCRYPTED: ++ ret = sm_drv_oid_get(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ if (ret >= 0) ++ param->value = exunencrypt > 0 ? 1 : 0; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ ret = sm_drv_oid_get(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ if (ret >= 0) { ++ switch (authen) { ++ case DOT11_AUTH_OS: ++ param->value = IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ case DOT11_AUTH_BOTH: ++ case DOT11_AUTH_SK: ++ param->value = IW_AUTH_ALG_SHARED_KEY; ++ case DOT11_AUTH_NONE: ++ default: ++ param->value = 0; ++ break; ++ } ++ } ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ param->value = wpa > 0 ? 1 : 0; ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ ret = sm_drv_oid_get(dev, DOT11_OID_DOT1XENABLE, ++ (void *)&dot1x, sizeof(uint32_t)); ++ if (ret >= 0) ++ param->value = dot1x > 0 ? 1 : 0; ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ ret = sm_drv_oid_get(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&privinvoked, sizeof(uint32_t)); ++ if (ret >= 0) ++ param->value = privinvoked > 0 ? 1 : 0; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ return ret; ++} ++ ++#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */ ++#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */ ++#define KEY_SIZE_TKIP 32 /* TKIP keys */ ++ ++static int sm_drv_set_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, alg = ext->alg, set_key = 1; ++ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; ++ int ret = 0; ++ ++ DEBUG(DBG_IOCTL, "SET ENCODEEXT\n"); ++ ++ /* Determine and validate the key index */ ++ idx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if (idx) { ++ if (idx < 0 || idx > 3) ++ return -EINVAL; ++ } else { ++ ret = sm_drv_oid_get(dev, DOT11_OID_DEFKEYID, ++ (void *)&idx, sizeof(uint32_t)); ++ if (ret < 0) ++ goto out; ++ } ++ ++ if (encoding->flags & IW_ENCODE_DISABLED) ++ alg = IW_ENCODE_ALG_NONE; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ /* Only set transmit key index here, actual ++ * key is set below if needed. ++ */ ++ ret = sm_drv_oid_set(dev, DOT11_OID_DEFKEYID, ++ (void *)&idx, sizeof(uint32_t)); ++ set_key = ext->key_len > 0 ? 1 : 0; ++ } ++ ++ if (set_key) { ++ switch (alg) { ++ case IW_ENCODE_ALG_NONE: ++ break; ++ case IW_ENCODE_ALG_WEP: { ++ struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; ++ memset(key.key, 0, sizeof(key.key)); ++ if (ext->key_len > KEY_SIZE_WEP104) { ++ ret = -EINVAL; ++ goto out; ++ } ++ if (ext->key_len > KEY_SIZE_WEP40) ++ key.length = KEY_SIZE_WEP104; ++ else ++ key.length = KEY_SIZE_WEP40; ++ memcpy(key.key, ext->key, ext->key_len); ++ ret = sm_drv_oid_set(dev, DOT11_OID_DEFKEYID + idx + 1, ++ (void *)&key, ++ sizeof(struct obj_key)); ++ break; ++ } ++ case IW_ENCODE_ALG_TKIP: ++ case IW_ENCODE_ALG_CCMP: { ++ struct obj_stakey key; ++ memset(key.key, 0, sizeof(key.key)); ++ if (alg == IW_ENCODE_ALG_TKIP) ++ key.type = DOT11_PRIV_TKIP; ++ else ++ key.type = DOT11_PRIV_AES_CCMP; ++ memcpy(key.address, ext->addr.sa_data, ETH_ALEN); ++ key.length = ext->key_len; ++ key.keyid = idx; ++ key.ext = 0; ++ memcpy(key.key, ext->key, ext->key_len); ++ ret = sm_drv_oid_set(dev, DOT11_OID_STAKEY, ++ (void *)&key, ++ sizeof(struct obj_stakey)); ++ break; ++ } ++ default: ++ return -EINVAL; ++ } ++ ++ if (ret < 0) ++ goto out; ++ ++ } ++ ++ /* Read the flags */ ++ if (encoding->flags & IW_ENCODE_DISABLED) { ++ /* Encoding disabled, ++ * authen = DOT11_AUTH_OS; ++ * invoke = 0; ++ * exunencrypt = 0; */ ++ } ++ if (encoding->flags & IW_ENCODE_OPEN) { ++ /* Encode but accept non-encoded packets. No auth */ ++ invoke = 1; ++ } ++ if (encoding->flags & IW_ENCODE_RESTRICTED) { ++ /* Refuse non-encoded packets. Auth */ ++ authen = DOT11_AUTH_BOTH; ++ invoke = 1; ++ exunencrypt = 1; ++ } ++ ++ /* do the change if requested */ ++ if (encoding->flags & IW_ENCODE_MODE) { ++ sm_drv_oid_set(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&invoke, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ } ++ ++ out: ++ return ret; ++} ++ ++ ++static int sm_drv_get_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ struct net_local *priv = netdev_priv(dev); ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, max_key_len; ++ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0; ++ int ret = 0; ++ ++ DEBUG(DBG_IOCTL, "GET ENCODEEXT\n"); ++ ++ /* first get the flags */ ++ ret = sm_drv_oid_get(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&invoke, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ if (ret < 0) ++ goto out; ++ ++ max_key_len = encoding->length - sizeof(*ext); ++ if (max_key_len < 0) ++ return -EINVAL; ++ ++ idx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if (idx) { ++ if (idx < 0 || idx > 3) ++ return -EINVAL; ++ } else { ++ ret = sm_drv_oid_get(dev, DOT11_OID_DEFKEYID, ++ (void *)&idx, sizeof(uint32_t)); ++ if (ret < 0) ++ goto out; ++ } ++ ++ encoding->flags = idx + 1; ++ memset(ext, 0, sizeof(*ext)); ++ ++ switch (authen) { ++ case DOT11_AUTH_BOTH: ++ case DOT11_AUTH_SK: ++ wrqu->encoding.flags |= IW_ENCODE_RESTRICTED; ++ case DOT11_AUTH_OS: ++ default: ++ wrqu->encoding.flags |= IW_ENCODE_OPEN; ++ break; ++ } ++ ++ down(&priv->wpa_sem); ++ wpa = priv->wpa; ++ up(&priv->wpa_sem); ++ ++ if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) { ++ /* No encryption */ ++ ext->alg = IW_ENCODE_ALG_NONE; ++ ext->key_len = 0; ++ wrqu->encoding.flags |= IW_ENCODE_DISABLED; ++ } else { ++ struct obj_key *key; ++ ++ ret = sm_drv_oid_get(dev, DOT11_OID_DEFKEYID + idx + 1, ++ (void *)&key, sizeof(struct obj_key)); ++ if (ret < 0) ++ goto out; ++ if (max_key_len < key->length) { ++ ret = -E2BIG; ++ goto out; ++ } ++ memcpy(ext->key, key->key, key->length); ++ ext->key_len = key->length; ++ ++ switch (key->type) { ++ case DOT11_PRIV_TKIP: ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ break; ++ case DOT11_PRIV_AES_CCMP: ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ break; ++ default: ++ case DOT11_PRIV_WEP: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ break; ++ } ++ wrqu->encoding.flags |= IW_ENCODE_ENABLED; ++ } ++ ++ out: ++ return ret; ++} + + /* Private handlers */ + +@@ -2473,10 +2902,10 @@ const iw_handler sm_drv_we_handler[] = { + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) sm_drv_set_genie, /* SIOCSIWGENIE*/ + (iw_handler) NULL, /* SIOCGIWGENIE */ +- (iw_handler) NULL, /* SIOCSIWAUTH */ +- (iw_handler) NULL, /* SIOCGIWAUTH */ +- (iw_handler) NULL, /* SIOCSIWENCODEEXT */ +- (iw_handler) NULL, /* SIOCGIWENCODEEXT */ ++ (iw_handler) sm_drv_set_auth, /* SIOCSIWAUTH */ ++ (iw_handler) sm_drv_get_auth, /* SIOCGIWAUTH */ ++ (iw_handler) sm_drv_set_encodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) sm_drv_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) sm_drv_set_pmk, /* SIOCSIWPMKSA */ + }; + diff --git a/patches/osso-wlan-1.3.10.patch b/patches/osso-wlan-1.3.10.patch new file mode 100644 index 0000000..3ed92d1 --- /dev/null +++ b/patches/osso-wlan-1.3.10.patch @@ -0,0 +1,185 @@ +diff -rup osso-wlan-1.3.10/common.h osso-wlan-1.3.10+wpa/common.h +--- osso-wlan-1.3.10/common.h 2007-12-20 07:20:35.000000000 +0100 ++++ osso-wlan-1.3.10+wpa/common.h 2009-02-23 14:03:24.000000000 +0100 +@@ -202,6 +202,7 @@ gboolean set_power_state(guint state, in + int get_encryption_info(void); + void remove_connect_timer(void); + int disassociate_eap(void); ++int using_supplicant(void); + int get_mode(void); + DBusHandlerResult wlancond_req_handler(DBusConnection *connection, + DBusMessage *message, void *user_data); +diff -rup osso-wlan-1.3.10/dbus-handler.c osso-wlan-1.3.10+wpa/dbus-handler.c +--- osso-wlan-1.3.10/dbus-handler.c 2007-12-04 12:20:31.000000000 +0100 ++++ osso-wlan-1.3.10+wpa/dbus-handler.c 2009-02-23 14:03:32.000000000 +0100 +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #ifdef USE_MCE_MODE + #include + #endif +@@ -73,6 +74,9 @@ static gboolean power_down_after_scan = + static gboolean scan_threshold_supported = FALSE; + static dbus_bool_t saved_inactivity = FALSE; + ++/* Indicates if we are using wpa_supplicant for the job */ ++static gboolean use_supplicant = FALSE; ++ + /* Timer IDs */ + static guint wlan_if_down_timer_id = 0; + static guint wlan_connect_timer_id = 0; +@@ -605,14 +609,18 @@ static gboolean wlan_connect_timer_cb(vo + { + wlan_connect_timer_id = 0; + +- if (get_wlan_state() == WLAN_INITIALIZED && !get_mic_status()) { +- DLOG_DEBUG("Association timeout"); +- set_wlan_state(WLAN_NOT_INITIALIZED, DISCONNECTED_SIGNAL, +- FORCE_YES); +- return FALSE; ++ if (get_wlan_state() == WLAN_INITIALIZED) { ++ if (use_supplicant) { ++ DLOG_DEBUG("wpa_supplicant should do its job now"); ++ } else if (!get_mic_status()) { ++ DLOG_DEBUG("Association timeout"); ++ ++ set_wlan_state(WLAN_NOT_INITIALIZED, DISCONNECTED_SIGNAL, ++ FORCE_YES); ++ } else { ++ DLOG_DEBUG("Association OK"); ++ } + } +- +- //DLOG_DEBUG("Association OK"); + + return FALSE; + } +@@ -1176,6 +1184,14 @@ static DBusHandlerResult settings_and_co + powersave = WLANCOND_SHORT_CAM; + } + ++ if (flags & WLANCOND_USE_SUPPLICANT) { ++ DLOG_DEBUG("Using wpa_supplicant"); ++ use_supplicant = TRUE; ++ encryption = WLANCOND_OPEN; // Don't handle it ++ } else { ++ use_supplicant = FALSE; ++ } ++ + if (power_level != WLANCOND_TX_POWER10 && + power_level != WLANCOND_TX_POWER100) { + DLOG_ERR("Invalid power level"); +@@ -2153,6 +2169,9 @@ int wpa_ie_push(unsigned char* ap_mac_ad + DBusMessage *msg; + DBusPendingCall *pending; + ++ if (use_supplicant) ++ return 0; ++ + if (wlan_status.wpa_ie.ie_valid == IE_NOT_VALID || + selected_ssid == NULL) { + DLOG_ERR("WPA IE / SSID (%s) not valid", selected_ssid); +@@ -2205,6 +2224,9 @@ int wpa_mic_failure_event(dbus_bool_t ke + DBusMessage *reply; + DBusError derr; + ++ if (use_supplicant) ++ return 0; ++ + msg = dbus_message_new_method_call( + EAP_SERVICE, + EAP_REQ_PATH, +@@ -2249,6 +2271,9 @@ int disassociate_eap(void) { + DBusMessage *reply; + DBusError derr; + ++ if (use_supplicant) ++ return 0; ++ + msg = dbus_message_new_method_call( + EAP_SERVICE, + EAP_REQ_PATH, +@@ -2280,6 +2305,11 @@ int disassociate_eap(void) { + return 0; + } + ++int using_supplicant(void) ++{ ++ return use_supplicant; ++} ++ + #ifdef USE_MCE_COVER + static DBusHandlerResult ignore_cover_request(DBusMessage *message, + DBusConnection *connection) +diff -rup osso-wlan-1.3.10/dbus-signal.c osso-wlan-1.3.10+wpa/dbus-signal.c +--- osso-wlan-1.3.10/dbus-signal.c 2008-04-09 12:53:28.000000000 +0200 ++++ osso-wlan-1.3.10+wpa/dbus-signal.c 2009-02-27 19:39:32.000000000 +0100 +@@ -274,7 +274,7 @@ static void handle_wap_event(struct scan + if (state != WLAN_CONNECTED) { + set_wlan_state(WLAN_NO_ADDRESS, NO_SIGNAL, FORCE_NO); + } +- } else { ++ } else if (!using_supplicant()) { + + /* Set_wlan_state puts IF down */ + set_wlan_state(WLAN_NOT_INITIALIZED, +@@ -488,7 +488,7 @@ static int handle_wpa_ie_assoc_event_bin + int ie_len; + int sock; + +- if (get_wpa_mode() == FALSE) ++ if (!get_wpa_mode() || using_supplicant()) + return 0; + + // event is MAC:IE, do minimal sanity checking +diff -rup osso-wlan-1.3.10/debian/changelog osso-wlan-1.3.10+wpa/debian/changelog +--- osso-wlan-1.3.10/debian/changelog 2008-04-09 12:54:37.000000000 +0200 ++++ osso-wlan-1.3.10+wpa/debian/changelog 2009-02-22 13:58:58.000000000 +0100 +@@ -1,3 +1,9 @@ ++osso-wlan (1.3.10+wpa) unstable; urgency=low ++ ++ * Added flag USE_SUPPLICANT (meaning "leave me alone") ++ ++ -- Javier Sun, 22 Feb 2009 13:58:22 +0100 ++ + osso-wlan (1.3.10) unstable; urgency=low + + * Fix build issues for SDK. Fixes: NB#83881 +diff -rup osso-wlan-1.3.10/Makefile osso-wlan-1.3.10+wpa/Makefile +--- osso-wlan-1.3.10/Makefile 2008-04-09 12:54:37.000000000 +0200 ++++ osso-wlan-1.3.10+wpa/Makefile 2009-02-27 19:40:17.000000000 +0100 +@@ -25,7 +25,7 @@ CFLAGS += -DVERSION=\"$(VERSION)\" -D_GN + + # Debug flags + #CFLAGS += -g -ggdb -DDEBUG -O0 -rdynamic +-CFLAGS += -DDEBUG ++#CFLAGS += -DDEBUG -DOSSOLOG_STDERR + CFLAGS += -DUSE_MCE_MODE -DACTIVITY_CHECK + + # Library flags +diff -rup osso-wlan-1.3.10/wpa.c osso-wlan-1.3.10+wpa/wpa.c +--- osso-wlan-1.3.10/wpa.c 2007-06-08 09:14:17.000000000 +0200 ++++ osso-wlan-1.3.10+wpa/wpa.c 2009-02-23 13:55:36.000000000 +0100 +@@ -188,6 +188,7 @@ static gboolean mic_failure_running_cb(v + + gboolean get_mic_status(void) + { ++ DLOG_DEBUG("get_mic_status timer=%d", mic_failure_running_timer_id); + return (mic_failure_running_timer_id != 0 ? TRUE:FALSE); + } + +@@ -198,6 +199,12 @@ gboolean get_mic_status(void) + */ + int handle_mic_failure(gboolean key_type) + { ++ DLOG_WARN("MIC failure"); ++ ++ if (using_supplicant()) { ++ DLOG_DEBUG("Using supplicant: ignoring MIC failure"); ++ return 0; ++ } + + if (mic_failure_timer_id != 0) { + diff --git a/patches/wpasupplicant-0.6.4.patch b/patches/wpasupplicant-0.6.4.patch new file mode 100644 index 0000000..97f4fdb --- /dev/null +++ b/patches/wpasupplicant-0.6.4.patch @@ -0,0 +1,324 @@ +diff -rup wpasupplicant-0.6.4.orig/debian/changelog wpasupplicant-0.6.4/debian/changelog +--- wpasupplicant-0.6.4.orig/debian/changelog 2009-03-02 14:03:10.000000000 +0100 ++++ wpasupplicant-0.6.4/debian/changelog 2009-02-20 12:31:12.000000000 +0100 +@@ -1,3 +1,9 @@ ++wpasupplicant (0.6.4-3+n810) unstable; urgency=low ++ ++ * Some hacks for cx3110x support. ++ ++ -- Reinhard Tartler Fri, 20 Feb 2009 12:30:44 +0100 ++ + wpasupplicant (0.6.4-3) unstable; urgency=low + + * Bugfix: "Missing -d in testing for a directory in init script". +diff -rup wpasupplicant-0.6.4.orig/debian/compat wpasupplicant-0.6.4/debian/compat +--- wpasupplicant-0.6.4.orig/debian/compat 2009-03-02 14:03:10.000000000 +0100 ++++ wpasupplicant-0.6.4/debian/compat 2009-02-16 20:50:34.000000000 +0100 +@@ -1 +1 @@ +-6 ++5 +diff -rup wpasupplicant-0.6.4.orig/debian/config/linux wpasupplicant-0.6.4/debian/config/linux +--- wpasupplicant-0.6.4.orig/debian/config/linux 2009-03-02 14:03:10.000000000 +0100 ++++ wpasupplicant-0.6.4/debian/config/linux 2009-02-22 14:11:17.000000000 +0100 +@@ -27,7 +27,7 @@ + #CONFIG_DRIVER_NDISWRAPPER=y + + # Driver interface for Atmel driver +-CONFIG_DRIVER_ATMEL=y ++#CONFIG_DRIVER_ATMEL=y + + # Driver interface for Broadcom driver + # XXX: Non-GPL header required +@@ -108,7 +108,7 @@ CONFIG_EAP_GTC=y + CONFIG_EAP_OTP=y + + # EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used) +-CONFIG_EAP_SIM=y ++#CONFIG_EAP_SIM=y + + # EAP-PSK (experimental; this is _not_ needed for WPA-PSK) + CONFIG_EAP_PSK=y +@@ -120,7 +120,7 @@ CONFIG_EAP_PAX=y + CONFIG_EAP_LEAP=y + + # EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used) +-CONFIG_EAP_AKA=y ++#CONFIG_EAP_AKA=y + + # EAP-SAKE + #CONFIG_EAP_SAKE=y +@@ -145,11 +145,11 @@ CONFIG_PKCS12=y + + # Smartcard support (i.e., private key on a smartcard), e.g., with openssl + # engine. +-CONFIG_SMARTCARD=y ++#CONFIG_SMARTCARD=y + + # PC/SC interface for smartcards (USIM, GSM SIM) + # Enable this if EAP-SIM or EAP-AKA is included +-CONFIG_PCSC=y ++#CONFIG_PCSC=y + + # Development testing + #CONFIG_EAPOL_TEST=y +@@ -251,7 +251,7 @@ CONFIG_PEERKEY=y + # This version is an experimental implementation based on IEEE 802.11w/D1.0 + # draft and is subject to change since the standard has not yet been finalized. + # Driver support is also needed for IEEE 802.11w. +-CONFIG_IEEE80211W=y ++#CONFIG_IEEE80211W=y + + # Select TLS implementation + # openssl = OpenSSL (default) +diff -rup wpasupplicant-0.6.4.orig/debian/control wpasupplicant-0.6.4/debian/control +--- wpasupplicant-0.6.4.orig/debian/control 2009-03-02 14:03:10.000000000 +0100 ++++ wpasupplicant-0.6.4/debian/control 2009-02-16 20:58:44.000000000 +0100 +@@ -1,21 +1,14 @@ + Source: wpasupplicant + Section: net + Priority: optional +-Maintainer: Debian/Ubuntu wpasupplicant Maintainers +-Uploaders: Kyle McMartin , Reinhard Tartler , Kel Modderman +-Build-Depends: debhelper (>= 6), ++Maintainer: javispedro ++Build-Depends: debhelper, + quilt, + libdbus-glib-1-dev, + libssl-dev, +- libpcsclite-dev, +- libreadline5-dev, +- libqt4-dev, ++ libreadline4-dev, + libdbus-1-dev, +- docbook, +- docbook-utils, + pkg-config, +- libpcap-dev [kfreebsd-i386 kfreebsd-amd64], +- libbsd [kfreebsd-i386 kfreebsd-amd64] + Standards-Version: 3.8.0 + Vcs-Svn: svn://svn.debian.org/pkg-wpa/wpasupplicant/trunk + Vcs-Browser: http://svn.debian.org/wsvn/pkg-wpa/wpasupplicant/trunk/ +@@ -23,19 +16,11 @@ Homepage: http://w1.fi/wpa_supplicant/ + + Package: wpasupplicant + Architecture: any +-Depends: ${shlibs:Depends}, lsb-base (>= 3.0-6), adduser ++Depends: ${shlibs:Depends}, lsb-base (>= 3.0-6) + Suggests: wpagui, libengine-pkcs11-openssl + Description: Client support for WPA and WPA2 (IEEE 802.11i) + WPA and WPA2 are methods for securing wireless networks, the former + using IEEE 802.1X, and the latter using IEEE 802.11i. This software + provides key negotiation with the WPA Authenticator, and controls + association with IEEE 802.11i networks. +- +-Package: wpagui +-Architecture: any +-Depends: ${shlibs:Depends}, wpasupplicant (= ${binary:Version}) +-Description: GUI for wpa_supplicant +- wpagui provides a Qt interface for choosing which configured network +- to connect to. It also provides a method for browsing 802.11 SSID scan +- results, an event history log of messages generated by wpa_supplicant, +- and a method to add or edit wpa_supplicant networks. ++ +diff -rup wpasupplicant-0.6.4.orig/debian/patches/series wpasupplicant-0.6.4/debian/patches/series +--- wpasupplicant-0.6.4.orig/debian/patches/series 2009-03-02 14:03:10.000000000 +0100 ++++ wpasupplicant-0.6.4/debian/patches/series 2009-02-16 20:59:36.000000000 +0100 +@@ -1,6 +1,3 @@ +-01_use_pkg-config_for_pcsc-lite_module.patch + 02_dbus_group_policy.patch +-03_dbus_service_activation_logfile.patch + 04_append_mmd_to_default_cflags.patch +-05_qmake_version_makefile.patch + 06_fix_segfault_32bit_compat_ioctls.patch +diff -rup wpasupplicant-0.6.4.orig/debian/rules wpasupplicant-0.6.4/debian/rules +--- wpasupplicant-0.6.4.orig/debian/rules 2009-03-02 14:03:10.000000000 +0100 ++++ wpasupplicant-0.6.4/debian/rules 2009-02-17 01:59:20.000000000 +0100 +@@ -1,12 +1,10 @@ + #!/usr/bin/make -f + + # Uncomment this to turn on verbose mode. +-#export DH_VERBOSE=1 ++export DH_VERBOSE=1 + + include /usr/share/quilt/quilt.make + +-WPAGUI = wpa_gui-qt4 +- + CFLAGS = -Wall -g + LDFLAGS = -Wl,--as-needed + +@@ -18,12 +16,7 @@ endif + + DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS) + +-ifeq ($(DEB_HOST_ARCH_OS),kfreebsd) +- CONFIG := debian/config/kfreebsd +-else +- CONFIG := debian/config/linux +-endif +- ++CONFIG := debian/config/linux + + build: build-stamp + build-stamp: $(QUILT_STAMPFN) +@@ -33,12 +26,6 @@ build-stamp: $(QUILT_STAMPFN) + cp -v $(CONFIG) wpa_supplicant/.config + CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" $(MAKE) -C wpa_supplicant all + +- # wpa_gui +- $(MAKE) -C wpa_supplicant $(WPAGUI) +- +- # manpages +- $(MAKE) -C wpa_supplicant/doc/docbook man +- + touch $@ + + clean: unpatch +@@ -46,12 +33,6 @@ clean: unpatch + + $(MAKE) -C wpa_supplicant clean + +- if [ -f wpa_supplicant/$(WPAGUI)/Makefile ]; then \ +- $(MAKE) -C wpa_supplicant/$(WPAGUI) distclean ; \ +- fi +- +- $(MAKE) -C wpa_supplicant/doc/docbook clean +- + dh_clean wpa_supplicant/.config build-stamp install-stamp + + install: build +@@ -61,15 +42,6 @@ install: build + dh_installdirs + dh_install + +- # wpa_gui +- dh_install --package=wpagui wpa_supplicant/$(WPAGUI)/wpa_gui usr/sbin/ +- +- # ifupdown +- install --mode=755 -D debian/ifupdown/ifupdown.sh \ +- debian/wpasupplicant/etc/wpa_supplicant/ifupdown.sh +- install --mode=755 -D debian/ifupdown/functions.sh \ +- debian/wpasupplicant/etc/wpa_supplicant/functions.sh +- + # wpa_action + install --mode=755 -D debian/ifupdown/wpa_action.sh \ + debian/wpasupplicant/sbin/wpa_action +@@ -84,6 +56,12 @@ install: build + mkdir -p debian/wpasupplicant/usr/share/doc/wpasupplicant + sed 's/^\([^#]\+=.*\|}\)/#\1/' < wpa_supplicant/wpa_supplicant.conf \ + > debian/wpasupplicant/usr/share/doc/wpasupplicant/README.wpa_supplicant.conf ++ ++ # Clean output a little ++ rm -rf debian/wpasupplicant/etc/network/if* ++ rm -rf debian/wpasupplicant/usr/share/doc ++ rm -rf debian/wpasupplicant/etc/init.d ++ + + # Build architecture-independent files here. + binary-indep: install +@@ -92,13 +70,6 @@ binary-indep: install + binary-arch: install + dh_testdir + dh_testroot +- dh_installchangelogs wpa_supplicant/ChangeLog +- dh_installdocs +- dh_installexamples +- dh_installlogrotate --package=wpasupplicant --name=wpa_action +- dh_installlogrotate --package=wpasupplicant --name=wpa_supplicant +- dh_installinit --package=wpasupplicant --name=wpa-ifupdown --no-start -- start 15 0 6 . +- dh_installman + dh_link + dh_strip + dh_compress +diff -rup wpasupplicant-0.6.4.orig/debian/wpasupplicant.links wpasupplicant-0.6.4/debian/wpasupplicant.links +--- wpasupplicant-0.6.4.orig/debian/wpasupplicant.links 2009-03-02 14:03:10.000000000 +0100 ++++ wpasupplicant-0.6.4/debian/wpasupplicant.links 2009-02-17 01:54:34.000000000 +0100 +@@ -1,5 +1 @@ +-etc/wpa_supplicant/ifupdown.sh etc/network/if-pre-up.d/wpasupplicant +-etc/wpa_supplicant/ifupdown.sh etc/network/if-up.d/wpasupplicant +-etc/wpa_supplicant/ifupdown.sh etc/network/if-down.d/wpasupplicant +-etc/wpa_supplicant/ifupdown.sh etc/network/if-post-down.d/wpasupplicant +-usr/share/doc/wpasupplicant/README.Debian usr/share/doc/wpasupplicant/README.modes ++ +diff -rup wpasupplicant-0.6.4.orig/debian/wpasupplicant.postinst wpasupplicant-0.6.4/debian/wpasupplicant.postinst +--- wpasupplicant-0.6.4.orig/debian/wpasupplicant.postinst 2009-03-02 14:03:10.000000000 +0100 ++++ wpasupplicant-0.6.4/debian/wpasupplicant.postinst 2009-02-16 21:09:26.000000000 +0100 +@@ -17,10 +17,7 @@ + + case "$1" in + configure) +- # Add the netdev group unless it's already there +- if ! getent group netdev >/dev/null; then +- addgroup --quiet --system netdev || true +- fi ++ + ;; + abort-upgrade|abort-deconfigure|abort-remove) + ;; +diff -rup wpasupplicant-0.6.4.orig/src/drivers/driver_wext.c wpasupplicant-0.6.4/src/drivers/driver_wext.c +--- wpasupplicant-0.6.4.orig/src/drivers/driver_wext.c 2008-08-10 19:33:12.000000000 +0200 ++++ wpasupplicant-0.6.4/src/drivers/driver_wext.c 2009-03-02 14:04:11.000000000 +0100 +@@ -628,6 +628,22 @@ static void wpa_driver_wext_event_wirele + os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); + custom += IW_EV_POINT_OFF; + } ++ ++ if (iwe->cmd == IWEVASSOCREQIE || ++ iwe->cmd == IWEVASSOCRESPIE) { ++ // Find and ignore bssid: put by the driver ++ while (iwe->u.data.length > 0 && *custom != ':') ++ { ++ custom++; ++ iwe->u.data.length--; ++ } ++ ++ if (iwe->u.data.length > 0) ++ { ++ custom++; ++ iwe->u.data.length--; ++ } ++ } + + switch (iwe->cmd) { + case SIOCGIWAP: +@@ -1221,7 +1237,6 @@ int wpa_driver_wext_scan(void *priv, con + struct wpa_driver_wext_data *drv = priv; + struct iwreq iwr; + int ret = 0, timeout; +- struct iw_scan_req req; + + if (ssid_len > IW_ESSID_MAX_SIZE) { + wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", +@@ -1233,14 +1248,13 @@ int wpa_driver_wext_scan(void *priv, con + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + + if (ssid && ssid_len) { +- os_memset(&req, 0, sizeof(req)); +- req.essid_len = ssid_len; +- req.bssid.sa_family = ARPHRD_ETHER; +- os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); +- os_memcpy(req.essid, ssid, ssid_len); +- iwr.u.data.pointer = (caddr_t) &req; +- iwr.u.data.length = sizeof(req); +- iwr.u.data.flags = IW_SCAN_THIS_ESSID; ++ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " ++ "seconds", ret, timeout); ++ iwr.u.essid.pointer = (caddr_t) ssid; ++ iwr.u.essid.length = ssid_len; ++ iwr.u.essid.flags = IW_SCAN_THIS_ESSID; ++ } else { ++ iwr.u.essid.flags = IW_SCAN_ALL_ESSID; + } + + if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { +diff -rup wpasupplicant-0.6.4.orig/wpa_supplicant/scan.c wpasupplicant-0.6.4/wpa_supplicant/scan.c +--- wpasupplicant-0.6.4.orig/wpa_supplicant/scan.c 2008-08-10 19:33:12.000000000 +0200 ++++ wpasupplicant-0.6.4/wpa_supplicant/scan.c 2009-02-20 13:25:51.000000000 +0100 +@@ -140,6 +140,7 @@ static void wpa_supplicant_scan(void *el + wpa_printf(MSG_DEBUG, "Trying to get current scan results " + "first without requesting a new scan to speed up " + "initial association"); ++ wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; + wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); + return; + } diff --git a/supp.c b/supp.c new file mode 100644 index 0000000..3877e46 --- /dev/null +++ b/supp.c @@ -0,0 +1,598 @@ +/** + @file supp.c + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "log.h" +#include "common.h" +#include "icd.h" +#include "dbus.h" +#include "dbus-helper.h" +#include "supp.h" + +/* Errors */ +#define WPAS_ERROR_INVALID_NETWORK \ + WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork" +#define WPAS_ERROR_INVALID_BSSID \ + WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID" + +#define WPAS_ERROR_INVALID_OPTS \ + WPAS_DBUS_INTERFACE ".InvalidOptions" +#define WPAS_ERROR_INVALID_IFACE \ + WPAS_DBUS_INTERFACE ".InvalidInterface" + +#define WPAS_ERROR_ADD_ERROR \ + WPAS_DBUS_INTERFACE ".AddError" +#define WPAS_ERROR_EXISTS_ERROR \ + WPAS_DBUS_INTERFACE ".ExistsError" +#define WPAS_ERROR_REMOVE_ERROR \ + WPAS_DBUS_INTERFACE ".RemoveError" + +#define WPAS_ERROR_SCAN_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".ScanError" +#define WPAS_ERROR_ADD_NETWORK_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError" +#define WPAS_ERROR_INTERNAL_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".InternalError" +#define WPAS_ERROR_REMOVE_NETWORK_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError" + +#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x" + +static pid_t supp_pid = 0; +static int supp_activation_tries = 0; + +static gchar* supp_iface = NULL; +static gchar* supp_iface_path = NULL; + +static gchar* supp_network_id = NULL; +static gchar* supp_config_path = NULL; + +static gboolean supp_configured = FALSE; // Unused right now + +/* Callback for supplicant events */ +static supp_cb_fn supp_cb = NULL; +static gpointer supp_cb_data = NULL; + +static void supp_configure(); + +void supp_set_callback(supp_cb_fn cb, gpointer user_data) +{ + supp_cb = cb; + supp_cb_data = user_data; +} + +static inline void supp_callback(int result, const char * message) +{ + if (supp_cb) supp_cb(result, message, supp_cb_data); +} + +static gboolean supp_set_interface_retry(gpointer data) +{ + DLOG_DEBUG(__func__); + + if (supp_pid && supp_iface) supp_set_interface(supp_iface); + return FALSE; +} + +static void add_iface_reply_cb(DBusPendingCall *pending, void *user_data) +{ + DBusMessage *reply; + DBusError error; + + DLOG_DEBUG("%s", __func__); + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + + if (dbus_set_error_from_message(&error, reply)) { + DLOG_WARN_L("Error in %s:%s", __func__, error.name); + + if (strcmp(DBUS_ERROR_SERVICE_UNKNOWN, error.name) == 0) + { + // Supplicant not (yet) active? Try later + DLOG_DEBUG("Still waiting for supplicant"); + supp_activation_tries++; + if (supp_activation_tries >= 3) { + supp_callback(-1, error.name); + } else { + g_timeout_add(1000, + supp_set_interface_retry, + NULL); + } + } else { + supp_callback(-1, error.name); + } + + dbus_error_free(&error); + } else if (reply) { + // Move on to next step + gchar* path; + if (!dbus_message_get_args( + reply, NULL, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) + { + supp_callback(-1, error.name); + goto iface_reply_error; + } + + supp_iface_path = g_strdup(path); + DLOG_DEBUG("Got interface path: %s", supp_iface_path); + if (supp_network_id && !supp_config_path) { + supp_set_network_id(supp_network_id); + } else if (supp_config_path && !supp_configured) { + supp_configure(); + } + } + +iface_reply_error: + if (reply) + dbus_message_unref(reply); + dbus_pending_call_unref(pending); +} + +void supp_unset_interface() +{ + // TODO + // mostly uneeded, since we're killing the supplicant instead + g_free(supp_iface_path); + supp_iface_path = NULL; + g_free(supp_iface); + supp_iface = NULL; +} + +void supp_set_interface(const char * iface) +{ + DBusMessage *msg; + DBusPendingCall *pending; + + DLOG_DEBUG("%s: %s", __func__, iface); + + if (supp_iface_path) { + supp_unset_interface(); + } + + if (iface != supp_iface) { + if (supp_iface) { + g_free(supp_iface); + } + + supp_iface = g_strdup(iface); + } + + msg = new_dbus_method_call( + WPAS_DBUS_SERVICE, + WPAS_DBUS_PATH, + WPAS_DBUS_INTERFACE, + "addInterface"); + + append_dbus_args( + msg, + DBUS_TYPE_STRING, &iface, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send_with_reply(get_dbus_connection(), + msg, &pending, -1)) + die("Out of memory"); + + if (!dbus_pending_call_set_notify(pending, + add_iface_reply_cb, NULL, NULL)) + die("Out of memory"); + + dbus_message_unref(msg); +} + +static void add_network_reply_cb(DBusPendingCall *pending, void *user_data) +{ + DBusMessage *reply; + DBusError error; + + DLOG_DEBUG("%s", __func__); + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + + if (dbus_set_error_from_message(&error, reply)) { + DLOG_WARN_L("Error in %s:%s", __func__, error.name); + + supp_callback(-1, error.name); + dbus_error_free(&error); + } else if (reply) { + // Move on to next step + gchar* path; + if (!dbus_message_get_args( + reply, NULL, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) + { + supp_callback(-1, error.name); + goto net_reply_error; + } + + supp_config_path = g_strdup(path); + DLOG_DEBUG("Got network path: %s", supp_iface_path); + if (supp_iface_path && !supp_configured) { + supp_configure(); + } + } + +net_reply_error: + if (reply) + dbus_message_unref(reply); + dbus_pending_call_unref(pending); +} + +void supp_unset_network_id() +{ + g_free(supp_config_path); + supp_config_path = NULL; + g_free(supp_network_id); + supp_network_id = NULL; + // TODO +} + +void supp_set_network_id(const char * network_id) +{ + DBusMessage *msg; + DBusPendingCall *pending; + + DLOG_DEBUG("%s: %s", __func__, network_id); + + if (supp_config_path) { + supp_unset_network_id(); + } + + if (network_id != supp_network_id) { + if (supp_network_id) { + g_free(supp_network_id); + } + + supp_network_id = g_strdup(network_id); + } + + if (!supp_iface_path) { + DLOG_DEBUG("Deferring network creation"); + return; + } + + msg = new_dbus_method_call( + WPAS_DBUS_SERVICE, + supp_iface_path, + WPAS_DBUS_IFACE_INTERFACE, + "addNetwork"); + + if (!dbus_connection_send_with_reply(get_dbus_connection(), + msg, &pending, -1)) + die("Out of memory"); + + if (!dbus_pending_call_set_notify(pending, + add_network_reply_cb, NULL, NULL)) + die("Out of memory"); + + dbus_message_unref(msg); +} + +static gchar * wpas_params[3] = { "/sbin/wpa_supplicant", "-u", NULL }; + +int supp_enable() +{ + DLOG_DEBUG("%s", __func__); + + supp_activation_tries = 0; + + GError* error; + GPid pid; + if (!g_spawn_async(NULL, wpas_params, NULL, + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &pid, &error)) { + DLOG_ERR("Couldn't spawn supplicant: %s", error->message); + return -1; + } + + supp_pid = pid; + + DLOG_INFO("Spawned %s , pid %d", wpas_params[0], pid); + + icd_watch_pid(supp_pid); + + return 0; +} + +void supp_disable(void) +{ + if (supp_pid) { + DLOG_INFO("Killing supplicant (pid %d)", supp_pid); + kill(supp_pid, SIGTERM); + } + + // Consider everything as deconfigured + g_free(supp_iface); + supp_iface = NULL; + g_free(supp_iface_path); + supp_iface_path = NULL; + g_free(supp_network_id); + supp_network_id = NULL; + g_free(supp_config_path); + supp_config_path = NULL; + + supp_configured = FALSE; +} + +int supp_is_active(void) +{ + return supp_pid ? TRUE : FALSE; +} + +void supp_handle_signal(gchar* old_state, gchar* new_state) +{ + DLOG_DEBUG("Supplicant StateChange %s -> %s", old_state, new_state); + + if (strcmp(new_state, "COMPLETED") == 0) + { + supp_callback(SUPP_STATUS_CONNECTED, new_state); + } else if (strcmp(new_state, "DISCONNECTED") == 0) { + supp_callback(SUPP_STATUS_DISCONNECTED, new_state); + } +} + +void supp_handle_killed(void) +{ + DLOG_DEBUG("%s", __func__); + + g_spawn_close_pid(supp_pid); + supp_pid = 0; + + supp_disable(); + + supp_callback(SUPP_STATUS_KILLED, NULL); +} + +static void free_settings_item(gpointer data, gpointer user_data) +{ + gconf_entry_free(data); +} + +static void enable_reply_cb(DBusPendingCall *pending, void *user_data) +{ + DBusMessage *reply; + DBusError error; + + DLOG_DEBUG("%s", __func__); + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + + if (dbus_set_error_from_message(&error, reply)) { + DLOG_WARN_L("Error in %s:%s", __func__, error.name); + + supp_callback(SUPP_STATUS_ERROR, error.name); + dbus_error_free(&error); + } + + if (reply) + dbus_message_unref(reply); + dbus_pending_call_unref(pending); +} + +static void supp_enable_network() +{ + DBusMessage* message; //The full mesage we are going to send. + DBusPendingCall *pending; + + message = dbus_message_new_method_call( + WPAS_DBUS_SERVICE, + supp_config_path, + WPAS_DBUS_IFACE_NETWORK, + WPAS_ENABLE_NETWORK_METHOD + ); + if (!message) { + DLOG_CRIT_L("Out of memory"); + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + return; + } + + // Send message + if (!dbus_connection_send_with_reply(get_dbus_connection(), + message, &pending, -1)) { + DLOG_CRIT_L("Out of memory"); + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + goto send_error; + } + + if (!dbus_pending_call_set_notify(pending, + enable_reply_cb, NULL, NULL)) { + DLOG_CRIT_L("Out of memory"); + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + } + + // Fall through +send_error: + dbus_message_unref(message); +} + +static void configure_reply_cb(DBusPendingCall *pending, void *user_data) +{ + DBusMessage *reply; + DBusError error; + + DLOG_DEBUG("%s", __func__); + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + + if (dbus_set_error_from_message(&error, reply)) { + DLOG_WARN_L("Error in %s:%s", __func__, error.name); + + supp_callback(-1, error.name); + dbus_error_free(&error); + } else if (reply) { + supp_enable_network(); + } + + if (reply) + dbus_message_unref(reply); + dbus_pending_call_unref(pending); +} + +static void supp_configure() +{ + // This is going to be long + DLOG_DEBUG("%s: %s", __func__, supp_network_id); + GConfClient *client = gconf_client_get_default(); + GError *error = NULL; + + DBusMessage* message; //The full mesage we are going to send. + DBusMessageIter iter, iter_dict; + DBusPendingCall *pending; + + if (!client) { + DLOG_ERR("Cannot get gconf client"); + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + return; + } + + gchar * settings_path = g_strconcat(ICD_GCONF_PATH, + "/", supp_network_id, NULL); + + GSList * settings = gconf_client_all_entries(client, + settings_path, &error); + if (error) { + DLOG_ERR("Could not get setting:%s, error:%s", settings_path, + error->message); + g_free(settings_path); + g_clear_error(&error); + g_object_unref(client); + supp_callback(-1, error->message); + return; + } + + message = dbus_message_new_method_call( + WPAS_DBUS_SERVICE, + supp_config_path, + WPAS_DBUS_IFACE_NETWORK, + WPAS_SET_NETWORK_METHOD + ); + if (!message) { + DLOG_CRIT_L("Out of memory"); + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + goto msg_init_error; + } + + dbus_message_iter_init_append(message, &iter); + if (dbus_dict_open_write(&iter, &iter_dict) != 0) { + DLOG_CRIT_L("Out of memory"); + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + goto dict_init_error; + } + + DLOG_DEBUG("Preparing to send %d settings", g_slist_length(settings)); + + GSList* i; + for (i = settings; i; i = g_slist_next(i)) { + GConfEntry* entry = i->data; + gchar * key = g_path_get_basename(gconf_entry_get_key(entry)); + GConfValue* value = gconf_entry_get_value(entry); + + if (g_ascii_strncasecmp(key, + WPA_GCONF_SETTING_PREFIX, + WPA_GCONF_SETTING_PREFIX_LEN)) { + g_free(key); + continue; + } + + // Skip prefix + key += WPA_GCONF_SETTING_PREFIX_LEN; + + switch (value->type) { + case GCONF_VALUE_STRING: + DLOG_DEBUG("Setting string %s = %s", + key, gconf_value_get_string(value)); + dbus_dict_append_string(&iter_dict, + key, gconf_value_get_string(value)); + break; + + case GCONF_VALUE_INT: + DLOG_DEBUG("Setting int32 %s = %d", + key, gconf_value_get_int(value)); + dbus_dict_append_int32(&iter_dict, + key, gconf_value_get_int(value)); + break; + default: + DLOG_DEBUG("Unknown setting type for %s", + key); + break; + } + + key -= WPA_GCONF_SETTING_PREFIX_LEN; + g_free(key); + } + + if (dbus_dict_close_write(&iter, &iter_dict) != 0) { + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + goto dict_close_error; + } + + // Send message + if (!dbus_connection_send_with_reply(get_dbus_connection(), + message, &pending, -1)) { + DLOG_CRIT_L("Out of memory"); + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + goto send_error; + } + + if (!dbus_pending_call_set_notify(pending, + configure_reply_cb, NULL, NULL)) { + DLOG_CRIT_L("Out of memory"); + supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR); + goto send_error; + } + + // Fall through +send_error: +dict_close_error: +dict_init_error: + dbus_message_unref(message); +msg_init_error: + g_free(settings_path); + + g_slist_foreach(settings, free_settings_item, NULL); + g_slist_free(settings); + + g_object_unref(client); +} + diff --git a/supp.h b/supp.h new file mode 100644 index 0000000..0314d57 --- /dev/null +++ b/supp.h @@ -0,0 +1,49 @@ +#ifndef _SUPP_H_ +#define _SUPP_H_ + +int supp_enable(); +void supp_disable(); + +#define WPAS_DBUS_OBJECT_PATH_MAX 150 + +#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant" +#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant" +#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant" + +#define WPAS_STATE_CHANGE_SIG "StateChange" + +#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces" +#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" + +#define WPAS_DBUS_NETWORKS_PART "Networks" +#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" + +#define WPAS_DBUS_BSSIDS_PART "BSSIDs" +#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID" + +#define WPAS_SET_NETWORK_METHOD "set" +#define WPAS_ENABLE_NETWORK_METHOD "enable" + +enum supp_status { + SUPP_STATUS_KILLED = -2, + SUPP_STATUS_ERROR = -1, + SUPP_STATUS_DISCONNECTED = 0, + SUPP_STATUS_CONNECTED +}; + +typedef void (*supp_cb_fn)(enum supp_status status, const char * data, + gpointer user_data); + +void supp_set_callback(supp_cb_fn cb, gpointer user_data); +void supp_set_interface(const char * iface); +void supp_set_network_id(const char * network_id); + +void supp_unset_interface(void); +void supp_unset_network_id(void); + +int supp_is_active(void); + +void supp_handle_signal(gchar* old_state, gchar* new_state); +void supp_handle_killed(void); + +#endif diff --git a/welcome b/welcome deleted file mode 100644 index e69de29..0000000 diff --git a/wlan.c b/wlan.c new file mode 100644 index 0000000..659e922 --- /dev/null +++ b/wlan.c @@ -0,0 +1,339 @@ +/** + @file wlan.c + + Copyright (C) 2004 Nokia Corporation. All rights reserved. + + Copyright (C) 2009 Javier S. Pedro + + @author Janne Ylalehto + @author Johan Hedberg + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include +#include + +#include +#include +#include + +#include "common.h" +#include "dbus.h" +#include "dbus-helper.h" +#include "wlan.h" +#include "log.h" + +/* -- SCANNING -- */ + +static wlan_found_ap found_ap_cb = NULL; + +int wlan_scan(const char * ssid, wlan_found_ap new_found_ap_cb) +{ + DBusMessage *msg, *reply; + DBusError error; + + DLOG_DEBUG("%s: %s (active)", __func__, ssid); + + dbus_error_init(&error); + + found_ap_cb = new_found_ap_cb; + + msg = new_dbus_method_call( + WLANCOND_SERVICE, + WLANCOND_REQ_PATH, + WLANCOND_REQ_INTERFACE, + WLANCOND_SCAN_REQ); + + gint32 power_level = WLANCOND_TX_POWER100; + guint32 flags = 0; + + append_dbus_args( + msg, + DBUS_TYPE_INT32, &power_level, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ssid, strlen(ssid) + 1, + DBUS_TYPE_UINT32, &flags, + + DBUS_TYPE_INVALID); + + reply = dbus_connection_send_with_reply_and_block(get_dbus_connection(), + msg, -1, &error); + + dbus_message_unref(msg); + + if (reply) { + DLOG_DEBUG("Scan reply OK"); + dbus_message_unref(reply); + + return 0; + } else if (dbus_error_is_set(&error)) { + DLOG_INFO("Scan pending call result:%s", error.name); + dbus_error_free(&error); + found_ap_cb = NULL; + return -1; + } else { + DLOG_WARN("Scan without reply"); + found_ap_cb = NULL; + return -1; + } +} + +gboolean wlan_is_scanning() +{ + return found_ap_cb ? TRUE : FALSE; +} + +void wlan_notify_ap(const char *ssid, const char *bssid, + int rssi, unsigned int channel, unsigned int cap_bits) +{ + if (found_ap_cb) + found_ap_cb(SEARCH_CONTINUE, ssid, bssid, rssi / 2 - 110); +} + +void wlan_notify_end_of_search() +{ + wlan_found_ap prev_found_ap_cb = found_ap_cb; + found_ap_cb = NULL; + + // A new search may be started right after calling this callback + + if (prev_found_ap_cb) + prev_found_ap_cb(SEARCH_FINISHED, NULL, NULL, 0); +} + +/* - CONNECTING - */ + +static wlan_connected connected_cb; + +static void connect_reply_cb(DBusPendingCall *pending, void *user_data) +{ + DBusMessage *reply; + DBusError error; + + DLOG_DEBUG("Connect reply callback"); + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + + if (dbus_set_error_from_message(&error, reply)) { + + DLOG_DEBUG("Connect pending call result:%s", error.name); + + connected_cb(-1, error.name); + dbus_error_free(&error); + } else if (reply) { + connected_cb(0, NULL); + } + + if (reply) + dbus_message_unref(reply); + dbus_pending_call_unref(pending); +} + +void wlan_connect(const char * ssid, wlan_connected _connected_cb) +{ + DBusMessage *msg; + DBusPendingCall *pending; + + DLOG_DEBUG("%s: %s", __func__, ssid); + + connected_cb = _connected_cb; + + msg = new_dbus_method_call( + WLANCOND_SERVICE, + WLANCOND_REQ_PATH, + WLANCOND_REQ_INTERFACE, + WLANCOND_SETTINGS_AND_CONNECT_REQ); + + guint32 dummy = 0; + guint32 *dummyP = &dummy; + + gint32 power_level, mode, encryption, default_key; + guint32 adhoc_channel, flags; + + power_level = WLANCOND_TX_POWER100; + mode = WLANCOND_INFRA; + encryption = 0; + default_key = 0; + adhoc_channel = 0; + flags = WLANCOND_USE_SUPPLICANT; + + append_dbus_args( + msg, + DBUS_TYPE_INT32, &power_level, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ssid, strlen(ssid), + DBUS_TYPE_INT32, &mode, + DBUS_TYPE_INT32, &encryption, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0, + DBUS_TYPE_INT32, &default_key, + DBUS_TYPE_UINT32, &adhoc_channel, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send_with_reply(get_dbus_connection(), + msg, &pending, -1)) + die("Out of memory"); + + if (!dbus_pending_call_set_notify(pending, connect_reply_cb, NULL, NULL)) + die("Out of memory"); + + dbus_message_unref(msg); +} + +static void disconnect_reply_cb(DBusPendingCall *pending, void *user_data) +{ + DBusMessage *reply; + DBusError error; + + DLOG_DEBUG("Disconnect reply callback"); + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + + if (dbus_set_error_from_message(&error, reply)) { + + DLOG_DEBUG("Disconnect pending call result:%s", error.name); + + dbus_error_free(&error); + } + + // No need to notify, wpa_supplicant will signal that for us + + if (reply) + dbus_message_unref(reply); + dbus_pending_call_unref(pending); +} + +void wlan_disconnect() +{ + DBusMessage *msg; + DBusPendingCall *pending; + + DLOG_DEBUG("%s", __func__); + + msg = new_dbus_method_call( + WLANCOND_SERVICE, + WLANCOND_REQ_PATH, + WLANCOND_REQ_INTERFACE, + WLANCOND_DISCONNECT_REQ); + + if (!dbus_connection_send_with_reply(get_dbus_connection(), + msg, &pending, -1)) + die("Out of memory"); + + if (!dbus_pending_call_set_notify(pending, disconnect_reply_cb, NULL, NULL)) + die("Out of memory"); + + dbus_message_unref(msg); +} + +/* -- STATUS -- */ + +static wlan_status_reply status_cb; + +static void status_reply_cb(DBusPendingCall *pending, void *user_data) +{ + DBusMessage *reply; + DBusError error; + + DLOG_DEBUG("%s", __func__); + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + + if (dbus_set_error_from_message(&error, reply)) { + + DLOG_DEBUG("%s error: %s", __func__, error.name); + goto dbus_error; + } else if (reply) { + char *essid, *bssid, *ifname; + int essid_len, bssid_len; + unsigned long sens, channel, capability, security; + + if (!dbus_message_get_args( + reply, &error, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &essid, &essid_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &bssid, &bssid_len, + DBUS_TYPE_UINT32, &sens, + DBUS_TYPE_UINT32, &channel, + DBUS_TYPE_UINT32, &capability, + DBUS_TYPE_UINT32, &security, + DBUS_TYPE_STRING, &ifname, + DBUS_TYPE_INVALID)) + { + DLOG_DEBUG("%s parse reply error: %s", __func__, + error.name); + goto dbus_error; + } + + status_cb(0, essid, essid_len, bssid, bssid_len, + sens, channel, capability, security, + ifname); + } + + if (reply) + dbus_message_unref(reply); + dbus_pending_call_unref(pending); + + return; +dbus_error: + status_cb(-1, NULL, 0, NULL, 0, + 0, 0, 0, 0, + error.name); + dbus_error_free(&error); + + if (reply) + dbus_message_unref(reply); + dbus_pending_call_unref(pending); +} + +void wlan_get_status(wlan_status_reply reply_cb) +{ + DBusMessage *msg; + DBusPendingCall *pending; + + DLOG_DEBUG("%s", __func__); + + status_cb = reply_cb; + + msg = new_dbus_method_call( + WLANCOND_SERVICE, + WLANCOND_REQ_PATH, + WLANCOND_REQ_INTERFACE, + WLANCOND_STATUS_REQ); + + if (!dbus_connection_send_with_reply(get_dbus_connection(), + msg, &pending, -1)) + die("Out of memory"); + + if (!dbus_pending_call_set_notify(pending, status_reply_cb, NULL, NULL)) + die("Out of memory"); + + dbus_message_unref(msg); +} + diff --git a/wlan.h b/wlan.h new file mode 100644 index 0000000..b3a29f3 --- /dev/null +++ b/wlan.h @@ -0,0 +1,52 @@ +/** + @file wlan.h + + Copyright (C) 2009 Javier S. Pedro + + @author Javier S. Pedro + + This file is part of libicd-network-wpa. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef _WLAN_H_ +#define _WLAN_H_ + +typedef void (*wlan_found_ap)(int status, + const char * ssid, const char * ap, int dB); +int wlan_scan(const char * ssid, wlan_found_ap found_ap_cb); + +gboolean wlan_is_scanning(); +void wlan_notify_ap(const char *ssid, const char *bssid, + int rssi, unsigned int channel, unsigned int cap_bits); +void wlan_notify_end_of_search(); + + +typedef void (*wlan_connected)(int status, const char *error); +void wlan_connect(const char *ssid, wlan_connected connected_cb); + +void wlan_disconnect(); + +typedef void (*wlan_status_reply)(int status, + const char * essid, int essid_len, + const char * bssid, int bssid_len, + int qual, int channel, unsigned long security, unsigned long capability, + const char * data); +void wlan_get_status(wlan_status_reply reply_cb); + + +#endif