[pkg-wpa-devel] r1324 - in /wpasupplicant/branches/upstream/current: src/ src/common/ src/crypto/ src/drivers/ src/eap_common/ src/eap_peer/ src/eap_server/ src/eapol_supp/ src/hlr_auc_gw/ src/l2_packet/ src/radius/ src/rsn_supp/ src/tls/ src/utils/ src/wps/ wpa_supplicant/ wpa_supplicant/doc/docbook/ wpa_supplicant/tests/ wpa_supplicant/wpa_gui-qt4/
kelmo-guest at users.alioth.debian.org
kelmo-guest at users.alioth.debian.org
Sun Feb 15 19:38:57 UTC 2009
Author: kelmo-guest
Date: Sun Feb 15 19:38:55 2009
New Revision: 1324
URL: http://svn.debian.org/wsvn/?sc=1&rev=1324
Log:
[svn-upgrade] Integrating new upstream version, wpasupplicant (0.6.8)
Added:
wpasupplicant/branches/upstream/current/src/wps/httpread.c
wpasupplicant/branches/upstream/current/src/wps/httpread.h
wpasupplicant/branches/upstream/current/src/wps/wps_upnp.c
wpasupplicant/branches/upstream/current/src/wps/wps_upnp.h
wpasupplicant/branches/upstream/current/src/wps/wps_upnp_event.c
wpasupplicant/branches/upstream/current/src/wps/wps_upnp_i.h
wpasupplicant/branches/upstream/current/src/wps/wps_upnp_ssdp.c
wpasupplicant/branches/upstream/current/src/wps/wps_upnp_web.c
Modified:
wpasupplicant/branches/upstream/current/src/Makefile
wpasupplicant/branches/upstream/current/src/common/Makefile
wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c
wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h
wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h
wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h
wpasupplicant/branches/upstream/current/src/common/privsep_commands.h
wpasupplicant/branches/upstream/current/src/common/version.h
wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.c
wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h
wpasupplicant/branches/upstream/current/src/crypto/Makefile
wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c
wpasupplicant/branches/upstream/current/src/crypto/crypto_gnutls.c
wpasupplicant/branches/upstream/current/src/crypto/crypto_openssl.c
wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c
wpasupplicant/branches/upstream/current/src/drivers/Makefile
wpasupplicant/branches/upstream/current/src/drivers/driver_broadcom.c
wpasupplicant/branches/upstream/current/src/drivers/driver_bsd.c
wpasupplicant/branches/upstream/current/src/drivers/driver_madwifi.c
wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c
wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c
wpasupplicant/branches/upstream/current/src/drivers/driver_roboswitch.c
wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c
wpasupplicant/branches/upstream/current/src/eap_common/Makefile
wpasupplicant/branches/upstream/current/src/eap_peer/Makefile
wpasupplicant/branches/upstream/current/src/eap_peer/eap.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h
wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c
wpasupplicant/branches/upstream/current/src/eap_server/Makefile
wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c
wpasupplicant/branches/upstream/current/src/eapol_supp/Makefile
wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c
wpasupplicant/branches/upstream/current/src/hlr_auc_gw/Makefile
wpasupplicant/branches/upstream/current/src/hlr_auc_gw/hlr_auc_gw.milenage_db
wpasupplicant/branches/upstream/current/src/l2_packet/Makefile
wpasupplicant/branches/upstream/current/src/radius/Makefile
wpasupplicant/branches/upstream/current/src/radius/radius.c
wpasupplicant/branches/upstream/current/src/radius/radius.h
wpasupplicant/branches/upstream/current/src/radius/radius_client.c
wpasupplicant/branches/upstream/current/src/radius/radius_client.h
wpasupplicant/branches/upstream/current/src/rsn_supp/Makefile
wpasupplicant/branches/upstream/current/src/tls/Makefile
wpasupplicant/branches/upstream/current/src/utils/Makefile
wpasupplicant/branches/upstream/current/src/utils/os_unix.c
wpasupplicant/branches/upstream/current/src/utils/wpabuf.c
wpasupplicant/branches/upstream/current/src/utils/wpabuf.h
wpasupplicant/branches/upstream/current/src/wps/Makefile
wpasupplicant/branches/upstream/current/src/wps/wps.c
wpasupplicant/branches/upstream/current/src/wps/wps.h
wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c
wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c
wpasupplicant/branches/upstream/current/src/wps/wps_common.c
wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c
wpasupplicant/branches/upstream/current/src/wps/wps_i.h
wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c
wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
wpasupplicant/branches/upstream/current/wpa_supplicant/README
wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS
wpasupplicant/branches/upstream/current/wpa_supplicant/config.h
wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c
wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c
wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c
wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.h
wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c
wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
wpasupplicant/branches/upstream/current/wpa_supplicant/nmake.mak
wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c
wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_sha256.c
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/main.cpp
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_priv.c
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h
wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c
wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h
Modified: wpasupplicant/branches/upstream/current/src/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/Makefile Sun Feb 15 19:38:55 2009
@@ -6,3 +6,6 @@
clean:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
rm -f *~
+
+install:
+ for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done
Modified: wpasupplicant/branches/upstream/current/src/common/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/common/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c Sun Feb 15 19:38:55 2009
@@ -116,6 +116,14 @@
}
+/**
+ * ieee802_11_parse_elems - Parse information elements in management frames
+ * @start: Pointer to the start of IEs
+ * @len: Length of IE buffer in octets
+ * @elems: Data structure for parsed elements
+ * @show_errors: Whether to show parsing errors in debug log
+ * Returns: Parsing result
+ */
ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
struct ieee802_11_elems *elems,
int show_errors)
@@ -211,6 +219,10 @@
elems->ftie = pos;
elems->ftie_len = elen;
break;
+ case WLAN_EID_TIMEOUT_INTERVAL:
+ elems->timeout_int = pos;
+ elems->timeout_int_len = elen;
+ break;
case WLAN_EID_HT_CAP:
elems->ht_capabilities = pos;
elems->ht_capabilities_len = elen;
@@ -218,10 +230,6 @@
case WLAN_EID_HT_OPERATION:
elems->ht_operation = pos;
elems->ht_operation_len = elen;
- break;
- case WLAN_EID_ASSOC_COMEBACK_TIME:
- elems->assoc_comeback = pos;
- elems->assoc_comeback_len = elen;
break;
default:
unknown++;
Modified: wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h Sun Feb 15 19:38:55 2009
@@ -55,12 +55,12 @@
u8 mdie_len;
u8 *ftie;
u8 ftie_len;
+ u8 *timeout_int;
+ u8 timeout_int_len;
u8 *ht_capabilities;
u8 ht_capabilities_len;
u8 *ht_operation;
u8 ht_operation_len;
- u8 *assoc_comeback;
- u8 assoc_comeback_len;
u8 *vendor_ht_cap;
u8 vendor_ht_cap_len;
};
Modified: wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h Sun Feb 15 19:38:55 2009
@@ -203,7 +203,6 @@
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
-#define WLAN_EID_ASSOC_COMEBACK_TIME 77
#define WLAN_EID_VENDOR_SPECIFIC 221
@@ -222,6 +221,11 @@
#define WLAN_SA_QUERY_RESPONSE 1
#define WLAN_SA_QUERY_TR_ID_LEN 16
+
+/* Timeout Interval Type */
+#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
+#define WLAN_TIMEOUT_KEY_LIFETIME 2
+#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
#ifdef _MSC_VER
Modified: wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h Sun Feb 15 19:38:55 2009
@@ -47,7 +47,7 @@
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
* %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
- * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET.
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -84,7 +84,7 @@
* %NL80222_CMD_NEW_BEACON message)
* @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
* using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
- * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
+ * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
* @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
* parameters are like for %NL80211_CMD_SET_BEACON.
* @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
@@ -113,6 +113,8 @@
* @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
* %NL80211_ATTR_IFINDEX.
*
+ * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
+ * regulatory domain.
* @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
* after being queried by the kernel. CRDA replies by sending a regulatory
* domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
@@ -133,6 +135,21 @@
* @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
* interface identified by %NL80211_ATTR_IFINDEX
*
+ * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
+ * interface is identified with %NL80211_ATTR_IFINDEX and the management
+ * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
+ * added to the end of the specified management frame is specified with
+ * %NL80211_ATTR_IE. If the command succeeds, the requested data will be
+ * added to all specified management frames generated by
+ * kernel/firmware/driver.
+ *
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
+ * NL80211_CMD_GET_SCAN and on the "scan" multicast group)
+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
+ * partial scan results may be available
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -178,6 +195,15 @@
NL80211_CMD_GET_MESH_PARAMS,
NL80211_CMD_SET_MESH_PARAMS,
+ NL80211_CMD_SET_MGMT_EXTRA_IE,
+
+ NL80211_CMD_GET_REG,
+
+ NL80211_CMD_GET_SCAN,
+ NL80211_CMD_TRIGGER_SCAN,
+ NL80211_CMD_NEW_SCAN_RESULTS,
+ NL80211_CMD_SCAN_ABORTED,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -190,6 +216,7 @@
* here
*/
#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
+#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
/**
* enum nl80211_attrs - nl80211 netlink attributes
@@ -284,6 +311,24 @@
* supported interface types, each a flag attribute with the number
* of the interface mode.
*
+ * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE.
+ *
+ * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE).
+ *
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ * a single scan request, a wiphy attribute.
+ *
+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ * scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the
+ * scan result list changes (BSS expired or added) so that applications
+ * can verify that they got a single, consistent snapshot (when all dump
+ * messages carried the same generation number)
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -348,6 +393,16 @@
NL80211_ATTR_KEY_DEFAULT_MGMT,
+ NL80211_ATTR_MGMT_SUBTYPE,
+ NL80211_ATTR_IE,
+
+ NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+ NL80211_ATTR_SCAN_FREQUENCIES,
+ NL80211_ATTR_SCAN_SSIDS,
+ NL80211_ATTR_SCAN_GENERATION,
+ NL80211_ATTR_BSS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -362,7 +417,9 @@
#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
-#define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET
+#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
+#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
+#define NL80211_ATTR_IE NL80211_ATTR_IE
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_REG_RULES 32
@@ -815,4 +872,38 @@
NL80211_CHAN_HT40MINUS,
NL80211_CHAN_HT40PLUS
};
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ * raw information elements from the probe response/beacon (bin)
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ * in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ * in unspecified units, scaled to 0..100 (u8)
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+ __NL80211_BSS_INVALID,
+ NL80211_BSS_BSSID,
+ NL80211_BSS_FREQUENCY,
+ NL80211_BSS_TSF,
+ NL80211_BSS_BEACON_INTERVAL,
+ NL80211_BSS_CAPABILITY,
+ NL80211_BSS_INFORMATION_ELEMENTS,
+ NL80211_BSS_SIGNAL_MBM,
+ NL80211_BSS_SIGNAL_UNSPEC,
+
+ /* keep last */
+ __NL80211_BSS_AFTER_LAST,
+ NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
#endif /* __LINUX_NL80211_H */
Modified: wpasupplicant/branches/upstream/current/src/common/privsep_commands.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/privsep_commands.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/privsep_commands.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/privsep_commands.h Sun Feb 15 19:38:55 2009
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - privilege separation commands
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,6 +31,7 @@
PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
PRIVSEP_CMD_L2_SEND,
PRIVSEP_CMD_SET_MODE,
+ PRIVSEP_CMD_SET_COUNTRY,
};
struct privsep_cmd_associate
@@ -71,6 +72,7 @@
PRIVSEP_EVENT_STKSTART,
PRIVSEP_EVENT_FT_RESPONSE,
PRIVSEP_EVENT_RX_EAPOL,
+ PRIVSEP_EVENT_STA_RX,
};
#endif /* PRIVSEP_COMMANDS_H */
Modified: wpasupplicant/branches/upstream/current/src/common/version.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/version.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/version.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/version.h Sun Feb 15 19:38:55 2009
@@ -1,6 +1,6 @@
#ifndef VERSION_H
#define VERSION_H
-#define VERSION_STR "0.6.7"
+#define VERSION_STR "0.6.8"
#endif /* VERSION_H */
Modified: wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.c (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.c Sun Feb 15 19:38:55 2009
@@ -64,6 +64,7 @@
static int counter = 0;
int ret;
size_t res;
+ int tries = 0;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
@@ -77,15 +78,28 @@
}
ctrl->local.sun_family = AF_UNIX;
+ counter++;
+try_again:
ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
- "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
+ "/tmp/wpa_ctrl_%d-%d", getpid(), counter);
if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
+ tries++;
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
+ if (errno == EADDRINUSE && tries < 2) {
+ /*
+ * getpid() returns unique identifier for this instance
+ * of wpa_ctrl, so the existing socket file must have
+ * been left by unclean termination of an earlier run.
+ * Remove the file and try again.
+ */
+ unlink(ctrl->local.sun_path);
+ goto try_again;
+ }
close(ctrl->s);
os_free(ctrl);
return NULL;
Modified: wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h Sun Feb 15 19:38:55 2009
@@ -66,10 +66,14 @@
#define WPS_EVENT_FAIL "WPS-FAIL "
/** WPS registration completed successfully */
#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
+/** WPS enrollment attempt timed out and was terminated */
+#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
+#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
+#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
/* wpa_supplicant/hostapd control interface access */
Modified: wpasupplicant/branches/upstream/current/src/crypto/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c Sun Feb 15 19:38:55 2009
@@ -86,6 +86,8 @@
#endif /* CONFIG_NO_AES_WRAP */
+#ifndef CONFIG_NO_AES_UNWRAP
+
/**
* aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* @kek: Key encryption key (KEK)
@@ -145,6 +147,8 @@
return 0;
}
+#endif /* CONFIG_NO_AES_UNWRAP */
+
#define BLOCK_SIZE 16
Modified: wpasupplicant/branches/upstream/current/src/crypto/crypto_gnutls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/crypto_gnutls.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto_gnutls.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto_gnutls.c Sun Feb 15 19:38:55 2009
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for libgcrypt
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -163,3 +163,151 @@
gcry_cipher_close(hd);
}
#endif /* EAP_TLS_FUNCS */
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+ const u8 *power, size_t power_len,
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len)
+{
+ gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL,
+ bn_result = NULL;
+ int ret = -1;
+
+ if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) !=
+ GPG_ERR_NO_ERROR ||
+ gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) !=
+ GPG_ERR_NO_ERROR ||
+ gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len,
+ NULL) != GPG_ERR_NO_ERROR)
+ goto error;
+ bn_result = gcry_mpi_new(modulus_len * 8);
+
+ gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus);
+
+ if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len,
+ bn_result) != GPG_ERR_NO_ERROR)
+ goto error;
+
+ ret = 0;
+
+error:
+ gcry_mpi_release(bn_base);
+ gcry_mpi_release(bn_exp);
+ gcry_mpi_release(bn_modulus);
+ gcry_mpi_release(bn_result);
+ return ret;
+}
+
+
+struct crypto_cipher {
+ gcry_cipher_hd_t enc;
+ gcry_cipher_hd_t dec;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+ gcry_error_t res;
+ enum gcry_cipher_algos a;
+ int ivlen;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ a = GCRY_CIPHER_ARCFOUR;
+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM,
+ 0);
+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0);
+ break;
+ case CRYPTO_CIPHER_ALG_AES:
+ if (key_len == 24)
+ a = GCRY_CIPHER_AES192;
+ else if (key_len == 32)
+ a = GCRY_CIPHER_AES256;
+ else
+ a = GCRY_CIPHER_AES;
+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ a = GCRY_CIPHER_3DES;
+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+ break;
+ case CRYPTO_CIPHER_ALG_DES:
+ a = GCRY_CIPHER_DES;
+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+ break;
+ case CRYPTO_CIPHER_ALG_RC2:
+ if (key_len == 5)
+ a = GCRY_CIPHER_RFC2268_40;
+ else
+ a = GCRY_CIPHER_RFC2268_128;
+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (res != GPG_ERR_NO_ERROR) {
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR ||
+ gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) {
+ gcry_cipher_close(ctx->enc);
+ gcry_cipher_close(ctx->dec);
+ os_free(ctx);
+ return NULL;
+ }
+
+ ivlen = gcry_cipher_get_algo_blklen(a);
+ if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR ||
+ gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) {
+ gcry_cipher_close(ctx->enc);
+ gcry_cipher_close(ctx->dec);
+ os_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) !=
+ GPG_ERR_NO_ERROR)
+ return -1;
+ return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) !=
+ GPG_ERR_NO_ERROR)
+ return -1;
+ return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ gcry_cipher_close(ctx->enc);
+ gcry_cipher_close(ctx->dec);
+ os_free(ctx);
+}
Modified: wpasupplicant/branches/upstream/current/src/crypto/crypto_openssl.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/crypto_openssl.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto_openssl.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto_openssl.c Sun Feb 15 19:38:55 2009
@@ -283,6 +283,7 @@
cipher = EVP_aes_256_cbc();
break;
default:
+ os_free(ctx);
return NULL;
}
break;
@@ -301,6 +302,7 @@
break;
#endif /* OPENSSL_NO_RC2 */
default:
+ os_free(ctx);
return NULL;
}
Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c Sun Feb 15 19:38:55 2009
@@ -254,8 +254,9 @@
conn->pull_buf = conn->pull_buf_offset = NULL;
conn->pull_buf_len = 0;
} else {
- wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in pull_buf",
- __func__, end - conn->pull_buf_offset);
+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
+ __func__,
+ (unsigned long) (end - conn->pull_buf_offset));
}
return len;
}
@@ -943,8 +944,9 @@
if (in_data && in_len) {
if (conn->pull_buf) {
- wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
- "pull_buf", __func__, conn->pull_buf_len);
+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+ "pull_buf", __func__,
+ (unsigned long) conn->pull_buf_len);
os_free(conn->pull_buf);
}
conn->pull_buf = os_malloc(in_len);
@@ -1058,6 +1060,14 @@
return -1;
if (conn->push_buf_len < out_len)
out_len = conn->push_buf_len;
+ else if (conn->push_buf_len > out_len) {
+ wpa_printf(MSG_INFO, "GnuTLS: Not enough buffer space for "
+ "encrypted message (in_len=%lu push_buf_len=%lu "
+ "out_len=%lu",
+ (unsigned long) in_len,
+ (unsigned long) conn->push_buf_len,
+ (unsigned long) out_len);
+ }
os_memcpy(out_data, conn->push_buf, out_len);
os_free(conn->push_buf);
conn->push_buf = NULL;
@@ -1073,8 +1083,9 @@
ssize_t res;
if (conn->pull_buf) {
- wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
- "pull_buf", __func__, conn->pull_buf_len);
+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+ "pull_buf", __func__,
+ (unsigned long) conn->pull_buf_len);
os_free(conn->pull_buf);
}
conn->pull_buf = os_malloc(in_len);
@@ -1132,7 +1143,7 @@
if (res < 0) {
wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
- "(%s)", __func__, res,
+ "(%s)", __func__, (int) res,
gnutls_strerror(res));
}
return res;
@@ -1142,7 +1153,7 @@
res = gnutls_record_recv(conn->session, out_data, out_len);
if (res < 0) {
wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
- "(%s)", __func__, res, gnutls_strerror(res));
+ "(%s)", __func__, (int) res, gnutls_strerror(res));
}
return res;
Modified: wpasupplicant/branches/upstream/current/src/drivers/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_broadcom.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_broadcom.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_broadcom.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_broadcom.c Sun Feb 15 19:38:55 2009
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant - driver interaction with Broadcom wl.o driver
+ * WPA Supplicant - driver interaction with old Broadcom wl.o driver
* Copyright (c) 2004, Nikki Chumkov <nikki at gattaca.ru>
* Copyright (c) 2004, Jouni Malinen <j at w1.fi>
*
@@ -11,6 +11,10 @@
* license.
*
* See README and COPYING for more details.
+ *
+ * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+ * Linux wireless extensions and does not need (or even work) with this old
+ * driver wrapper. Use driver_wext.c with that driver.
*/
#include "includes.h"
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_bsd.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_bsd.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_bsd.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_bsd.c Sun Feb 15 19:38:55 2009
@@ -21,7 +21,13 @@
#include "ieee802_11_defs.h"
#include <net/if.h>
+
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#define COMPAT_FREEBSD_NET80211
+#else
#include <net/ethernet.h>
+#endif
#include <net80211/ieee80211.h>
#include <net80211/ieee80211_crypto.h>
@@ -449,7 +455,12 @@
}
#include <net/route.h>
+#if __FreeBSD__
#include <net80211/ieee80211_freebsd.h>
+#endif
+#if __NetBSD__
+#include <net80211/ieee80211_netbsd.h>
+#endif
static void
wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_madwifi.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_madwifi.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_madwifi.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_madwifi.c Sun Feb 15 19:38:55 2009
@@ -59,7 +59,8 @@
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- if (len < IFNAMSIZ) {
+ if (len < IFNAMSIZ &&
+ op != IEEE80211_IOCTL_SET_APPIEBUF) {
/*
* Argument data fits inline; put it there.
*/
@@ -90,7 +91,7 @@
"ioctl[IEEE80211_IOCTL_GETCHANLIST]",
"ioctl[IEEE80211_IOCTL_CHANSWITCH]",
NULL,
- NULL,
+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
NULL,
"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
@@ -482,6 +483,30 @@
}
+static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
+ size_t ies_len)
+{
+ struct ieee80211req_getset_appiebuf *probe_req_ie;
+ int ret;
+
+ probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
+ if (probe_req_ie == NULL)
+ return -1;
+
+ probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
+ probe_req_ie->app_buflen = ies_len;
+ os_memcpy(probe_req_ie->app_buf, ies, ies_len);
+
+ ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
+ sizeof(struct ieee80211req_getset_appiebuf) +
+ ies_len, 1);
+
+ os_free(probe_req_ie);
+
+ return ret;
+}
+
+
static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
{
struct wpa_driver_madwifi_data *drv;
@@ -568,4 +593,5 @@
.associate = wpa_driver_madwifi_associate,
.set_auth_alg = wpa_driver_madwifi_set_auth_alg,
.set_operstate = wpa_driver_madwifi_set_operstate,
+ .set_probe_req_ie = wpa_driver_madwifi_set_probe_req_ie,
};
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c Sun Feb 15 19:38:55 2009
@@ -49,7 +49,7 @@
struct wpa_driver_nl80211_data {
void *ctx;
- int event_sock;
+ int wext_event_sock;
int ioctl_sock;
char ifname[IFNAMSIZ + 1];
int ifindex;
@@ -151,6 +151,68 @@
}
+struct family_data {
+ const char *group;
+ int id;
+};
+
+
+static int family_handler(struct nl_msg *msg, void *arg)
+{
+ struct family_data *res = arg;
+ struct nlattr *tb[CTRL_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *mcgrp;
+ int i;
+
+ nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[CTRL_ATTR_MCAST_GROUPS])
+ return NL_SKIP;
+
+ nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+ struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+ nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
+ nla_len(mcgrp), NULL);
+ if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
+ !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
+ os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
+ res->group,
+ nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
+ continue;
+ res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+ break;
+ };
+
+ return NL_SKIP;
+}
+
+
+static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+ const char *family, const char *group)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+ struct family_data res = { group, -ENOENT };
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+ genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
+ 0, 0, CTRL_CMD_GETFAMILY, 0);
+ NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
+
+ ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+ msg = NULL;
+ if (ret == 0)
+ ret = res.id;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
static int wpa_driver_nl80211_send_oper_ifla(
struct wpa_driver_nl80211_data *drv,
int linkmode, int operstate)
@@ -200,7 +262,7 @@
wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
linkmode, operstate);
- ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
+ ret = send(drv->wext_event_sock, &req, req.hdr.nlmsg_len, 0);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
"%s (assume operstate is not supported)",
@@ -631,12 +693,6 @@
wpa_driver_nl80211_event_wireless_custom(ctx, buf);
os_free(buf);
break;
- case SIOCGIWSCAN:
- drv->scan_complete_events = 1;
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
- drv, ctx);
- wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
- break;
case IWEVASSOCREQIE:
wpa_driver_nl80211_event_wireless_assocreqie(
drv, custom, iwe->u.data.length);
@@ -832,8 +888,8 @@
}
-static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
- void *sock_ctx)
+static void wpa_driver_nl80211_event_receive_wext(int sock, void *eloop_ctx,
+ void *sock_ctx)
{
char buf[8192];
int left;
@@ -899,6 +955,77 @@
}
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+
+static int process_event(struct nl_msg *msg, void *arg)
+{
+ struct wpa_driver_nl80211_data *drv = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_IFINDEX]) {
+ int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+ if (ifindex != drv->ifindex) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
+ " for foreign interface (ifindex %d)",
+ gnlh->cmd, ifindex);
+ return NL_SKIP;
+ }
+ }
+
+ switch (gnlh->cmd) {
+ case NL80211_CMD_NEW_SCAN_RESULTS:
+ wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case NL80211_CMD_SCAN_ABORTED:
+ wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
+ /*
+ * Need to indicate that scan results are available in order
+ * not to make wpa_supplicant stop its scanning.
+ */
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl0211: Ignored unknown event (cmd=%d)",
+ gnlh->cmd);
+ break;
+ }
+
+ return NL_SKIP;
+}
+
+
+static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct nl_cb *cb;
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+
+ cb = nl_cb_clone(drv->nl_cb);
+ if (!cb)
+ return;
+ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
+ nl_recvmsgs(drv->nl_handle, cb);
+ nl_cb_put(cb);
+}
+
+
static int wpa_driver_nl80211_get_ifflags_ifname(struct wpa_driver_nl80211_data *drv,
const char *ifname, int *flags)
{
@@ -990,6 +1117,36 @@
return 0;
nla_put_failure:
return -EINVAL;
+}
+
+
+static int wpa_driver_nl80211_set_probe_req_ie(void *priv, const u8 *ies,
+ size_t ies_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_MGMT_EXTRA_IE, 0);
+
+ NLA_PUT_U8(msg, NL80211_ATTR_MGMT_SUBTYPE, 4 /* ProbeReq */);
+ if (ies)
+ NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
+
+ ret = 0;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ return ret;
+
+nla_put_failure:
+ return -ENOBUFS;
}
@@ -1254,7 +1411,7 @@
*/
static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
{
- int s;
+ int s, ret;
struct sockaddr_nl local;
struct wpa_driver_nl80211_data *drv;
@@ -1297,6 +1454,18 @@
"found");
goto err4;
}
+
+ ret = nl_get_multicast_id(drv, "nl80211", "scan");
+ if (ret >= 0)
+ ret = nl_socket_add_membership(drv->nl_handle, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
+ "membership for scan events: %d (%s)",
+ ret, strerror(-ret));
+ goto err4;
+ }
+ eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle),
+ wpa_driver_nl80211_event_receive, drv, ctx);
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
@@ -1319,9 +1488,9 @@
goto err6;
}
- eloop_register_read_sock(s, wpa_driver_nl80211_event_receive, drv,
+ eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_wext, drv,
ctx);
- drv->event_sock = s;
+ drv->wext_event_sock = s;
wpa_driver_nl80211_finish_drv_init(drv);
@@ -1354,17 +1523,6 @@
if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) {
printf("Could not set interface '%s' UP\n",
drv->ifname);
- } else {
- /*
- * Wait some time to allow driver to initialize before
- * starting configuring the driver. This seems to be
- * needed at least some drivers that load firmware etc.
- * when the interface is set up.
- */
- wpa_printf(MSG_DEBUG, "Interface %s set UP - waiting "
- "a second for the driver to complete "
- "initialization", drv->ifname);
- sleep(1);
}
}
@@ -1419,16 +1577,17 @@
wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
- eloop_unregister_read_sock(drv->event_sock);
+ eloop_unregister_read_sock(drv->wext_event_sock);
if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0)
(void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
- close(drv->event_sock);
+ close(drv->wext_event_sock);
close(drv->ioctl_sock);
os_free(drv->assoc_req_ies);
os_free(drv->assoc_resp_ies);
+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
genl_family_put(drv->nl80211);
nl_cache_free(drv->nl_cache);
nl_handle_destroy(drv->nl_handle);
@@ -1465,38 +1624,42 @@
static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len)
{
struct wpa_driver_nl80211_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)",
- __FUNCTION__, (unsigned long) ssid_len);
+ struct nl_msg *msg, *ssids;
+
+ msg = nlmsg_alloc();
+ ssids = nlmsg_alloc();
+ if (!msg || !ssids) {
+ nlmsg_free(msg);
+ nlmsg_free(ssids);
return -1;
}
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_TRIGGER_SCAN, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
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;
- }
-
- if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
- perror("ioctl[SIOCSIWSCAN]");
- ret = -1;
+ /* Request an active scan for a specific SSID */
+ NLA_PUT(ssids, 1, ssid_len, ssid);
+ } else {
+ /* Request an active scan for wildcard SSID */
+ NLA_PUT(ssids, 1, 0, "");
+ }
+ nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
}
/* Not all drivers generate "scan completed" wireless event, so try to
* read results after a timeout. */
- timeout = 5;
+ timeout = 10;
if (drv->scan_complete_events) {
/*
* The driver seems to deliver SIOCGIWSCAN events to notify
@@ -1508,341 +1671,86 @@
wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
"seconds", ret, timeout);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
- eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, drv,
- drv->ctx);
-
+ eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+
+nla_put_failure:
+ nlmsg_free(ssids);
+ nlmsg_free(msg);
return ret;
}
-static u8 * wpa_driver_nl80211_giwscan(struct wpa_driver_nl80211_data *drv,
- size_t *len)
-{
- struct iwreq iwr;
- u8 *res_buf;
- size_t res_buf_len;
-
- res_buf_len = IW_SCAN_MAX_DATA;
- for (;;) {
- res_buf = os_malloc(res_buf_len);
- if (res_buf == NULL)
- return NULL;
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = res_buf;
- iwr.u.data.length = res_buf_len;
-
- if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
- break;
-
- if (errno == E2BIG && res_buf_len < 100000) {
- os_free(res_buf);
- res_buf = NULL;
- res_buf_len *= 2;
- wpa_printf(MSG_DEBUG, "Scan results did not fit - "
- "trying larger buffer (%lu bytes)",
- (unsigned long) res_buf_len);
- } else {
- perror("ioctl[SIOCGIWSCAN]");
- os_free(res_buf);
- return NULL;
- }
- }
-
- if (iwr.u.data.length > res_buf_len) {
- os_free(res_buf);
- return NULL;
- }
- *len = iwr.u.data.length;
-
- return res_buf;
-}
-
-
-/*
- * Data structure for collecting WEXT scan results. This is needed to allow
- * the various methods of reporting IEs to be combined into a single IE buffer.
- */
-struct wext_scan_data {
- struct wpa_scan_res res;
- u8 *ie;
- size_t ie_len;
- u8 ssid[32];
- size_t ssid_len;
- int maxrate;
-};
-
-
-static void wext_get_scan_mode(struct iw_event *iwe,
- struct wext_scan_data *res)
-{
- if (iwe->u.mode == IW_MODE_ADHOC)
- res->res.caps |= IEEE80211_CAP_IBSS;
- else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
- res->res.caps |= IEEE80211_CAP_ESS;
-}
-
-
-static void wext_get_scan_ssid(struct iw_event *iwe,
- struct wext_scan_data *res, char *custom,
- char *end)
-{
- int ssid_len = iwe->u.essid.length;
- if (custom + ssid_len > end)
- return;
- if (iwe->u.essid.flags &&
- ssid_len > 0 &&
- ssid_len <= IW_ESSID_MAX_SIZE) {
- os_memcpy(res->ssid, custom, ssid_len);
- res->ssid_len = ssid_len;
- }
-}
-
-
-static void wext_get_scan_freq(struct iw_event *iwe,
- struct wext_scan_data *res)
-{
- int divi = 1000000, i;
-
- if (iwe->u.freq.e == 0) {
- /*
- * Some drivers do not report frequency, but a channel.
- * Try to map this to frequency by assuming they are using
- * IEEE 802.11b/g. But don't overwrite a previously parsed
- * frequency if the driver sends both frequency and channel,
- * since the driver may be sending an A-band channel that we
- * don't handle here.
- */
-
- if (res->res.freq)
- return;
-
- if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
- res->res.freq = 2407 + 5 * iwe->u.freq.m;
- return;
- } else if (iwe->u.freq.m == 14) {
- res->res.freq = 2484;
- return;
- }
- }
-
- if (iwe->u.freq.e > 6) {
- wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
- MACSTR " m=%d e=%d)",
- MAC2STR(res->res.bssid), iwe->u.freq.m,
- iwe->u.freq.e);
- return;
- }
-
- for (i = 0; i < iwe->u.freq.e; i++)
- divi /= 10;
- res->res.freq = iwe->u.freq.m / divi;
-}
-
-
-static void wext_get_scan_qual(struct iw_event *iwe,
- struct wext_scan_data *res)
-{
- res->res.qual = iwe->u.qual.qual;
- res->res.noise = iwe->u.qual.noise;
- res->res.level = iwe->u.qual.level;
-}
-
-
-static void wext_get_scan_encode(struct iw_event *iwe,
- struct wext_scan_data *res)
-{
- if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
- res->res.caps |= IEEE80211_CAP_PRIVACY;
-}
-
-
-static void wext_get_scan_rate(struct iw_event *iwe,
- struct wext_scan_data *res, char *pos,
- char *end)
-{
- int maxrate;
- char *custom = pos + IW_EV_LCP_LEN;
- struct iw_param p;
- size_t clen;
-
- clen = iwe->len;
- if (custom + clen > end)
- return;
- maxrate = 0;
- while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
- /* Note: may be misaligned, make a local, aligned copy */
- os_memcpy(&p, custom, sizeof(struct iw_param));
- if (p.value > maxrate)
- maxrate = p.value;
- clen -= sizeof(struct iw_param);
- custom += sizeof(struct iw_param);
- }
-
- /* Convert the maxrate from WE-style (b/s units) to
- * 802.11 rates (500000 b/s units).
- */
- res->maxrate = maxrate / 500000;
-}
-
-
-static void wext_get_scan_iwevgenie(struct iw_event *iwe,
- struct wext_scan_data *res, char *custom,
- char *end)
-{
- char *genie, *gpos, *gend;
- u8 *tmp;
-
- if (iwe->u.data.length == 0)
- return;
-
- gpos = genie = custom;
- gend = genie + iwe->u.data.length;
- if (gend > end) {
- wpa_printf(MSG_INFO, "IWEVGENIE overflow");
- return;
- }
-
- tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
- if (tmp == NULL)
- return;
- os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
- res->ie = tmp;
- res->ie_len += gend - gpos;
-}
-
-
-static void wext_get_scan_custom(struct iw_event *iwe,
- struct wext_scan_data *res, char *custom,
- char *end)
-{
- size_t clen;
- u8 *tmp;
-
- clen = iwe->u.data.length;
- if (custom + clen > end)
- return;
-
- if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
- char *spos;
- int bytes;
- spos = custom + 7;
- bytes = custom + clen - spos;
- if (bytes & 1 || bytes == 0)
- return;
- bytes /= 2;
- tmp = os_realloc(res->ie, res->ie_len + bytes);
- if (tmp == NULL)
- return;
- hexstr2bin(spos, tmp + res->ie_len, bytes);
- res->ie = tmp;
- res->ie_len += bytes;
- } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
- char *spos;
- int bytes;
- spos = custom + 7;
- bytes = custom + clen - spos;
- if (bytes & 1 || bytes == 0)
- return;
- bytes /= 2;
- tmp = os_realloc(res->ie, res->ie_len + bytes);
- if (tmp == NULL)
- return;
- hexstr2bin(spos, tmp + res->ie_len, bytes);
- res->ie = tmp;
- res->ie_len += bytes;
- } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
- char *spos;
- int bytes;
- u8 bin[8];
- spos = custom + 4;
- bytes = custom + clen - spos;
- if (bytes != 16) {
- wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
- return;
- }
- bytes /= 2;
- hexstr2bin(spos, bin, bytes);
- res->res.tsf += WPA_GET_BE64(bin);
- }
-}
-
-
-static int wext_19_iw_point(struct wpa_driver_nl80211_data *drv, u16 cmd)
-{
- return drv->we_version_compiled > 18 &&
- (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
- cmd == IWEVGENIE || cmd == IWEVCUSTOM);
-}
-
-
-static void wpa_driver_nl80211_add_scan_entry(struct wpa_scan_results *res,
- struct wext_scan_data *data)
-{
+static int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_TSF] = { .type = NLA_U64 },
+ [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+ [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+ };
+ struct wpa_scan_results *res = arg;
struct wpa_scan_res **tmp;
struct wpa_scan_res *r;
- size_t extra_len;
- u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
-
- /* Figure out whether we need to fake any IEs */
- pos = data->ie;
- end = pos + data->ie_len;
- while (pos && pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == WLAN_EID_SSID)
- ssid_ie = pos;
- else if (pos[0] == WLAN_EID_SUPP_RATES)
- rate_ie = pos;
- else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
- rate_ie = pos;
- pos += 2 + pos[1];
- }
-
- extra_len = 0;
- if (ssid_ie == NULL)
- extra_len += 2 + data->ssid_len;
- if (rate_ie == NULL && data->maxrate)
- extra_len += 3;
-
- r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
+ const u8 *ie;
+ size_t ie_len;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS])
+ return NL_SKIP;
+ if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy))
+ return NL_SKIP;
+ if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ } else {
+ ie = NULL;
+ ie_len = 0;
+ }
+
+ r = os_zalloc(sizeof(*r) + ie_len);
if (r == NULL)
- return;
- os_memcpy(r, &data->res, sizeof(*r));
- r->ie_len = extra_len + data->ie_len;
- pos = (u8 *) (r + 1);
- if (ssid_ie == NULL) {
- /*
- * Generate a fake SSID IE since the driver did not report
- * a full IE list.
- */
- *pos++ = WLAN_EID_SSID;
- *pos++ = data->ssid_len;
- os_memcpy(pos, data->ssid, data->ssid_len);
- pos += data->ssid_len;
- }
- if (rate_ie == NULL && data->maxrate) {
- /*
- * Generate a fake Supported Rates IE since the driver did not
- * report a full IE list.
- */
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos++ = 1;
- *pos++ = data->maxrate;
- }
- if (data->ie)
- os_memcpy(pos, data->ie, data->ie_len);
+ return NL_SKIP;
+ if (bss[NL80211_BSS_BSSID])
+ os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
+ ETH_ALEN);
+ if (bss[NL80211_BSS_FREQUENCY])
+ r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ if (bss[NL80211_BSS_BEACON_INTERVAL])
+ r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
+ if (bss[NL80211_BSS_CAPABILITY])
+ r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+ if (bss[NL80211_BSS_SIGNAL_UNSPEC])
+ r->qual = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
+ if (bss[NL80211_BSS_SIGNAL_MBM])
+ r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
+ if (bss[NL80211_BSS_TSF])
+ r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ r->ie_len = ie_len;
+ if (ie)
+ os_memcpy(r + 1, ie, ie_len);
tmp = os_realloc(res->res,
(res->num + 1) * sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(r);
- return;
+ return NL_SKIP;
}
tmp[res->num++] = r;
res->res = tmp;
-}
-
+
+ return NL_SKIP;
+}
+
/**
* wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
@@ -1853,98 +1761,34 @@
wpa_driver_nl80211_get_scan_results(void *priv)
{
struct wpa_driver_nl80211_data *drv = priv;
- size_t ap_num = 0, len;
- int first;
- u8 *res_buf;
- struct iw_event iwe_buf, *iwe = &iwe_buf;
- char *pos, *end, *custom;
+ struct nl_msg *msg;
struct wpa_scan_results *res;
- struct wext_scan_data data;
-
- res_buf = wpa_driver_nl80211_giwscan(drv, &len);
- if (res_buf == NULL)
- return NULL;
-
- ap_num = 0;
- first = 1;
+ int ret;
res = os_zalloc(sizeof(*res));
- if (res == NULL) {
- os_free(res_buf);
- return NULL;
- }
-
- pos = (char *) res_buf;
- end = (char *) res_buf + len;
- os_memset(&data, 0, sizeof(data));
-
- while (pos + IW_EV_LCP_LEN <= end) {
- /* Event data may be unaligned, so make a local, aligned copy
- * before processing. */
- os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
- if (iwe->len <= IW_EV_LCP_LEN)
- break;
-
- custom = pos + IW_EV_POINT_LEN;
- if (wext_19_iw_point(drv, iwe->cmd)) {
- /* WE-19 removed the pointer from struct iw_point */
- char *dpos = (char *) &iwe_buf.u.data.length;
- int dlen = dpos - (char *) &iwe_buf;
- os_memcpy(dpos, pos + IW_EV_LCP_LEN,
- sizeof(struct iw_event) - dlen);
- } else {
- os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
- custom += IW_EV_POINT_OFF;
- }
-
- switch (iwe->cmd) {
- case SIOCGIWAP:
- if (!first)
- wpa_driver_nl80211_add_scan_entry(res, &data);
- first = 0;
- os_free(data.ie);
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.res.bssid,
- iwe->u.ap_addr.sa_data, ETH_ALEN);
- break;
- case SIOCGIWMODE:
- wext_get_scan_mode(iwe, &data);
- break;
- case SIOCGIWESSID:
- wext_get_scan_ssid(iwe, &data, custom, end);
- break;
- case SIOCGIWFREQ:
- wext_get_scan_freq(iwe, &data);
- break;
- case IWEVQUAL:
- wext_get_scan_qual(iwe, &data);
- break;
- case SIOCGIWENCODE:
- wext_get_scan_encode(iwe, &data);
- break;
- case SIOCGIWRATE:
- wext_get_scan_rate(iwe, &data, pos, end);
- break;
- case IWEVGENIE:
- wext_get_scan_iwevgenie(iwe, &data, custom, end);
- break;
- case IWEVCUSTOM:
- wext_get_scan_custom(iwe, &data, custom, end);
- break;
- }
-
- pos += iwe->len;
- }
- os_free(res_buf);
- res_buf = NULL;
- if (!first)
- wpa_driver_nl80211_add_scan_entry(res, &data);
- os_free(data.ie);
-
- wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
- (unsigned long) len, (unsigned long) res->num);
-
- return res;
+ if (res == NULL)
+ return 0;
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
+ NL80211_CMD_GET_SCAN, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, res);
+ msg = NULL;
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
+ (unsigned long) res->num);
+ return res;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+nla_put_failure:
+ nlmsg_free(msg);
+ wpa_scan_results_free(res);
+ return NULL;
}
@@ -2895,6 +2739,7 @@
.get_capa = wpa_driver_nl80211_get_capa,
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_country = wpa_driver_nl80211_set_country,
+ .set_probe_req_ie = wpa_driver_nl80211_set_probe_req_ie,
#ifdef CONFIG_CLIENT_MLME
.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
.set_channel = wpa_driver_nl80211_set_channel,
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c Sun Feb 15 19:38:55 2009
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - privilege separated driver interface
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -443,6 +443,22 @@
}
+static void wpa_driver_privsep_event_sta_rx(void *ctx, u8 *buf, size_t len)
+{
+#ifdef CONFIG_CLIENT_MLME
+ struct ieee80211_rx_status *rx_status;
+
+ if (len < sizeof(*rx_status))
+ return;
+ rx_status = (struct ieee80211_rx_status *) buf;
+ buf += sizeof(*rx_status);
+ len -= sizeof(*rx_status);
+
+ wpa_supplicant_sta_rx(ctx, buf, len, rx_status);
+#endif /* CONFIG_CLIENT_MLME */
+}
+
+
static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -476,8 +492,8 @@
os_memcpy(&event, buf, sizeof(int));
event_buf = &buf[sizeof(int)];
event_len = res - sizeof(int);
- wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%d)",
- event, event_len);
+ wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
+ event, (unsigned long) event_len);
e = event;
switch (e) {
@@ -518,6 +534,11 @@
case PRIVSEP_EVENT_RX_EAPOL:
wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
event_len);
+ break;
+ case PRIVSEP_EVENT_STA_RX:
+ wpa_driver_privsep_event_sta_rx(drv->ctx, event_buf,
+ event_len);
+ break;
}
os_free(buf);
@@ -732,6 +753,15 @@
wpa_printf(MSG_DEBUG, "%s mode=%d", __func__, mode);
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_MODE, &mode, sizeof(mode),
NULL, NULL);
+}
+
+
+static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
+ os_strlen(alpha2), NULL, NULL);
}
@@ -775,7 +805,7 @@
wpa_driver_privsep_get_scan_results2,
NULL /* set_probe_req_ie */,
wpa_driver_privsep_set_mode,
- NULL /* set_country */,
+ wpa_driver_privsep_set_country,
NULL /* global_init */,
NULL /* global_deinit */,
NULL /* init2 */,
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_roboswitch.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_roboswitch.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_roboswitch.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_roboswitch.c Sun Feb 15 19:38:55 2009
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - roboswitch driver interface
- * Copyright (c) 2008 Jouke Witteveen
+ * Copyright (c) 2008-2009 Jouke Witteveen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -47,7 +47,9 @@
/* VLAN page registers */
#define ROBO_VLAN_ACCESS 0x06 /* VLAN table Access register */
+#define ROBO_VLAN_ACCESS_5365 0x08 /* VLAN table Access register (5365) */
#define ROBO_VLAN_READ 0x0C /* VLAN read register */
+#define ROBO_VLAN_MAX 0xFF /* Maximum number of VLANs */
static const u8 pae_group_addr[ETH_ALEN] =
@@ -240,32 +242,44 @@
const u8 *addr)
{
int i;
- u8 mport[4] = { ROBO_ARLCTRL_VEC_1, ROBO_ARLCTRL_ADDR_1,
- ROBO_ARLCTRL_VEC_2, ROBO_ARLCTRL_ADDR_2 };
u16 _read[3], zero = 0;
- /* same as at join */
- u16 addr_word[ETH_ALEN / 2];
+ u16 addr_word[ETH_ALEN / 2]; /* same as at join */
for (i = 0; i < ETH_ALEN; i += 2)
addr_word[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i);
- /* find our address/vector pair */
- for (i = 0; i < 4; i += 2) {
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, mport[i],
- _read, 1);
- if (_read[0] == drv->ports) {
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
- mport[i + 1], _read, 3);
- if (os_memcmp(_read, addr_word, 6) == 0)
- break;
+ /* check if multiport address 1 was used */
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
+ _read, 1);
+ if (_read[0] == drv->ports) {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, _read, 3);
+ if (os_memcmp(_read, addr_word, 6) == 0) {
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &zero,
+ 1);
+ goto clean_up;
}
}
- /* check if we found our address/vector pair and deactivate it */
- if (i == 4)
- return -1;
- wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, mport[i], &zero,
- 1);
-
+
+ /* check if multiport address 2 was used */
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_2,
+ _read, 1);
+ if (_read[0] == drv->ports) {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, _read, 3);
+ if (os_memcmp(_read, addr_word, 6) == 0) {
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &zero,
+ 1);
+ goto clean_up;
+ }
+ }
+
+ /* used multiport address not found */
+ return -1;
+
+clean_up:
/* leave the multiport registers in a sane state */
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
_read, 1);
@@ -306,7 +320,7 @@
{
struct wpa_driver_roboswitch_data *drv;
int len = -1, sep = -1;
- u16 vlan = 0, vlan_read[2];
+ u16 vlan_max = ROBO_VLAN_MAX, vlan = 0, vlan_read[2];
drv = os_zalloc(sizeof(*drv));
if (drv == NULL) return NULL;
@@ -339,7 +353,7 @@
}
vlan *= 10;
vlan += ifname[sep] - '0';
- if (vlan > 255) {
+ if (vlan > ROBO_VLAN_MAX) {
wpa_printf(MSG_INFO, "%s: VLAN out of range in "
"interface name %s", __func__, ifname);
os_free(drv);
@@ -368,10 +382,19 @@
return NULL;
}
+ /* set the read bit */
vlan |= 1 << 13;
- /* The BCM5365 uses a different register and is not accounted for. */
+ /* set and read back to see if the register can be used */
wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS,
- &vlan, 1);
+ &vlan_max, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS,
+ &vlan_max, 1);
+ if (vlan_max == ROBO_VLAN_MAX) /* pre-5365 */
+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
+ ROBO_VLAN_ACCESS, &vlan, 1);
+ else /* 5365 uses a different register */
+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
+ ROBO_VLAN_ACCESS_5365, &vlan, 1);
wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ,
vlan_read, 2);
if (!(vlan_read[1] & (1 << 4))) {
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c Sun Feb 15 19:38:55 2009
@@ -1140,10 +1140,12 @@
if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
break;
- if (errno == E2BIG && res_buf_len < 100000) {
+ if (errno == E2BIG && res_buf_len < 65535) {
os_free(res_buf);
res_buf = NULL;
res_buf_len *= 2;
+ if (res_buf_len > 65535)
+ res_buf_len = 65535; /* 16-bit length field */
wpa_printf(MSG_DEBUG, "Scan results did not fit - "
"trying larger buffer (%lu bytes)",
(unsigned long) res_buf_len);
@@ -1690,6 +1692,7 @@
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
if (alg == WPA_ALG_NONE)
iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
iwr.u.encoding.pointer = (caddr_t) ext;
@@ -1819,6 +1822,7 @@
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
if (alg == WPA_ALG_NONE)
iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
iwr.u.encoding.pointer = (caddr_t) key;
@@ -1833,6 +1837,7 @@
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
iwr.u.encoding.pointer = (caddr_t) NULL;
iwr.u.encoding.length = 0;
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
@@ -1893,12 +1898,35 @@
}
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
+{
+ const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ u8 ssid[32];
+ int i;
+
+ /*
+ * Clear the BSSID selection and set a random SSID to make sure the
+ * driver will not be trying to associate with something even if it
+ * does not understand SIOCSIWMLME commands (or tries to associate
+ * automatically after deauth/disassoc).
+ */
+ wpa_driver_wext_set_bssid(drv, null_bssid);
+
+ for (i = 0; i < 32; i++)
+ ssid[i] = rand() & 0xFF;
+ wpa_driver_wext_set_ssid(drv, ssid, 32);
+}
+
+
static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
int reason_code)
{
struct wpa_driver_wext_data *drv = priv;
+ int ret;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+ return ret;
}
@@ -1906,9 +1934,11 @@
int reason_code)
{
struct wpa_driver_wext_data *drv = priv;
+ int ret;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC,
- reason_code);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ return ret;
}
Modified: wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c Sun Feb 15 19:38:55 2009
@@ -156,10 +156,13 @@
return -1;
/* best/max rate preferred if signal level close enough XXX */
- maxrate_a = wpa_scan_get_max_rate(wa);
- maxrate_b = wpa_scan_get_max_rate(wb);
- if (maxrate_a != maxrate_b && abs(wb->level - wa->level) < 5)
- return maxrate_b - maxrate_a;
+ if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) ||
+ (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
+ maxrate_a = wpa_scan_get_max_rate(wa);
+ maxrate_b = wpa_scan_get_max_rate(wb);
+ if (maxrate_a != maxrate_b)
+ return maxrate_b - maxrate_a;
+ }
/* use freq for channel preference */
Modified: wpasupplicant/branches/upstream/current/src/eap_common/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/Makefile Sun Feb 15 19:38:55 2009
@@ -3,4 +3,10 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
- rm -f *~ *.o *.d
+ rm -f *~ *.o *.so *.d
+
+install:
+ if ls *.so >/dev/null 2>&1; then \
+ install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \
+ cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \
+ ; fi
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap.c Sun Feb 15 19:38:55 2009
@@ -134,7 +134,8 @@
{
SM_ENTRY(EAP, INITIALIZE);
if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
- sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
+ sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
+ !sm->prev_failure) {
wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
"fast reauthentication");
sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
@@ -165,6 +166,7 @@
eapol_set_bool(sm, EAPOL_eapResp, FALSE);
eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
sm->num_rounds = 0;
+ sm->prev_failure = 0;
}
@@ -505,6 +507,8 @@
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
"EAP authentication failed");
+
+ sm->prev_failure = 1;
}
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c Sun Feb 15 19:38:55 2009
@@ -60,6 +60,7 @@
u8 *network_name;
size_t network_name_len;
u16 kdf;
+ int kdf_negotiation;
};
@@ -665,6 +666,7 @@
{
struct eap_sim_msg *msg;
+ data->kdf_negotiation = 1;
data->kdf = kdf;
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
"select)", id);
@@ -704,7 +706,7 @@
/* The only allowed (and required) duplication of a KDF is the addition
* of the selected KDF into the beginning of the list. */
- if (data->kdf) {
+ if (data->kdf_negotiation) {
if (attr->kdf[0] != data->kdf) {
wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
"accept the selected KDF");
@@ -840,7 +842,13 @@
#ifdef EAP_AKA_PRIME
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
- * needed 6-octet SQN ^AK for CK',IK' derivation */
+ * needed 6-octet SQN ^ AK for CK',IK' derivation */
+ u16 amf = WPA_GET_BE16(data->autn + 6);
+ if (!(amf & 0x8000)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
+ "not set (AMF=0x%4x)", amf);
+ return eap_aka_authentication_reject(data, id);
+ }
eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
data->autn,
data->network_name,
@@ -1245,6 +1253,7 @@
wpabuf_free(data->id_msgs);
data->id_msgs = NULL;
data->use_result_ind = 0;
+ data->kdf_negotiation = 0;
}
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h Sun Feb 15 19:38:55 2009
@@ -333,6 +333,8 @@
int force_disabled;
struct wps_context *wps;
+
+ int prev_failure;
};
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c Sun Feb 15 19:38:55 2009
@@ -904,7 +904,7 @@
if (in_data) {
eap_peer_tls_reset_output(data);
- len = wpabuf_len(in_data) + 100;
+ len = wpabuf_len(in_data) + 300;
data->tls_out = os_malloc(len);
if (data->tls_out == NULL)
return -1;
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c Sun Feb 15 19:38:55 2009
@@ -405,6 +405,7 @@
eap_wsc_state(data, MESG);
break;
case WPS_FAILURE:
+ case WPS_PENDING:
wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
eap_wsc_state(data, FAIL);
break;
Modified: wpasupplicant/branches/upstream/current/src/eap_server/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c Sun Feb 15 19:38:55 2009
@@ -369,15 +369,19 @@
EAP_AKA_SUBTYPE_CHALLENGE);
wpa_printf(MSG_DEBUG, " AT_RAND");
eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
+ wpa_printf(MSG_DEBUG, " AT_AUTN");
eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
if (data->kdf) {
/* Add the selected KDF into the beginning */
+ wpa_printf(MSG_DEBUG, " AT_KDF");
eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
NULL, 0);
}
+ wpa_printf(MSG_DEBUG, " AT_KDF");
eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
NULL, 0);
+ wpa_printf(MSG_DEBUG, " AT_KDF_INPUT");
eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
data->network_name_len,
data->network_name, data->network_name_len);
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c Sun Feb 15 19:38:55 2009
@@ -15,6 +15,7 @@
#include "includes.h"
#include "common.h"
+#include "eloop.h"
#include "eap_i.h"
#include "eap_common/eap_wsc_common.h"
#include "wps/wps.h"
@@ -29,6 +30,7 @@
size_t out_used;
size_t fragment_size;
struct wps_data *wps;
+ int ext_reg_timeout;
};
@@ -62,6 +64,21 @@
}
+static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct eap_sm *sm = eloop_ctx;
+ struct eap_wsc_data *data = timeout_ctx;
+
+ if (sm->method_pending != METHOD_PENDING_WAIT)
+ return;
+
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
+ "Registrar");
+ data->ext_reg_timeout = 1;
+ eap_sm_pending_cb(sm);
+}
+
+
static void * eap_wsc_init(struct eap_sm *sm)
{
struct eap_wsc_data *data;
@@ -123,6 +140,7 @@
static void eap_wsc_reset(struct eap_sm *sm, void *priv)
{
struct eap_wsc_data *data = priv;
+ eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
wpabuf_free(data->in_buf);
wpabuf_free(data->out_buf);
wps_deinit(data->wps);
@@ -324,6 +342,12 @@
enum wps_process_res res;
struct wpabuf tmpbuf;
+ eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
+ if (data->ext_reg_timeout) {
+ eap_wsc_state(data, FAIL);
+ return;
+ }
+
pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
respData, &len);
if (pos == NULL || len < 2)
@@ -408,6 +432,13 @@
case WPS_FAILURE:
wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
eap_wsc_state(data, FAIL);
+ break;
+ case WPS_PENDING:
+ eap_wsc_state(data, MSG);
+ sm->method_pending = METHOD_PENDING_WAIT;
+ eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
+ eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
+ sm, data);
break;
}
Modified: wpasupplicant/branches/upstream/current/src/eapol_supp/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eapol_supp/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eapol_supp/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/eapol_supp/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c (original)
+++ wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c Sun Feb 15 19:38:55 2009
@@ -1165,6 +1165,31 @@
sm->dot1xSuppEapLengthErrorFramesRx++;
return 0;
}
+#ifdef CONFIG_WPS
+ if (sm->conf.workaround &&
+ plen < len - sizeof(*hdr) &&
+ hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
+ len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
+ const struct eap_hdr *ehdr =
+ (const struct eap_hdr *) (hdr + 1);
+ u16 elen;
+
+ elen = be_to_host16(ehdr->length);
+ if (elen > plen && elen <= len - sizeof(*hdr)) {
+ /*
+ * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
+ * packets with too short EAPOL header length field
+ * (14 octets). This is fixed in firmware Ver.1.49.
+ * As a workaround, fix the EAPOL header based on the
+ * correct length in the EAP packet.
+ */
+ wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
+ "payload length based on EAP header: "
+ "%d -> %d", (int) plen, elen);
+ plen = elen;
+ }
+ }
+#endif /* CONFIG_WPS */
data_len = plen + sizeof(*hdr);
switch (hdr->type) {
@@ -1349,6 +1374,7 @@
sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
sm->conf.required_keys = conf->required_keys;
sm->conf.fast_reauth = conf->fast_reauth;
+ sm->conf.workaround = conf->workaround;
if (sm->eap) {
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
eap_set_workaround(sm->eap, conf->workaround);
Modified: wpasupplicant/branches/upstream/current/src/hlr_auc_gw/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/hlr_auc_gw/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/hlr_auc_gw/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/hlr_auc_gw/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/hlr_auc_gw/hlr_auc_gw.milenage_db
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/hlr_auc_gw/hlr_auc_gw.milenage_db?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/hlr_auc_gw/hlr_auc_gw.milenage_db (original)
+++ wpasupplicant/branches/upstream/current/src/hlr_auc_gw/hlr_auc_gw.milenage_db Sun Feb 15 19:38:55 2009
@@ -7,3 +7,7 @@
# IMSI Ki OPc AMF SQN
232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
+
+# These values are from Test Set 19 which has the AMF separation bit set to 1
+# and as such, is suitable for EAP-AKA' test.
+555444333222111 5122250214c33e723a5dd523fc145fc0 981d464c7c52eb6e5036234984ad0bcf c3ab 16f3b3f70fc1
Modified: wpasupplicant/branches/upstream/current/src/l2_packet/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/l2_packet/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/l2_packet/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/l2_packet/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/radius/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/radius/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/radius/radius.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius.c Sun Feb 15 19:38:55 2009
@@ -293,7 +293,8 @@
}
-int radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len)
+int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len)
{
if (secret) {
u8 auth[MD5_MAC_LEN];
@@ -364,7 +365,7 @@
}
-void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
+void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len)
{
const u8 *addr[2];
@@ -899,7 +900,7 @@
struct radius_ms_mppe_keys *
radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
- u8 *secret, size_t secret_len)
+ const u8 *secret, size_t secret_len)
{
u8 *key;
size_t keylen;
@@ -940,7 +941,7 @@
struct radius_ms_mppe_keys *
radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
- u8 *secret, size_t secret_len)
+ const u8 *secret, size_t secret_len)
{
u8 *key;
size_t keylen;
@@ -1043,8 +1044,8 @@
* in RFC 2865, Chap. 5.2 */
struct radius_attr_hdr *
radius_msg_add_attr_user_password(struct radius_msg *msg,
- u8 *data, size_t data_len,
- u8 *secret, size_t secret_len)
+ const u8 *data, size_t data_len,
+ const u8 *secret, size_t secret_len)
{
u8 buf[128];
int padlen, i;
Modified: wpasupplicant/branches/upstream/current/src/radius/radius.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius.h Sun Feb 15 19:38:55 2009
@@ -207,10 +207,11 @@
void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier);
void radius_msg_free(struct radius_msg *msg);
void radius_msg_dump(struct radius_msg *msg);
-int radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len);
+int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len);
int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
size_t secret_len, const u8 *req_authenticator);
-void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
+void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
const u8 *data, size_t data_len);
@@ -229,10 +230,10 @@
const u8 *data, size_t len);
struct radius_ms_mppe_keys *
radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
- u8 *secret, size_t secret_len);
+ const u8 *secret, size_t secret_len);
struct radius_ms_mppe_keys *
radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
- u8 *secret, size_t secret_len);
+ const u8 *secret, size_t secret_len);
int radius_msg_add_mppe_keys(struct radius_msg *msg,
const u8 *req_authenticator,
const u8 *secret, size_t secret_len,
@@ -240,8 +241,8 @@
const u8 *recv_key, size_t recv_key_len);
struct radius_attr_hdr *
radius_msg_add_attr_user_password(struct radius_msg *msg,
- u8 *data, size_t data_len,
- u8 *secret, size_t secret_len);
+ const u8 *data, size_t data_len,
+ const u8 *secret, size_t secret_len);
int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
int radius_msg_get_vlanid(struct radius_msg *msg);
Modified: wpasupplicant/branches/upstream/current/src/radius/radius_client.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_client.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.c Sun Feb 15 19:38:55 2009
@@ -35,7 +35,8 @@
struct radius_rx_handler {
RadiusRxResult (*handler)(struct radius_msg *msg,
struct radius_msg *req,
- u8 *shared_secret, size_t shared_secret_len,
+ const u8 *shared_secret,
+ size_t shared_secret_len,
void *data);
void *data;
};
@@ -106,7 +107,7 @@
RadiusType msg_type,
RadiusRxResult (*handler)(struct radius_msg *msg,
struct radius_msg *req,
- u8 *shared_secret,
+ const u8 *shared_secret,
size_t shared_secret_len,
void *data),
void *data)
Modified: wpasupplicant/branches/upstream/current/src/radius/radius_client.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_client.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.h Sun Feb 15 19:38:55 2009
@@ -85,7 +85,7 @@
RadiusType msg_type,
RadiusRxResult (*handler)
(struct radius_msg *msg, struct radius_msg *req,
- u8 *shared_secret, size_t shared_secret_len,
+ const u8 *shared_secret, size_t shared_secret_len,
void *data),
void *data);
int radius_client_send(struct radius_client_data *radius,
Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/tls/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/tls/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/utils/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/utils/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Modified: wpasupplicant/branches/upstream/current/src/utils/os_unix.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/os_unix.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/os_unix.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/os_unix.c Sun Feb 15 19:38:55 2009
@@ -76,12 +76,47 @@
}
+#ifdef __APPLE__
+#include <fcntl.h>
+static int os_daemon(int nochdir, int noclose)
+{
+ int devnull;
+
+ if (chdir("/") < 0)
+ return -1;
+
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0)
+ return -1;
+
+ if (dup2(devnull, STDIN_FILENO) < 0) {
+ close(devnull);
+ return -1;
+ }
+
+ if (dup2(devnull, STDOUT_FILENO) < 0) {
+ close(devnull);
+ return -1;
+ }
+
+ if (dup2(devnull, STDERR_FILENO) < 0) {
+ close(devnull);
+ return -1;
+ }
+
+ return 0;
+}
+#else /* __APPLE__ */
+#define os_daemon daemon
+#endif /* __APPLE__ */
+
+
int os_daemonize(const char *pid_file)
{
#ifdef __uClinux__
return -1;
#else /* __uClinux__ */
- if (daemon(0, 0)) {
+ if (os_daemon(0, 0)) {
perror("daemon");
return -1;
}
Modified: wpasupplicant/branches/upstream/current/src/utils/wpabuf.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/wpabuf.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/wpabuf.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/wpabuf.c Sun Feb 15 19:38:55 2009
@@ -1,6 +1,6 @@
/*
* Dynamic data buffer
- * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -160,3 +160,53 @@
return n;
}
+
+
+/**
+ * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
+ * @buf: Buffer to be padded
+ * @len: Length for the padded buffer
+ * Returns: wpabuf padded to len octets or %NULL on failure
+ *
+ * If buf is longer than len octets or of same size, it will be returned as-is.
+ * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
+ * by the source data. The source buffer will be freed on error, i.e., caller
+ * will only be responsible on freeing the returned buffer. If buf is %NULL,
+ * %NULL will be returned.
+ */
+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
+{
+ struct wpabuf *ret;
+ size_t blen;
+
+ if (buf == NULL)
+ return NULL;
+
+ blen = wpabuf_len(buf);
+ if (blen >= len)
+ return buf;
+
+ ret = wpabuf_alloc(len);
+ if (ret) {
+ os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
+ wpabuf_put_buf(ret, buf);
+ }
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
+{
+ va_list ap;
+ void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
+ int res;
+
+ va_start(ap, fmt);
+ res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
+ va_end(ap);
+ if (res < 0 || (size_t) res >= buf->size - buf->used)
+ wpabuf_overflow(buf, res);
+ buf->used += res;
+}
Modified: wpasupplicant/branches/upstream/current/src/utils/wpabuf.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/wpabuf.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/wpabuf.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/wpabuf.h Sun Feb 15 19:38:55 2009
@@ -1,6 +1,6 @@
/*
* Dynamic data buffer
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -37,6 +37,8 @@
void wpabuf_free(struct wpabuf *buf);
void * wpabuf_put(struct wpabuf *buf, size_t len);
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
/**
@@ -146,4 +148,9 @@
buf->size = buf->used = len;
}
+static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)
+{
+ wpabuf_put_data(dst, str, os_strlen(str));
+}
+
#endif /* WPABUF_H */
Modified: wpasupplicant/branches/upstream/current/src/wps/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/wps/Makefile Sun Feb 15 19:38:55 2009
@@ -4,3 +4,6 @@
clean:
for d in $(SUBDIRS); do make -C $$d clean; done
rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
Added: wpasupplicant/branches/upstream/current/src/wps/httpread.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/httpread.c?rev=1324&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/httpread.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/httpread.c Sun Feb 15 19:38:55 2009
@@ -1,0 +1,858 @@
+/**
+ * httpread - Manage reading file(s) from HTTP/TCP socket
+ * Author: Ted Merrill
+ * Copyright 2008 Atheros Communications
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * The files are buffered via internal callbacks from eloop, then presented to
+ * an application callback routine when completely read into memory. May also
+ * be used if no file is expected but just to get the header, including HTTP
+ * replies (e.g. HTTP/1.1 200 OK etc.).
+ *
+ * This does not attempt to be an optimally efficient implementation, but does
+ * attempt to be of reasonably small size and memory consumption; assuming that
+ * only small files are to be read. A maximum file size is provided by
+ * application and enforced.
+ *
+ * It is assumed that the application does not expect any of the following:
+ * -- transfer encoding other than chunked
+ * -- trailer fields
+ * It is assumed that, even if the other side requested that the connection be
+ * kept open, that we will close it (thus HTTP messages sent by application
+ * should have the connection closed field); this is allowed by HTTP/1.1 and
+ * simplifies things for us.
+ *
+ * Other limitations:
+ * -- HTTP header may not exceed a hard-coded size.
+ *
+ * Notes:
+ * This code would be massively simpler without some of the new features of
+ * HTTP/1.1, especially chunked data.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "httpread.h"
+
+
+/* Tunable parameters */
+#define HTTPREAD_READBUF_SIZE 1024 /* read in chunks of this size */
+#define HTTPREAD_HEADER_MAX_SIZE 4096 /* max allowed for headers */
+#define HTTPREAD_BODYBUF_DELTA 4096 /* increase allocation by this */
+
+#if 0
+/* httpread_debug -- set this global variable > 0 e.g. from debugger
+ * to enable debugs (larger numbers for more debugs)
+ * Make this a #define of 0 to eliminate the debugging code.
+ */
+int httpread_debug = 99;
+#else
+#define httpread_debug 0 /* eliminates even the debugging code */
+#endif
+
+
+/* control instance -- actual definition (opaque to application)
+ */
+struct httpread {
+ /* information from creation */
+ int sd; /* descriptor of TCP socket to read from */
+ void (*cb)(struct httpread *handle, void *cookie,
+ enum httpread_event e); /* call on event */
+ void *cookie; /* pass to callback */
+ int max_bytes; /* maximum file size else abort it */
+ int timeout_seconds; /* 0 or total duration timeout period */
+
+ /* dynamically used information follows */
+ int sd_registered; /* nonzero if we need to unregister socket */
+ int to_registered; /* nonzero if we need to unregister timeout */
+
+ int got_hdr; /* nonzero when header is finalized */
+ char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */
+ int hdr_nbytes;
+
+ enum httpread_hdr_type hdr_type;
+ int version; /* 1 if we've seen 1.1 */
+ int reply_code; /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */
+ int got_content_length; /* true if we know content length for sure */
+ int content_length; /* body length, iff got_content_length */
+ int chunked; /* nonzero for chunked data */
+ char *uri;
+
+ int got_body; /* nonzero when body is finalized */
+ char *body;
+ int body_nbytes;
+ int body_alloc_nbytes; /* amount allocated */
+
+ int got_file; /* here when we are done */
+
+ /* The following apply if data is chunked: */
+ int in_chunk_data; /* 0=in/at header, 1=in the data or tail*/
+ int chunk_start; /* offset in body of chunk hdr or data */
+ int chunk_size; /* data of chunk (not hdr or ending CRLF)*/
+ int in_trailer; /* in header fields after data (chunked only)*/
+ enum trailer_state {
+ trailer_line_begin = 0,
+ trailer_empty_cr, /* empty line + CR */
+ trailer_nonempty,
+ trailer_nonempty_cr,
+ } trailer_state;
+};
+
+
+/* Check words for equality, where words consist of graphical characters
+ * delimited by whitespace
+ * Returns nonzero if "equal" doing case insensitive comparison.
+ */
+static int word_eq(char *s1, char *s2)
+{
+ int c1;
+ int c2;
+ int end1 = 0;
+ int end2 = 0;
+ for (;;) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if (isalpha(c1) && isupper(c1))
+ c1 = tolower(c1);
+ if (isalpha(c2) && isupper(c2))
+ c2 = tolower(c2);
+ end1 = !isgraph(c1);
+ end2 = !isgraph(c2);
+ if (end1 || end2 || c1 != c2)
+ break;
+ }
+ return end1 && end2; /* reached end of both words? */
+}
+
+
+/* convert hex to binary
+ * Requires that c have been previously tested true with isxdigit().
+ */
+static int hex_value(int c)
+{
+ if (isdigit(c))
+ return c - '0';
+ if (islower(c))
+ return 10 + c - 'a';
+ return 10 + c - 'A';
+}
+
+
+static void httpread_timeout_handler(void *eloop_data, void *user_ctx);
+
+/* httpread_destroy -- if h is non-NULL, clean up
+ * This must eventually be called by the application following
+ * call of the application's callback and may be called
+ * earlier if desired.
+ */
+void httpread_destroy(struct httpread *h)
+{
+ if (httpread_debug >= 10)
+ wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h);
+ if (!h)
+ return;
+
+ if (h->to_registered)
+ eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
+ h->to_registered = 0;
+ if (h->sd_registered)
+ eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
+ h->sd_registered = 0;
+ os_free(h->body);
+ os_free(h->uri);
+ os_memset(h, 0, sizeof(*h)); /* aid debugging */
+ h->sd = -1; /* aid debugging */
+ os_free(h);
+}
+
+
+/* httpread_timeout_handler -- called on excessive total duration
+ */
+static void httpread_timeout_handler(void *eloop_data, void *user_ctx)
+{
+ struct httpread *h = user_ctx;
+ wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
+ h->to_registered = 0; /* is self-cancelling */
+ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
+}
+
+
+/* Analyze options only so far as is needed to correctly obtain the file.
+ * The application can look at the raw header to find other options.
+ */
+static int httpread_hdr_option_analyze(
+ struct httpread *h,
+ char *hbp /* pointer to current line in header buffer */
+ )
+{
+ if (word_eq(hbp, "CONTENT-LENGTH:")) {
+ while (isgraph(*hbp))
+ hbp++;
+ while (*hbp == ' ' || *hbp == '\t')
+ hbp++;
+ if (!isdigit(*hbp))
+ return -1;
+ h->content_length = atol(hbp);
+ h->got_content_length = 1;
+ return 0;
+ }
+ if (word_eq(hbp, "TRANSFER_ENCODING:")) {
+ while (isgraph(*hbp))
+ hbp++;
+ while (*hbp == ' ' || *hbp == '\t')
+ hbp++;
+ /* There should (?) be no encodings of interest
+ * other than chunked...
+ */
+ if (os_strncmp(hbp, "CHUNKED", 7)) {
+ h->chunked = 1;
+ h->in_chunk_data = 0;
+ /* ignore possible ;<parameters> */
+ }
+ return 0;
+ }
+ /* skip anything we don't know, which is a lot */
+ return 0;
+}
+
+
+static int httpread_hdr_analyze(struct httpread *h)
+{
+ char *hbp = h->hdr; /* pointer into h->hdr */
+ int standard_first_line = 1;
+
+ /* First line is special */
+ h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN;
+ if (!isgraph(*hbp))
+ goto bad;
+ if (os_strncmp(hbp, "HTTP/", 5) == 0) {
+ h->hdr_type = HTTPREAD_HDR_TYPE_REPLY;
+ standard_first_line = 0;
+ hbp += 5;
+ if (hbp[0] == '1' && hbp[1] == '.' &&
+ isdigit(hbp[2]) && hbp[2] != '0')
+ h->version = 1;
+ while (isgraph(*hbp))
+ hbp++;
+ while (*hbp == ' ' || *hbp == '\t')
+ hbp++;
+ if (!isdigit(*hbp))
+ goto bad;
+ h->reply_code = atol(hbp);
+ } else if (word_eq(hbp, "GET"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_GET;
+ else if (word_eq(hbp, "HEAD"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_HEAD;
+ else if (word_eq(hbp, "POST"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_POST;
+ else if (word_eq(hbp, "PUT"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_PUT;
+ else if (word_eq(hbp, "DELETE"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_DELETE;
+ else if (word_eq(hbp, "TRACE"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_TRACE;
+ else if (word_eq(hbp, "CONNECT"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT;
+ else if (word_eq(hbp, "NOTIFY"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY;
+ else if (word_eq(hbp, "M-SEARCH"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH;
+ else if (word_eq(hbp, "M-POST"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_M_POST;
+ else if (word_eq(hbp, "SUBSCRIBE"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE;
+ else if (word_eq(hbp, "UNSUBSCRIBE"))
+ h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE;
+ else {
+ }
+
+ if (standard_first_line) {
+ char *rawuri;
+ char *uri;
+ /* skip type */
+ while (isgraph(*hbp))
+ hbp++;
+ while (*hbp == ' ' || *hbp == '\t')
+ hbp++;
+ /* parse uri.
+ * Find length, allocate memory for translated
+ * copy, then translate by changing %<hex><hex>
+ * into represented value.
+ */
+ rawuri = hbp;
+ while (isgraph(*hbp))
+ hbp++;
+ h->uri = os_malloc((hbp - rawuri) + 1);
+ if (h->uri == NULL)
+ goto bad;
+ uri = h->uri;
+ while (rawuri < hbp) {
+ int c = *rawuri;
+ if (c == '%' &&
+ isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
+ *uri++ = (hex_value(rawuri[1]) << 4) |
+ hex_value(rawuri[2]);
+ rawuri += 3;
+ } else {
+ *uri++ = c;
+ rawuri++;
+ }
+ }
+ *uri = 0; /* null terminate */
+ while (isgraph(*hbp))
+ hbp++;
+ while (*hbp == ' ' || *hbp == '\t')
+ hbp++;
+ /* get version */
+ if (0 == strncmp(hbp, "HTTP/", 5)) {
+ hbp += 5;
+ if (hbp[0] == '1' && hbp[1] == '.' &&
+ isdigit(hbp[2]) && hbp[2] != '0')
+ h->version = 1;
+ }
+ }
+ /* skip rest of line */
+ while (*hbp)
+ if (*hbp++ == '\n')
+ break;
+
+ /* Remainder of lines are options, in any order;
+ * or empty line to terminate
+ */
+ for (;;) {
+ /* Empty line to terminate */
+ if (hbp[0] == '\n' ||
+ (hbp[0] == '\r' && hbp[1] == '\n'))
+ break;
+ if (!isgraph(*hbp))
+ goto bad;
+ if (httpread_hdr_option_analyze(h, hbp))
+ goto bad;
+ /* skip line */
+ while (*hbp)
+ if (*hbp++ == '\n')
+ break;
+ }
+
+ /* chunked overrides content-length always */
+ if (h->chunked)
+ h->got_content_length = 0;
+
+ /* For some types, we should not try to read a body
+ * This is in addition to the application determining
+ * that we should not read a body.
+ */
+ switch (h->hdr_type) {
+ case HTTPREAD_HDR_TYPE_REPLY:
+ /* Some codes can have a body and some not.
+ * For now, just assume that any other than 200
+ * do not...
+ */
+ if (h->reply_code != 200)
+ h->max_bytes = 0;
+ break;
+ case HTTPREAD_HDR_TYPE_GET:
+ case HTTPREAD_HDR_TYPE_HEAD:
+ /* in practice it appears that it is assumed
+ * that GETs have a body length of 0... ?
+ */
+ if (h->chunked == 0 && h->got_content_length == 0)
+ h->max_bytes = 0;
+ break;
+ case HTTPREAD_HDR_TYPE_POST:
+ case HTTPREAD_HDR_TYPE_PUT:
+ case HTTPREAD_HDR_TYPE_DELETE:
+ case HTTPREAD_HDR_TYPE_TRACE:
+ case HTTPREAD_HDR_TYPE_CONNECT:
+ case HTTPREAD_HDR_TYPE_NOTIFY:
+ case HTTPREAD_HDR_TYPE_M_SEARCH:
+ case HTTPREAD_HDR_TYPE_M_POST:
+ case HTTPREAD_HDR_TYPE_SUBSCRIBE:
+ case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
+ default:
+ break;
+ }
+
+ return 0;
+
+bad:
+ /* Error */
+ return -1;
+}
+
+
+/* httpread_read_handler -- called when socket ready to read
+ *
+ * Note: any extra data we read past end of transmitted file is ignored;
+ * if we were to support keeping connections open for multiple files then
+ * this would have to be addressed.
+ */
+static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct httpread *h = sock_ctx;
+ int nread;
+ char *rbp; /* pointer into read buffer */
+ char *hbp; /* pointer into header buffer */
+ char *bbp; /* pointer into body buffer */
+ char readbuf[HTTPREAD_READBUF_SIZE]; /* temp use to read into */
+
+ if (httpread_debug >= 20)
+ wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h);
+
+ /* read some at a time, then search for the interal
+ * boundaries between header and data and etc.
+ */
+ nread = read(h->sd, readbuf, sizeof(readbuf));
+ if (nread < 0)
+ goto bad;
+ if (nread == 0) {
+ /* end of transmission... this may be normal
+ * or may be an error... in some cases we can't
+ * tell which so we must assume it is normal then.
+ */
+ if (!h->got_hdr) {
+ /* Must at least have completed header */
+ wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h);
+ goto bad;
+ }
+ if (h->chunked || h->got_content_length) {
+ /* Premature EOF; e.g. dropped connection */
+ wpa_printf(MSG_DEBUG,
+ "httpread premature eof(%p) %d/%d",
+ h, h->body_nbytes,
+ h->content_length);
+ goto bad;
+ }
+ /* No explicit length, hopefully we have all the data
+ * although dropped connections can cause false
+ * end
+ */
+ if (httpread_debug >= 10)
+ wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
+ h->got_body = 1;
+ goto got_file;
+ }
+ rbp = readbuf;
+
+ /* Header consists of text lines (terminated by both CR and LF)
+ * and an empty line (CR LF only).
+ */
+ if (!h->got_hdr) {
+ hbp = h->hdr + h->hdr_nbytes;
+ /* add to headers until:
+ * -- we run out of data in read buffer
+ * -- or, we run out of header buffer room
+ * -- or, we get double CRLF in headers
+ */
+ for (;;) {
+ if (nread == 0)
+ goto get_more;
+ if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {
+ goto bad;
+ }
+ *hbp++ = *rbp++;
+ nread--;
+ h->hdr_nbytes++;
+ if (h->hdr_nbytes >= 4 &&
+ hbp[-1] == '\n' &&
+ hbp[-2] == '\r' &&
+ hbp[-3] == '\n' &&
+ hbp[-4] == '\r' ) {
+ h->got_hdr = 1;
+ *hbp = 0; /* null terminate */
+ break;
+ }
+ }
+ /* here we've just finished reading the header */
+ if (httpread_hdr_analyze(h)) {
+ wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h);
+ goto bad;
+ }
+ if (h->max_bytes == 0) {
+ if (httpread_debug >= 10)
+ wpa_printf(MSG_DEBUG,
+ "httpread no body hdr end(%p)", h);
+ goto got_file;
+ }
+ if (h->got_content_length && h->content_length == 0) {
+ if (httpread_debug >= 10)
+ wpa_printf(MSG_DEBUG,
+ "httpread zero content length(%p)",
+ h);
+ goto got_file;
+ }
+ }
+
+ /* Certain types of requests never have data and so
+ * must be specially recognized.
+ */
+ if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) ||
+ !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) ||
+ !os_strncasecmp(h->hdr, "HEAD", 4) ||
+ !os_strncasecmp(h->hdr, "GET", 3)) {
+ if (!h->got_body) {
+ if (httpread_debug >= 10)
+ wpa_printf(MSG_DEBUG,
+ "httpread NO BODY for sp. type");
+ }
+ h->got_body = 1;
+ goto got_file;
+ }
+
+ /* Data can be just plain binary data, or if "chunked"
+ * consists of chunks each with a header, ending with
+ * an ending header.
+ */
+ if (!h->got_body) {
+ /* Here to get (more of) body */
+ /* ensure we have enough room for worst case for body
+ * plus a null termination character
+ */
+ if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) {
+ char *new_body;
+ int new_alloc_nbytes;
+
+ if (h->body_nbytes >= h->max_bytes)
+ goto bad;
+ new_alloc_nbytes = h->body_alloc_nbytes +
+ HTTPREAD_BODYBUF_DELTA;
+ /* For content-length case, the first time
+ * through we allocate the whole amount
+ * we need.
+ */
+ if (h->got_content_length &&
+ new_alloc_nbytes < (h->content_length + 1))
+ new_alloc_nbytes = h->content_length + 1;
+ if ((new_body = os_realloc(h->body, new_alloc_nbytes))
+ == NULL)
+ goto bad;
+
+ h->body = new_body;
+ h->body_alloc_nbytes = new_alloc_nbytes;
+ }
+ /* add bytes */
+ bbp = h->body + h->body_nbytes;
+ for (;;) {
+ int ncopy;
+ /* See if we need to stop */
+ if (h->chunked && h->in_chunk_data == 0) {
+ /* in chunk header */
+ char *cbp = h->body + h->chunk_start;
+ if (bbp-cbp >= 2 && bbp[-2] == '\r' &&
+ bbp[-1] == '\n') {
+ /* end of chunk hdr line */
+ /* hdr line consists solely
+ * of a hex numeral and CFLF
+ */
+ if (!isxdigit(*cbp))
+ goto bad;
+ h->chunk_size = strtoul(cbp, NULL, 16);
+ /* throw away chunk header
+ * so we have only real data
+ */
+ h->body_nbytes = h->chunk_start;
+ bbp = cbp;
+ if (h->chunk_size == 0) {
+ /* end of chunking */
+ /* trailer follows */
+ h->in_trailer = 1;
+ if (httpread_debug >= 20)
+ wpa_printf(
+ MSG_DEBUG,
+ "httpread end chunks(%p)", h);
+ break;
+ }
+ h->in_chunk_data = 1;
+ /* leave chunk_start alone */
+ }
+ } else if (h->chunked) {
+ /* in chunk data */
+ if ((h->body_nbytes - h->chunk_start) ==
+ (h->chunk_size + 2)) {
+ /* end of chunk reached,
+ * new chunk starts
+ */
+ /* check chunk ended w/ CRLF
+ * which we'll throw away
+ */
+ if (bbp[-1] == '\n' &&
+ bbp[-2] == '\r') {
+ } else
+ goto bad;
+ h->body_nbytes -= 2;
+ bbp -= 2;
+ h->chunk_start = h->body_nbytes;
+ h->in_chunk_data = 0;
+ h->chunk_size = 0; /* just in case */
+ }
+ } else if (h->got_content_length &&
+ h->body_nbytes >= h->content_length) {
+ h->got_body = 1;
+ if (httpread_debug >= 10)
+ wpa_printf(
+ MSG_DEBUG,
+ "httpread got content(%p)", h);
+ goto got_file;
+ }
+ if (nread <= 0)
+ break;
+ /* Now transfer. Optimize using memcpy where we can. */
+ if (h->chunked && h->in_chunk_data) {
+ /* copy up to remainder of chunk data
+ * plus the required CR+LF at end
+ */
+ ncopy = (h->chunk_start + h->chunk_size + 2) -
+ h->body_nbytes;
+ } else if (h->chunked) {
+ /*in chunk header -- don't optimize */
+ *bbp++ = *rbp++;
+ nread--;
+ h->body_nbytes++;
+ continue;
+ } else if (h->got_content_length) {
+ ncopy = h->content_length - h->body_nbytes;
+ } else {
+ ncopy = nread;
+ }
+ /* Note: should never be 0 */
+ if (ncopy > nread)
+ ncopy = nread;
+ os_memcpy(bbp, rbp, ncopy);
+ bbp += ncopy;
+ h->body_nbytes += ncopy;
+ rbp += ncopy;
+ nread -= ncopy;
+ } /* body copy loop */
+ } /* !got_body */
+ if (h->chunked && h->in_trailer) {
+ /* If "chunked" then there is always a trailer,
+ * consisting of zero or more non-empty lines
+ * ending with CR LF and then an empty line w/ CR LF.
+ * We do NOT support trailers except to skip them --
+ * this is supported (generally) by the http spec.
+ */
+ bbp = h->body + h->body_nbytes;
+ for (;;) {
+ int c;
+ if (nread <= 0)
+ break;
+ c = *rbp++;
+ nread--;
+ switch (h->trailer_state) {
+ case trailer_line_begin:
+ if (c == '\r')
+ h->trailer_state = trailer_empty_cr;
+ else
+ h->trailer_state = trailer_nonempty;
+ break;
+ case trailer_empty_cr:
+ /* end empty line */
+ if (c == '\n') {
+ h->trailer_state = trailer_line_begin;
+ h->in_trailer = 0;
+ if (httpread_debug >= 10)
+ wpa_printf(
+ MSG_DEBUG,
+ "httpread got content(%p)", h);
+ h->got_body = 1;
+ goto got_file;
+ }
+ h->trailer_state = trailer_nonempty;
+ break;
+ case trailer_nonempty:
+ if (c == '\r')
+ h->trailer_state = trailer_nonempty_cr;
+ break;
+ case trailer_nonempty_cr:
+ if (c == '\n')
+ h->trailer_state = trailer_line_begin;
+ else
+ h->trailer_state = trailer_nonempty;
+ break;
+ }
+ }
+ }
+ goto get_more;
+
+bad:
+ /* Error */
+ wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h);
+ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR);
+ return;
+
+get_more:
+ return;
+
+got_file:
+ if (httpread_debug >= 10)
+ wpa_printf(MSG_DEBUG,
+ "httpread got file %d bytes type %d",
+ h->body_nbytes, h->hdr_type);
+ /* Null terminate for convenience of some applications */
+ if (h->body)
+ h->body[h->body_nbytes] = 0; /* null terminate */
+ h->got_file = 1;
+ /* Assume that we do NOT support keeping connection alive,
+ * and just in case somehow we don't get destroyed right away,
+ * unregister now.
+ */
+ if (h->sd_registered)
+ eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
+ h->sd_registered = 0;
+ /* The application can destroy us whenever they feel like...
+ * cancel timeout.
+ */
+ if (h->to_registered)
+ eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
+ h->to_registered = 0;
+ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
+}
+
+
+/* httpread_create -- start a new reading session making use of eloop.
+ * The new instance will use the socket descriptor for reading (until
+ * it gets a file and not after) but will not close the socket, even
+ * when the instance is destroyed (the application must do that).
+ * Return NULL on error.
+ *
+ * Provided that httpread_create successfully returns a handle,
+ * the callback fnc is called to handle httpread_event events.
+ * The caller should do destroy on any errors or unknown events.
+ *
+ * Pass max_bytes == 0 to not read body at all (required for e.g.
+ * reply to HEAD request).
+ */
+struct httpread * httpread_create(
+ int sd, /* descriptor of TCP socket to read from */
+ void (*cb)(struct httpread *handle, void *cookie,
+ enum httpread_event e), /* call on event */
+ void *cookie, /* pass to callback */
+ int max_bytes, /* maximum body size else abort it */
+ int timeout_seconds /* 0; or total duration timeout period */
+ )
+{
+ struct httpread *h = NULL;
+
+ h = os_zalloc(sizeof(*h));
+ if (h == NULL)
+ goto fail;
+ h->sd = sd;
+ h->cb = cb;
+ h->cookie = cookie;
+ h->max_bytes = max_bytes;
+ h->timeout_seconds = timeout_seconds;
+
+ if (timeout_seconds > 0) {
+ if (eloop_register_timeout(timeout_seconds, 0,
+ httpread_timeout_handler,
+ NULL, h)) {
+ /* No way to recover (from malloc failure) */
+ goto fail;
+ }
+ h->to_registered = 1;
+ }
+ if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
+ NULL, h)) {
+ /* No way to recover (from malloc failure) */
+ goto fail;
+ }
+ h->sd_registered = 1;
+ return h;
+
+fail:
+
+ /* Error */
+ httpread_destroy(h);
+ return NULL;
+}
+
+
+/* httpread_hdr_type_get -- When file is ready, returns header type. */
+enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h)
+{
+ return h->hdr_type;
+}
+
+
+/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
+ * or possibly NULL (which would be an error).
+ */
+char * httpread_uri_get(struct httpread *h)
+{
+ return h->uri;
+}
+
+
+/* httpread_reply_code_get -- When reply is ready, returns reply code */
+int httpread_reply_code_get(struct httpread *h)
+{
+ return h->reply_code;
+}
+
+
+/* httpread_length_get -- When file is ready, returns file length. */
+int httpread_length_get(struct httpread *h)
+{
+ return h->body_nbytes;
+}
+
+
+/* httpread_data_get -- When file is ready, returns file content
+ * with null byte appened.
+ * Might return NULL in some error condition.
+ */
+void * httpread_data_get(struct httpread *h)
+{
+ return h->body ? h->body : "";
+}
+
+
+/* httpread_hdr_get -- When file is ready, returns header content
+ * with null byte appended.
+ * Might return NULL in some error condition.
+ */
+char * httpread_hdr_get(struct httpread *h)
+{
+ return h->hdr;
+}
+
+
+/* httpread_hdr_line_get -- When file is ready, returns pointer
+ * to line within header content matching the given tag
+ * (after the tag itself and any spaces/tabs).
+ *
+ * The tag should end with a colon for reliable matching.
+ *
+ * If not found, returns NULL;
+ */
+char * httpread_hdr_line_get(struct httpread *h, const char *tag)
+{
+ int tag_len = os_strlen(tag);
+ char *hdr = h->hdr;
+ hdr = os_strchr(hdr, '\n');
+ if (hdr == NULL)
+ return NULL;
+ hdr++;
+ for (;;) {
+ if (!os_strncasecmp(hdr, tag, tag_len)) {
+ hdr += tag_len;
+ while (*hdr == ' ' || *hdr == '\t')
+ hdr++;
+ return hdr;
+ }
+ hdr = os_strchr(hdr, '\n');
+ if (hdr == NULL)
+ return NULL;
+ hdr++;
+ }
+}
Added: wpasupplicant/branches/upstream/current/src/wps/httpread.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/httpread.h?rev=1324&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/httpread.h (added)
+++ wpasupplicant/branches/upstream/current/src/wps/httpread.h Sun Feb 15 19:38:55 2009
@@ -1,0 +1,123 @@
+/**
+ * httpread - Manage reading file(s) from HTTP/TCP socket
+ * Author: Ted Merrill
+ * Copyright 2008 Atheros Communications
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef HTTPREAD_H
+#define HTTPREAD_H
+
+/* event types (passed to callback) */
+enum httpread_event {
+ HTTPREAD_EVENT_FILE_READY = 1, /* including reply ready */
+ HTTPREAD_EVENT_TIMEOUT = 2,
+ HTTPREAD_EVENT_ERROR = 3 /* misc. error, esp malloc error */
+};
+
+
+/* header type detected
+ * available to callback via call to httpread_reply_code_get()
+ */
+enum httpread_hdr_type {
+ HTTPREAD_HDR_TYPE_UNKNOWN = 0, /* none of the following */
+ HTTPREAD_HDR_TYPE_REPLY = 1, /* hdr begins w/ HTTP/ */
+ HTTPREAD_HDR_TYPE_GET = 2, /* hdr begins with GET<sp> */
+ HTTPREAD_HDR_TYPE_HEAD = 3, /* hdr begins with HEAD<sp> */
+ HTTPREAD_HDR_TYPE_POST = 4, /* hdr begins with POST<sp> */
+ HTTPREAD_HDR_TYPE_PUT = 5, /* hdr begins with ... */
+ HTTPREAD_HDR_TYPE_DELETE = 6, /* hdr begins with ... */
+ HTTPREAD_HDR_TYPE_TRACE = 7, /* hdr begins with ... */
+ HTTPREAD_HDR_TYPE_CONNECT = 8, /* hdr begins with ... */
+ HTTPREAD_HDR_TYPE_NOTIFY = 9, /* hdr begins with ... */
+ HTTPREAD_HDR_TYPE_M_SEARCH = 10, /* hdr begins with ... */
+ HTTPREAD_HDR_TYPE_M_POST = 11, /* hdr begins with ... */
+ HTTPREAD_HDR_TYPE_SUBSCRIBE = 12, /* hdr begins with ... */
+ HTTPREAD_HDR_TYPE_UNSUBSCRIBE = 13, /* hdr begins with ... */
+
+ HTTPREAD_N_HDR_TYPES /* keep last */
+};
+
+
+/* control instance -- opaque struct declaration
+ */
+struct httpread;
+
+
+/* httpread_destroy -- if h is non-NULL, clean up
+ * This must eventually be called by the application following
+ * call of the application's callback and may be called
+ * earlier if desired.
+ */
+void httpread_destroy(struct httpread *h);
+
+/* httpread_create -- start a new reading session making use of eloop.
+ * The new instance will use the socket descriptor for reading (until
+ * it gets a file and not after) but will not close the socket, even
+ * when the instance is destroyed (the application must do that).
+ * Return NULL on error.
+ *
+ * Provided that httpread_create successfully returns a handle,
+ * the callback fnc is called to handle httpread_event events.
+ * The caller should do destroy on any errors or unknown events.
+ *
+ * Pass max_bytes == 0 to not read body at all (required for e.g.
+ * reply to HEAD request).
+ */
+struct httpread * httpread_create(
+ int sd, /* descriptor of TCP socket to read from */
+ void (*cb)(struct httpread *handle, void *cookie,
+ enum httpread_event e), /* call on event */
+ void *cookie, /* pass to callback */
+ int max_bytes, /* maximum file size else abort it */
+ int timeout_seconds /* 0; or total duration timeout period */
+ );
+
+/* httpread_hdr_type_get -- When file is ready, returns header type.
+ */
+enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h);
+
+
+/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
+ * or possibly NULL (which would be an error).
+ */
+char *httpread_uri_get(struct httpread *h);
+
+/* httpread_reply_code_get -- When reply is ready, returns reply code */
+int httpread_reply_code_get(struct httpread *h);
+
+
+/* httpread_length_get -- When file is ready, returns file length. */
+int httpread_length_get(struct httpread *h);
+
+/* httpread_data_get -- When file is ready, returns file content
+ * with null byte appened.
+ * Might return NULL in some error condition.
+ */
+void * httpread_data_get(struct httpread *h);
+
+/* httpread_hdr_get -- When file is ready, returns header content
+ * with null byte appended.
+ * Might return NULL in some error condition.
+ */
+char * httpread_hdr_get(struct httpread *h);
+
+/* httpread_hdr_line_get -- When file is ready, returns pointer
+ * to line within header content matching the given tag
+ * (after the tag itself and any spaces/tabs).
+ *
+ * The tag should end with a colon for reliable matching.
+ *
+ * If not found, returns NULL;
+ */
+char * httpread_hdr_line_get(struct httpread *h, const char *tag);
+
+#endif /* HTTPREAD_H */
Modified: wpasupplicant/branches/upstream/current/src/wps/wps.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps.c (original)
+++ wpasupplicant/branches/upstream/current/src/wps/wps.c Sun Feb 15 19:38:55 2009
@@ -186,7 +186,7 @@
/**
- * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PIN
+ * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
* @msg: WPS IE contents from Beacon or Probe Response frame
* Returns: 1 if PIN Registrar is active, 0 if not
*/
@@ -202,9 +202,13 @@
* Device Password ID here.
*/
- if (wps_parse_msg(msg, &attr) < 0 ||
- !attr.selected_registrar || *attr.selected_registrar == 0 ||
- !attr.dev_password_id ||
+ if (wps_parse_msg(msg, &attr) < 0)
+ return 0;
+
+ if (!attr.selected_registrar || *attr.selected_registrar == 0)
+ return 0;
+
+ if (attr.dev_password_id != NULL &&
WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
return 0;
@@ -316,3 +320,16 @@
return ie;
}
+
+
+void wps_free_pending_msgs(struct upnp_pending_message *msgs)
+{
+ struct upnp_pending_message *p, *prev;
+ p = msgs;
+ while (p) {
+ prev = p;
+ p = p->next;
+ wpabuf_free(prev->msg);
+ os_free(prev);
+ }
+}
Modified: wpasupplicant/branches/upstream/current/src/wps/wps.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps.h (original)
+++ wpasupplicant/branches/upstream/current/src/wps/wps.h Sun Feb 15 19:38:55 2009
@@ -21,6 +21,7 @@
* enum wsc_op_code - EAP-WSC OP-Code values
*/
enum wsc_op_code {
+ WSC_UPnP = 0 /* No OP Code in UPnP transport */,
WSC_Start = 0x01,
WSC_ACK = 0x02,
WSC_NACK = 0x03,
@@ -30,6 +31,7 @@
};
struct wps_registrar;
+struct upnp_wps_device_sm;
/**
* struct wps_credential - WPS Credential
@@ -41,6 +43,9 @@
* @key: Key
* @key_len: Key length in octets
* @mac_addr: MAC address of the peer
+ * @cred_attr: Unparsed Credential attribute data (used only in cred_cb());
+ * this may be %NULL, if not used
+ * @cred_attr_len: Length of cred_attr in octets
*/
struct wps_credential {
u8 ssid[32];
@@ -51,6 +56,8 @@
u8 key[64];
size_t key_len;
u8 mac_addr[ETH_ALEN];
+ const u8 *cred_attr;
+ size_t cred_attr_len;
};
/**
@@ -137,7 +144,13 @@
/**
* WPS_FAILURE - Processing failed
*/
- WPS_FAILURE
+ WPS_FAILURE,
+
+ /**
+ * WPS_PENDING - Processing continues, but waiting for an external
+ * event (e.g., UPnP message from an external Registrar)
+ */
+ WPS_PENDING
};
enum wps_process_res wps_process_msg(struct wps_data *wps,
enum wsc_op_code op_code,
@@ -201,9 +214,58 @@
const struct wps_device_data *dev);
/**
+ * reg_success_cb - Callback for reporting successful registration
+ * @ctx: Higher layer context data (cb_ctx)
+ * @mac_addr: MAC address of the Enrollee
+ * @uuid_e: UUID-E of the Enrollee
+ *
+ * This callback is called whenever an Enrollee completes registration
+ * successfully.
+ */
+ void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
+ const u8 *uuid_e);
+
+ /**
* cb_ctx: Higher layer context data for Registrar callbacks
*/
void *cb_ctx;
+
+ /**
+ * skip_cred_build: Do not build credential
+ *
+ * This option can be used to disable internal code that builds
+ * Credential attribute into M8 based on the current network
+ * configuration and Enrollee capabilities. The extra_cred data will
+ * then be used as the Credential(s).
+ */
+ int skip_cred_build;
+
+ /**
+ * extra_cred: Additional Credential attribute(s)
+ *
+ * This optional data (set to %NULL to disable) can be used to add
+ * Credential attribute(s) for other networks into M8. If
+ * skip_cred_build is set, this will also override the automatically
+ * generated Credential attribute.
+ */
+ const u8 *extra_cred;
+
+ /**
+ * extra_cred_len: Length of extra_cred in octets
+ */
+ size_t extra_cred_len;
+
+ /**
+ * disable_auto_conf - Disable auto-configuration on first registration
+ *
+ * By default, the AP that is started in not configured state will
+ * generate a random PSK and move to configured state when the first
+ * registration protocol run is completed successfully. This option can
+ * be used to disable this functionality and leave it up to an external
+ * program to take care of configuration. This requires the extra_cred
+ * to be set with a suitable Credential and skip_cred_build being used.
+ */
+ int disable_auto_conf;
};
@@ -224,7 +286,12 @@
/**
* WPS_EV_SUCCESS - Registration succeeded
*/
- WPS_EV_SUCCESS
+ WPS_EV_SUCCESS,
+
+ /**
+ * WPS_EV_PWD_AUTH_FAIL - Password authentication failed
+ */
+ WPS_EV_PWD_AUTH_FAIL
};
/**
@@ -258,6 +325,25 @@
struct wps_event_fail {
int msg;
} fail;
+
+ struct wps_event_pwd_auth_fail {
+ int enrollee;
+ int part;
+ } pwd_auth_fail;
+};
+
+/**
+ * struct upnp_pending_message - Pending PutWLANResponse messages
+ * @next: Pointer to next pending message or %NULL
+ * @addr: NewWLANEventMAC
+ * @msg: NewMessage
+ * @type: Message Type
+ */
+struct upnp_pending_message {
+ struct upnp_pending_message *next;
+ u8 addr[ETH_ALEN];
+ struct wpabuf *msg;
+ enum wps_msg_type type;
};
/**
@@ -343,6 +429,44 @@
size_t network_key_len;
/**
+ * ap_settings - AP Settings override for M7 (only used at AP)
+ *
+ * If %NULL, AP Settings attributes will be generated based on the
+ * current network configuration.
+ */
+ u8 *ap_settings;
+
+ /**
+ * ap_settings_len - Length of ap_settings in octets
+ */
+ size_t ap_settings_len;
+
+ /**
+ * friendly_name - Friendly Name (required for UPnP)
+ */
+ char *friendly_name;
+
+ /**
+ * manufacturer_url - Manufacturer URL (optional for UPnP)
+ */
+ char *manufacturer_url;
+
+ /**
+ * model_description - Model Description (recommended for UPnP)
+ */
+ char *model_description;
+
+ /**
+ * model_url - Model URL (optional for UPnP)
+ */
+ char *model_url;
+
+ /**
+ * upc - Universal Product Code (optional for UPnP)
+ */
+ char *upc;
+
+ /**
* cred_cb - Callback to notify that new Credentials were received
* @ctx: Higher layer context data (cb_ctx)
* @cred: The received Credential
@@ -363,6 +487,11 @@
* cb_ctx: Higher layer context data for callbacks
*/
void *cb_ctx;
+
+ struct upnp_wps_device_sm *wps_upnp;
+
+ /* Pending messages from UPnP PutWLANResponse */
+ struct upnp_pending_message *upnp_msgs;
};
@@ -377,9 +506,13 @@
int wps_registrar_button_pushed(struct wps_registrar *reg);
void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
const struct wpabuf *wps_data);
+int wps_registrar_update_ie(struct wps_registrar *reg);
+int wps_registrar_set_selected_registrar(struct wps_registrar *reg,
+ const struct wpabuf *msg);
unsigned int wps_pin_checksum(unsigned int pin);
unsigned int wps_pin_valid(unsigned int pin);
unsigned int wps_generate_pin(void);
+void wps_free_pending_msgs(struct upnp_pending_message *msgs);
#endif /* WPS_H */
Modified: wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c (original)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c Sun Feb 15 19:38:55 2009
@@ -27,6 +27,7 @@
wpa_printf(MSG_DEBUG, "WPS: * Public Key");
pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), &wps->dh_privkey);
+ pubkey = wpabuf_zeropad(pubkey, 192);
if (pubkey == NULL) {
wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
"Diffie-Hellman handshake");
Modified: wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c (original)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c Sun Feb 15 19:38:55 2009
@@ -254,6 +254,23 @@
wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
return 0;
+}
+
+
+static void wps_workaround_cred_key(struct wps_credential *cred)
+{
+ if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
+ cred->key_len > 8 && cred->key_len < 64 &&
+ cred->key[cred->key_len - 1] == 0) {
+ /*
+ * A deployed external registrar is known to encode ASCII
+ * passphrases incorrectly. Remove the extra NULL termination
+ * to fix the encoding.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL "
+ "termination from ASCII passphrase");
+ cred->key_len--;
+ }
}
@@ -279,6 +296,8 @@
wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
return -1;
+ wps_workaround_cred_key(cred);
+
return 0;
}
@@ -298,5 +317,7 @@
wps_process_cred_mac_addr(cred, attr->mac_addr))
return -1;
- return 0;
-}
+ wps_workaround_cred_key(cred);
+
+ return 0;
+}
Modified: wpasupplicant/branches/upstream/current/src/wps/wps_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_common.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_common.c Sun Feb 15 19:38:55 2009
@@ -82,6 +82,7 @@
dh_shared = dh_derive_shared(pubkey, wps->dh_privkey,
dh_groups_get(WPS_DH_GROUP));
+ dh_shared = wpabuf_zeropad(dh_shared, 192);
if (dh_shared == NULL) {
wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
return -1;
@@ -320,3 +321,17 @@
wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
}
+
+
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
+{
+ union wps_event_data data;
+
+ if (wps->event_cb == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.pwd_auth_fail.enrollee = enrollee;
+ data.pwd_auth_fail.part = part;
+ wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
+}
Modified: wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c (original)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c Sun Feb 15 19:38:55 2009
@@ -32,10 +32,16 @@
static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
{
- wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State");
+ u8 state;
+ if (wps->wps->ap)
+ state = wps->wps->wps_state;
+ else
+ state = WPS_STATE_NOT_CONFIGURED;
+ wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)",
+ state);
wpabuf_put_be16(msg, ATTR_WPS_STATE);
wpabuf_put_be16(msg, 1);
- wpabuf_put_u8(msg, WPS_STATE_CONFIGURED);
+ wpabuf_put_u8(msg, WPS_STATE_NOT_CONFIGURED);
return 0;
}
@@ -268,17 +274,34 @@
}
+static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
+{
+ if (wps->wps->ap_settings) {
+ wpa_printf(MSG_DEBUG, "WPS: * AP Settings (pre-configured)");
+ wpabuf_put_data(plain, wps->wps->ap_settings,
+ wps->wps->ap_settings_len);
+ return 0;
+ }
+
+ return wps_build_cred_ssid(wps, plain) ||
+ wps_build_cred_mac_addr(wps, plain) ||
+ wps_build_cred_auth_type(wps, plain) ||
+ wps_build_cred_encr_type(wps, plain) ||
+ wps_build_cred_network_key(wps, plain);
+}
+
+
static struct wpabuf * wps_build_m7(struct wps_data *wps)
{
struct wpabuf *msg, *plain;
wpa_printf(MSG_DEBUG, "WPS: Building Message M7");
- plain = wpabuf_alloc(500);
+ plain = wpabuf_alloc(500 + wps->wps->ap_settings_len);
if (plain == NULL)
return NULL;
- msg = wpabuf_alloc(1000);
+ msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len);
if (msg == NULL) {
wpabuf_free(plain);
return NULL;
@@ -288,12 +311,7 @@
wps_build_msg_type(msg, WPS_M7) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_e_snonce2(wps, plain) ||
- (wps->wps->ap &&
- (wps_build_cred_ssid(wps, plain) ||
- wps_build_cred_mac_addr(wps, plain) ||
- wps_build_cred_auth_type(wps, plain) ||
- wps_build_cred_encr_type(wps, plain) ||
- wps_build_cred_network_key(wps, plain))) ||
+ (wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
wps_build_authenticator(wps, msg)) {
@@ -568,6 +586,7 @@
wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+ wps_pwd_auth_fail_event(wps->wps, 1, 1);
return -1;
}
@@ -607,6 +626,7 @@
wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+ wps_pwd_auth_fail_event(wps->wps, 1, 2);
return -1;
}
@@ -630,8 +650,13 @@
wps_process_cred(&attr, &wps->cred))
return -1;
- if (wps->wps->cred_cb)
+ if (wps->wps->cred_cb) {
+ wps->cred.cred_attr = cred - 4;
+ wps->cred.cred_attr_len = cred_len + 4;
wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+ wps->cred.cred_attr = NULL;
+ wps->cred.cred_attr_len = 0;
+ }
return 0;
}
@@ -661,7 +686,8 @@
static int wps_process_ap_settings_e(struct wps_data *wps,
- struct wps_parse_attr *attr)
+ struct wps_parse_attr *attr,
+ struct wpabuf *attrs)
{
struct wps_credential cred;
@@ -674,8 +700,11 @@
wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
"Registrar");
- if (wps->wps->cred_cb)
+ if (wps->wps->cred_cb) {
+ cred.cred_attr = wpabuf_head(attrs);
+ cred.cred_attr_len = wpabuf_len(attrs);
wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
+ }
return 0;
}
@@ -904,7 +933,7 @@
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_creds(wps, eattr.cred, eattr.cred_len,
eattr.num_cred) ||
- wps_process_ap_settings_e(wps, &eattr)) {
+ wps_process_ap_settings_e(wps, &eattr, decrypted)) {
wpabuf_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
@@ -927,7 +956,7 @@
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
@@ -972,7 +1001,14 @@
return WPS_FAILURE;
}
- if (ret == WPS_CONTINUE) {
+ /*
+ * Save a copy of the last message for Authenticator derivation if we
+ * are continuing. However, skip M2D since it is not authenticated and
+ * neither is the ACK/NACK response frame. This allows the possibly
+ * following M2 to be processed correctly by using the previously sent
+ * M1 in Authenticator derivation.
+ */
+ if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) {
/* Save a copy of the last message for Authenticator derivation
*/
wpabuf_free(wps->last_msg);
@@ -993,7 +1029,7 @@
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
@@ -1045,7 +1081,7 @@
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
@@ -1125,6 +1161,7 @@
switch (op_code) {
case WSC_MSG:
+ case WSC_UPnP:
return wps_process_wsc_msg(wps, msg);
case WSC_ACK:
return wps_process_wsc_ack(wps, msg);
Modified: wpasupplicant/branches/upstream/current/src/wps/wps_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_i.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_i.h Sun Feb 15 19:38:55 2009
@@ -101,6 +101,8 @@
* config_error - Configuration Error value to be used in NACK
*/
u16 config_error;
+
+ int ext_reg;
};
@@ -187,6 +189,7 @@
size_t encr_len);
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg);
void wps_success_event(struct wps_context *wps);
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
/* wps_attr_parse.c */
int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
@@ -235,4 +238,11 @@
enum wsc_op_code op_code,
const struct wpabuf *msg);
+
+static inline int wps_version_supported(const u8 *version)
+{
+ /* Require major version match, but allow minor version differences */
+ return version && (*version & 0xf0) == (WPS_VERSION & 0xf0);
+}
+
#endif /* WPS_I_H */
Modified: wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c (original)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c Sun Feb 15 19:38:55 2009
@@ -21,6 +21,7 @@
#include "eloop.h"
#include "wps_i.h"
#include "wps_dev_attr.h"
+#include "wps_upnp.h"
struct wps_uuid_pin {
@@ -85,15 +86,25 @@
const u8 *probe_resp_ie, size_t probe_resp_ie_len);
void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
const struct wps_device_data *dev);
+ void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
+ const u8 *uuid_e);
void *cb_ctx;
struct wps_uuid_pin *pins;
struct wps_pbc_session *pbc_sessions;
+
+ int skip_cred_build;
+ struct wpabuf *extra_cred;
+ int disable_auto_conf;
+ int sel_reg_dev_password_id_override;
+ int sel_reg_config_methods_override;
};
static int wps_set_ie(struct wps_registrar *reg);
static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wps_registrar_set_selected_timeout(void *eloop_ctx,
+ void *timeout_ctx);
static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
@@ -205,6 +216,31 @@
}
+#ifdef CONFIG_WPS_UPNP
+static void wps_registrar_free_pending_m2(struct wps_context *wps)
+{
+ struct upnp_pending_message *p, *p2, *prev = NULL;
+ p = wps->upnp_msgs;
+ while (p) {
+ if (p->type == WPS_M2 || p->type == WPS_M2D) {
+ if (prev == NULL)
+ wps->upnp_msgs = p->next;
+ else
+ prev->next = p->next;
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D");
+ p2 = p;
+ p = p->next;
+ wpabuf_free(p2->msg);
+ os_free(p2);
+ continue;
+ }
+ prev = p;
+ p = p->next;
+ }
+}
+#endif /* CONFIG_WPS_UPNP */
+
+
static int wps_build_ap_setup_locked(struct wps_context *wps,
struct wpabuf *msg)
{
@@ -237,6 +273,8 @@
u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
if (!reg->selected_registrar)
return 0;
+ if (reg->sel_reg_dev_password_id_override >= 0)
+ id = reg->sel_reg_dev_password_id_override;
wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id);
wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
wpabuf_put_be16(msg, 2);
@@ -254,6 +292,8 @@
methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
if (reg->pbc)
methods |= WPS_CONFIG_PUSHBUTTON;
+ if (reg->sel_reg_config_methods_override >= 0)
+ methods = reg->sel_reg_config_methods_override;
wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar Config Methods (%x)",
methods);
wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
@@ -322,7 +362,20 @@
reg->new_psk_cb = cfg->new_psk_cb;
reg->set_ie_cb = cfg->set_ie_cb;
reg->pin_needed_cb = cfg->pin_needed_cb;
+ reg->reg_success_cb = cfg->reg_success_cb;
reg->cb_ctx = cfg->cb_ctx;
+ reg->skip_cred_build = cfg->skip_cred_build;
+ if (cfg->extra_cred) {
+ reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred,
+ cfg->extra_cred_len);
+ if (reg->extra_cred == NULL) {
+ os_free(reg);
+ return NULL;
+ }
+ }
+ reg->disable_auto_conf = cfg->disable_auto_conf;
+ reg->sel_reg_dev_password_id_override = -1;
+ reg->sel_reg_config_methods_override = -1;
if (wps_set_ie(reg)) {
wps_registrar_deinit(reg);
@@ -342,8 +395,10 @@
if (reg == NULL)
return;
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
+ eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
wps_free_pins(reg->pins);
wps_free_pbc_sessions(reg->pbc_sessions);
+ wpabuf_free(reg->extra_cred);
os_free(reg);
}
@@ -573,8 +628,9 @@
"WPS: Probe Request with WPS data received",
wps_data);
- if (wps_parse_msg(wps_data, &attr) < 0 ||
- attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (wps_parse_msg(wps_data, &attr) < 0)
+ return;
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported ProbeReq WPS IE "
"version 0x%x", attr.version ? *attr.version : 0);
return;
@@ -614,6 +670,16 @@
return;
reg->pin_needed_cb(reg->cb_ctx, uuid_e, dev);
+}
+
+
+static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,
+ const u8 *uuid_e)
+{
+ if (reg->reg_success_cb == NULL)
+ return;
+
+ reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e);
}
@@ -838,7 +904,7 @@
wpa_printf(MSG_DEBUG, "WPS: * Network Index");
wpabuf_put_be16(msg, ATTR_NETWORK_INDEX);
wpabuf_put_be16(msg, 1);
- wpabuf_put_u8(msg, 0);
+ wpabuf_put_u8(msg, 1);
return 0;
}
@@ -892,7 +958,8 @@
static int wps_build_cred_mac_addr(struct wpabuf *msg,
struct wps_credential *cred)
{
- wpa_printf(MSG_DEBUG, "WPS: * MAC Address");
+ wpa_printf(MSG_DEBUG, "WPS: * MAC Address (" MACSTR ")",
+ MAC2STR(cred->mac_addr));
wpabuf_put_be16(msg, ATTR_MAC_ADDR);
wpabuf_put_be16(msg, ETH_ALEN);
wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN);
@@ -917,6 +984,9 @@
static int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
{
struct wpabuf *cred;
+
+ if (wps->wps->registrar->skip_cred_build)
+ goto skip_cred_build;
wpa_printf(MSG_DEBUG, "WPS: * Credential");
os_memset(&wps->cred, 0, sizeof(wps->cred));
@@ -963,9 +1033,11 @@
}
}
wps->cred.encr_type = wps->encr_type;
- os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
-
- if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap) {
+ /* Set MAC address in the Credential to be the AP's address (BSSID) */
+ os_memcpy(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN);
+
+ if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap &&
+ !wps->wps->registrar->disable_auto_conf) {
u8 r[16];
/* Generate a random passphrase */
if (os_get_random(r, sizeof(r)) < 0)
@@ -1021,6 +1093,12 @@
wpabuf_put_buf(msg, cred);
wpabuf_free(cred);
+skip_cred_build:
+ if (wps->wps->registrar->extra_cred) {
+ wpa_printf(MSG_DEBUG, "WPS: * Credential (pre-configured)");
+ wpabuf_put_buf(msg, wps->wps->registrar->extra_cred);
+ }
+
return 0;
}
@@ -1066,7 +1144,7 @@
wps_build_rf_bands(&wps->wps->dev, msg) ||
wps_build_assoc_state(wps, msg) ||
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
- wps_build_dev_password_id(msg, DEV_PW_DEFAULT) ||
+ wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_os_version(&wps->wps->dev, msg) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(msg);
@@ -1270,6 +1348,39 @@
enum wsc_op_code *op_code)
{
struct wpabuf *msg;
+
+#ifdef CONFIG_WPS_UPNP
+ if (wps->wps->wps_upnp) {
+ struct upnp_pending_message *p, *prev = NULL;
+ if (wps->ext_reg > 1)
+ wps_registrar_free_pending_m2(wps->wps);
+ p = wps->wps->upnp_msgs;
+ /* TODO: check pending message MAC address */
+ while (p && p->next) {
+ prev = p;
+ p = p->next;
+ }
+ if (p) {
+ wpa_printf(MSG_DEBUG, "WPS: Use pending message from "
+ "UPnP");
+ if (prev)
+ prev->next = NULL;
+ else
+ wps->wps->upnp_msgs = NULL;
+ msg = p->msg;
+ os_free(p);
+ *op_code = WSC_MSG;
+ if (wps->ext_reg == 0)
+ wps->ext_reg = 1;
+ return msg;
+ }
+ }
+ if (wps->ext_reg) {
+ wpa_printf(MSG_DEBUG, "WPS: Using external Registrar, but no "
+ "pending message available");
+ return NULL;
+ }
+#endif /* CONFIG_WPS_UPNP */
switch (wps->state) {
case SEND_M2:
@@ -1437,6 +1548,7 @@
wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+ wps_pwd_auth_fail_event(wps->wps, 0, 1);
return -1;
}
@@ -1477,6 +1589,7 @@
"not match with the pre-committed value");
wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+ wps_pwd_auth_fail_event(wps->wps, 0, 2);
return -1;
}
@@ -1864,7 +1977,7 @@
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
@@ -1885,6 +1998,17 @@
switch (*attr.msg_type) {
case WPS_M1:
+#ifdef CONFIG_WPS_UPNP
+ if (wps->wps->wps_upnp && attr.mac_addr) {
+ /* Remove old pending messages when starting new run */
+ wps_free_pending_msgs(wps->wps->upnp_msgs);
+ wps->wps->upnp_msgs = NULL;
+
+ upnp_wps_device_send_wlan_event(
+ wps->wps->wps_upnp, attr.mac_addr,
+ UPNP_WPS_WLANEVENT_TYPE_EAP, msg);
+ }
+#endif /* CONFIG_WPS_UPNP */
ret = wps_process_m1(wps, &attr);
break;
case WPS_M3:
@@ -1929,7 +2053,7 @@
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
@@ -1945,6 +2069,17 @@
*attr.msg_type);
return WPS_FAILURE;
}
+
+#ifdef CONFIG_WPS_UPNP
+ if (wps->wps->wps_upnp && wps->ext_reg && wps->state == RECV_M2D_ACK &&
+ upnp_wps_subscribers(wps->wps->wps_upnp)) {
+ if (wps->wps->upnp_msgs)
+ return WPS_CONTINUE;
+ wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
+ "external Registrar");
+ return WPS_PENDING;
+ }
+#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
@@ -1960,8 +2095,18 @@
}
if (wps->state == RECV_M2D_ACK) {
- /* TODO: support for multiple registrars and sending of
- * multiple M2/M2D messages */
+#ifdef CONFIG_WPS_UPNP
+ if (wps->wps->wps_upnp &&
+ upnp_wps_subscribers(wps->wps->wps_upnp)) {
+ if (wps->wps->upnp_msgs)
+ return WPS_CONTINUE;
+ if (wps->ext_reg == 0)
+ wps->ext_reg = 1;
+ wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
+ "external Registrar");
+ return WPS_PENDING;
+ }
+#endif /* CONFIG_WPS_UPNP */
wpa_printf(MSG_DEBUG, "WPS: No more registrars available - "
"terminate negotiation");
@@ -1985,7 +2130,7 @@
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
@@ -2001,6 +2146,14 @@
*attr.msg_type);
return WPS_FAILURE;
}
+
+#ifdef CONFIG_WPS_UPNP
+ if (wps->wps->wps_upnp && wps->ext_reg) {
+ wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
+ "Registrar terminated by the Enrollee");
+ return WPS_FAILURE;
+ }
+#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
@@ -2052,7 +2205,8 @@
wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done");
- if (wps->state != RECV_DONE) {
+ if (wps->state != RECV_DONE &&
+ (!wps->wps->wps_upnp || !wps->ext_reg)) {
wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
"receiving WSC_Done", wps->state);
return WPS_FAILURE;
@@ -2061,7 +2215,7 @@
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
@@ -2077,6 +2231,14 @@
*attr.msg_type);
return WPS_FAILURE;
}
+
+#ifdef CONFIG_WPS_UPNP
+ if (wps->wps->wps_upnp && wps->ext_reg) {
+ wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
+ "Registrar completed successfully");
+ return WPS_DONE;
+ }
+#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
@@ -2094,7 +2256,7 @@
wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully");
if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk &&
- wps->wps->ap) {
+ wps->wps->ap && !wps->wps->registrar->disable_auto_conf) {
struct wps_credential cred;
wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
@@ -2136,6 +2298,8 @@
wps->new_psk = NULL;
}
+ wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e);
+
if (wps->pbc) {
wps_registrar_remove_pbc_session(wps->wps->registrar,
wps->mac_addr_e, wps->uuid_e);
@@ -2157,6 +2321,39 @@
wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
"op_code=%d)",
(unsigned long) wpabuf_len(msg), op_code);
+
+#ifdef CONFIG_WPS_UPNP
+ if (wps->wps->wps_upnp && op_code == WSC_MSG && wps->ext_reg == 1) {
+ struct wps_parse_attr attr;
+ if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type &&
+ *attr.msg_type == WPS_M3)
+ wps->ext_reg = 2; /* past M2/M2D phase */
+ }
+ if (wps->ext_reg > 1)
+ wps_registrar_free_pending_m2(wps->wps);
+ if (wps->wps->wps_upnp && wps->ext_reg &&
+ wps->wps->upnp_msgs == NULL &&
+ (op_code == WSC_MSG || op_code == WSC_Done)) {
+ struct wps_parse_attr attr;
+ int type;
+ if (wps_parse_msg(msg, &attr) < 0 || attr.msg_type == NULL)
+ type = -1;
+ else
+ type = *attr.msg_type;
+ wpa_printf(MSG_DEBUG, "WPS: Sending received message (type %d)"
+ " to external Registrar for processing", type);
+ upnp_wps_device_send_wlan_event(wps->wps->wps_upnp,
+ wps->mac_addr_e,
+ UPNP_WPS_WLANEVENT_TYPE_EAP,
+ msg);
+ if (op_code == WSC_MSG)
+ return WPS_PENDING;
+ } else if (wps->wps->wps_upnp && wps->ext_reg && op_code == WSC_MSG) {
+ wpa_printf(MSG_DEBUG, "WPS: Skip internal processing - using "
+ "external Registrar");
+ return WPS_CONTINUE;
+ }
+#endif /* CONFIG_WPS_UPNP */
switch (op_code) {
case WSC_MSG:
@@ -2177,3 +2374,75 @@
return WPS_FAILURE;
}
}
+
+
+int wps_registrar_update_ie(struct wps_registrar *reg)
+{
+ return wps_set_ie(reg);
+}
+
+
+static void wps_registrar_set_selected_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wps_registrar *reg = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar timed out - "
+ "unselect Registrar");
+ reg->selected_registrar = 0;
+ reg->pbc = 0;
+ reg->sel_reg_dev_password_id_override = -1;
+ reg->sel_reg_config_methods_override = -1;
+ wps_set_ie(reg);
+}
+
+
+/**
+ * wps_registrar_set_selected_registrar - Notification of SetSelectedRegistrar
+ * @reg: Registrar data from wps_registrar_init()
+ * @msg: Received message from SetSelectedRegistrar
+ * @msg_len: Length of msg in octets
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when an AP receives a SetSelectedRegistrar UPnP
+ * message.
+ */
+int wps_registrar_set_selected_registrar(struct wps_registrar *reg,
+ const struct wpabuf *msg)
+{
+ struct wps_parse_attr attr;
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "WPS: SetSelectedRegistrar attributes",
+ msg);
+
+ if (wps_parse_msg(msg, &attr) < 0)
+ return -1;
+ if (!wps_version_supported(attr.version)) {
+ wpa_printf(MSG_DEBUG, "WPS: Unsupported SetSelectedRegistrar "
+ "version 0x%x", attr.version ? *attr.version : 0);
+ return -1;
+ }
+
+ if (attr.selected_registrar == NULL ||
+ *attr.selected_registrar == 0) {
+ wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable "
+ "Selected Registrar");
+ eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg,
+ NULL);
+ wps_registrar_set_selected_timeout(reg, NULL);
+ return 0;
+ }
+
+ reg->selected_registrar = 1;
+ reg->sel_reg_dev_password_id_override = attr.dev_password_id ?
+ WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT;
+ reg->sel_reg_config_methods_override = attr.sel_reg_config_methods ?
+ WPA_GET_BE16(attr.sel_reg_config_methods) : -1;
+ wps_set_ie(reg);
+
+ eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+ eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
+ wps_registrar_set_selected_timeout,
+ reg, NULL);
+ return 0;
+}
Added: wpasupplicant/branches/upstream/current/src/wps/wps_upnp.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_upnp.c?rev=1324&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_upnp.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_upnp.c Sun Feb 15 19:38:55 2009
@@ -1,0 +1,1056 @@
+/*
+ * UPnP WPS Device
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See below for more details on licensing and code history.
+ */
+
+/*
+ * This has been greatly stripped down from the original file
+ * (upnp_wps_device.c) by Ted Merrill, Atheros Communications
+ * in order to eliminate use of the bulky libupnp library etc.
+ *
+ * History:
+ * upnp_wps_device.c is/was a shim layer between wps_opt_upnp.c and
+ * the libupnp library.
+ * The layering (by Sony) was well done; only a very minor modification
+ * to API of upnp_wps_device.c was required.
+ * libupnp was found to be undesirable because:
+ * -- It consumed too much code and data space
+ * -- It uses multiple threads, making debugging more difficult
+ * and possibly reducing reliability.
+ * -- It uses static variables and only supports one instance.
+ * The shim and libupnp are here replaced by special code written
+ * specifically for the needs of hostapd.
+ * Various shortcuts can and are taken to keep the code size small.
+ * Generally, execution time is not as crucial.
+ *
+ * BUGS:
+ * -- UPnP requires that we be able to resolve domain names.
+ * While uncommon, if we have to do it then it will stall the entire
+ * hostapd program, which is bad.
+ * This is because we use the standard linux getaddrinfo() function
+ * which is syncronous.
+ * An asyncronous solution would be to use the free "ares" library.
+ * -- Does not have a robust output buffering scheme. Uses a single
+ * fixed size output buffer per TCP/HTTP connection, with possible (although
+ * unlikely) possibility of overflow and likely excessive use of RAM.
+ * A better solution would be to write the HTTP output as a buffered stream,
+ * using chunking: (handle header specially, then) generate data with
+ * a printf-like function into a buffer, catching buffer full condition,
+ * then send it out surrounded by http chunking.
+ * -- There is some code that could be separated out into the common
+ * library to be shared with wpa_supplicant.
+ * -- Needs renaming with module prefix to avoid polluting the debugger
+ * namespace and causing possible collisions with other static fncs
+ * and structure declarations when using the debugger.
+ * -- Just what should be in the first event message sent after subscription
+ * for the WLANEvent field? If i pass it empty, Vista replies with OK
+ * but apparently barfs on the message.
+ * -- The http error code generation is pretty bogus, hopefully noone cares.
+ *
+ * Author: Ted Merrill, Atheros Communications, based upon earlier work
+ * as explained above and below.
+ *
+ * Copyright:
+ * Copyright 2008 Atheros Communications.
+ *
+ * The original header (of upnp_wps_device.c) reads:
+ *
+ * Copyright (c) 2006-2007 Sony Corporation. All Rights Reserved.
+ *
+ * File Name: upnp_wps_device.c
+ * Description: EAP-WPS UPnP device source
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Sony Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions from Intel libupnp files, e.g. genlib/net/http/httpreadwrite.c
+ * typical header:
+ *
+ * Copyright (c) 2000-2003 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Overview of WPS over UPnP:
+ *
+ * UPnP is a protocol that allows devices to discover each other and control
+ * each other. In UPnP terminology, a device is either a "device" (a server
+ * that provides information about itself and allows itself to be controlled)
+ * or a "control point" (a client that controls "devices") or possibly both.
+ * This file implements a UPnP "device".
+ *
+ * For us, we use mostly basic UPnP discovery, but the control part of interest
+ * is WPS carried via UPnP messages. There is quite a bit of basic UPnP
+ * discovery to do before we can get to WPS, however.
+ *
+ * UPnP discovery begins with "devices" send out multicast UDP packets to a
+ * certain fixed multicast IP address and port, and "control points" sending
+ * out other such UDP packets.
+ *
+ * The packets sent by devices are NOTIFY packets (not to be confused with TCP
+ * NOTIFY packets that are used later) and those sent by control points are
+ * M-SEARCH packets. These packets contain a simple HTTP style header. The
+ * packets are sent redundantly to get around packet loss. Devices respond to
+ * M-SEARCH packets with HTTP-like UDP packets containing HTTP/1.1 200 OK
+ * messages, which give similar information as the UDP NOTIFY packets.
+ *
+ * The above UDP packets advertise the (arbitrary) TCP ports that the
+ * respective parties will listen to. The control point can then do a HTTP
+ * SUBSCRIBE (something like an HTTP PUT) after which the device can do a
+ * separate HTTP NOTIFY (also like an HTTP PUT) to do event messaging.
+ *
+ * The control point will also do HTTP GET of the "device file" listed in the
+ * original UDP information from the device (see UPNP_WPS_DEVICE_XML_FILE
+ * data), and based on this will do additional GETs... HTTP POSTs are done to
+ * cause an action.
+ *
+ * Beyond some basic information in HTTP headers, additional information is in
+ * the HTTP bodies, in a format set by the SOAP and XML standards, a markup
+ * language related to HTML used for web pages. This language is intended to
+ * provide the ultimate in self-documentation by providing a universal
+ * namespace based on pseudo-URLs called URIs. Note that although a URI looks
+ * like a URL (a web address), they are never accessed as such but are used
+ * only as identifiers.
+ *
+ * The POST of a GetDeviceInfo gets information similar to what might be
+ * obtained from a probe request or response on Wi-Fi. WPS messages M1-M8
+ * are passed via a POST of a PutMessage; the M1-M8 WPS messages are converted
+ * to a bin64 ascii representation for encapsulation. When proxying messages,
+ * WLANEvent and PutWLANResponse are used.
+ *
+ * This of course glosses over a lot of details.
+ */
+
+#include "includes.h"
+
+#include <assert.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "uuid.h"
+#include "base64.h"
+#include "wps.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+
+/*
+ * UPnP allows a client ("control point") to send a server like us ("device")
+ * a domain name for registration, and we are supposed to resolve it. This is
+ * bad because, using the standard Linux library, we will stall the entire
+ * hostapd waiting for resolution.
+ *
+ * The "correct" solution would be to use an event driven library for domain
+ * name resolution such as "ares". However, this would increase code size
+ * further. Since it is unlikely that we'll actually see such domain names, we
+ * can just refuse to accept them.
+ */
+#define NO_DOMAIN_NAME_RESOLUTION 1 /* 1 to allow only dotted ip addresses */
+
+
+/*
+ * UPnP does not scale well. If we were in a room with thousands of control
+ * points then potentially we could be expected to handle subscriptions for
+ * each of them, which would exhaust our memory. So we must set a limit. In
+ * practice we are unlikely to see more than one or two.
+ */
+#define MAX_SUBSCRIPTIONS 4 /* how many subscribing clients we handle */
+#define MAX_ADDR_PER_SUBSCRIPTION 8
+
+
+/* Write the current date/time per RFC */
+void format_date(struct wpabuf *buf)
+{
+ const char *weekday_str = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
+ const char *month_str = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0"
+ "Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
+ struct tm *date;
+ time_t t;
+
+ t = time(NULL);
+ date = gmtime(&t);
+ wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT",
+ &weekday_str[date->tm_wday * 4], date->tm_mday,
+ &month_str[date->tm_mon * 4], date->tm_year + 1900,
+ date->tm_hour, date->tm_min, date->tm_sec);
+}
+
+
+/***************************************************************************
+ * UUIDs (unique identifiers)
+ *
+ * These are supposed to be unique in all the world.
+ * Sometimes permanent ones are used, sometimes temporary ones
+ * based on random numbers... there are different rules for valid content
+ * of different types.
+ * Each uuid is 16 bytes long.
+ **************************************************************************/
+
+/* uuid_make -- construct a random UUID
+ * The UPnP documents don't seem to offer any guidelines as to which method to
+ * use for constructing UUIDs for subscriptions. Presumably any method from
+ * rfc4122 is good enough; I've chosen random number method.
+ */
+static void uuid_make(u8 uuid[UUID_LEN])
+{
+ os_get_random(uuid, UUID_LEN);
+
+ /* Replace certain bits as specified in rfc4122 or X.667 */
+ uuid[6] &= 0x0f; uuid[6] |= (4 << 4); /* version 4 == random gen */
+ uuid[8] &= 0x3f; uuid[8] |= 0x80;
+}
+
+
+/*
+ * Subscriber address handling.
+ * Since a subscriber may have an arbitrary number of addresses, we have to
+ * add a bunch of code to handle them.
+ *
+ * Addresses are passed in text, and MAY be domain names instead of the (usual
+ * and expected) dotted IP addresses. Resolving domain names consumes a lot of
+ * resources. Worse, we are currently using the standard Linux getaddrinfo()
+ * which will block the entire program until complete or timeout! The proper
+ * solution would be to use the "ares" library or similar with more state
+ * machine steps etc. or just disable domain name resolution by setting
+ * NO_DOMAIN_NAME_RESOLUTION to 1 at top of this file.
+ */
+
+/* subscr_addr_delete -- delete single unlinked subscriber address
+ * (be sure to unlink first if need be)
+ */
+static void subscr_addr_delete(struct subscr_addr *a)
+{
+ /*
+ * Note: do NOT free domain_and_port or path because they point to
+ * memory within the allocation of "a".
+ */
+ os_free(a);
+}
+
+
+/* subscr_addr_unlink -- unlink subscriber address from linked list */
+static void subscr_addr_unlink(struct subscription *s, struct subscr_addr *a)
+{
+ struct subscr_addr **listp = &s->addr_list;
+ s->n_addr--;
+ a->next->prev = a->prev;
+ a->prev->next = a->next;
+ if (*listp == a) {
+ if (a == a->next) {
+ /* last in queue */
+ *listp = NULL;
+ assert(s->n_addr == 0);
+ } else {
+ *listp = a->next;
+ }
+ }
+}
+
+
+/* subscr_addr_free_all -- unlink and delete list of subscriber addresses. */
+static void subscr_addr_free_all(struct subscription *s)
+{
+ struct subscr_addr **listp = &s->addr_list;
+ struct subscr_addr *a;
+ while ((a = *listp) != NULL) {
+ subscr_addr_unlink(s, a);
+ subscr_addr_delete(a);
+ }
+}
+
+
+/* subscr_addr_link -- add subscriber address to list of addresses */
+static void subscr_addr_link(struct subscription *s, struct subscr_addr *a)
+{
+ struct subscr_addr **listp = &s->addr_list;
+ s->n_addr++;
+ if (*listp == NULL) {
+ *listp = a->next = a->prev = a;
+ } else {
+ a->next = *listp;
+ a->prev = (*listp)->prev;
+ a->prev->next = a;
+ a->next->prev = a;
+ }
+}
+
+
+/* subscr_addr_add_url -- add address(es) for one url to subscription */
+static void subscr_addr_add_url(struct subscription *s, const char *url)
+{
+ int alloc_len;
+ char *scratch_mem = NULL;
+ char *mem;
+ char *domain_and_port;
+ char *delim;
+ char *path;
+ char *domain;
+ int port = 80; /* port to send to (default is port 80) */
+ struct addrinfo hints;
+ struct addrinfo *result = NULL;
+ struct addrinfo *rp;
+ int rerr;
+ struct subscr_addr *a = NULL;
+
+ /* url MUST begin with http: */
+ if (os_strncasecmp(url, "http://", 7))
+ goto fail;
+ url += 7;
+
+ /* allocate memory for the extra stuff we need */
+ alloc_len = (2 * (os_strlen(url) + 1));
+ scratch_mem = os_zalloc(alloc_len);
+ if (scratch_mem == NULL)
+ goto fail;
+ mem = scratch_mem;
+ strcpy(mem, url);
+ domain_and_port = mem;
+ mem += 1 + os_strlen(mem);
+ delim = os_strchr(domain_and_port, '/');
+ if (delim) {
+ *delim++ = 0; /* null terminate domain and port */
+ path = delim;
+ } else {
+ path = domain_and_port + os_strlen(domain_and_port);
+ }
+ domain = mem;
+ strcpy(domain, domain_and_port);
+ delim = strchr(domain, ':');
+ if (delim) {
+ *delim++ = 0; /* null terminate domain */
+ if (isdigit(*delim))
+ port = atol(delim);
+ }
+
+ /*
+ * getaddrinfo does the right thing with dotted decimal notations, or
+ * will resolve domain names. Resolving domain names will unfortunately
+ * hang the entire program until it is resolved or it times out
+ * internal to getaddrinfo; fortunately we think that the use of actual
+ * domain names (vs. dotted decimal notations) should be uncommon.
+ */
+ os_memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET; /* IPv4 */
+ hints.ai_socktype = SOCK_STREAM;
+#if NO_DOMAIN_NAME_RESOLUTION
+ /* Suppress domain name resolutions that would halt
+ * the program for periods of time
+ */
+ hints.ai_flags = AI_NUMERICHOST;
+#else
+ /* Allow domain name resolution. */
+ hints.ai_flags = 0;
+#endif
+ hints.ai_protocol = 0; /* Any protocol? */
+ rerr = getaddrinfo(domain, NULL /* fill in port ourselves */,
+ &hints, &result);
+ if (rerr) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s",
+ rerr, gai_strerror(rerr), domain);
+ goto fail;
+ }
+ for (rp = result; rp; rp = rp->ai_next) {
+ /* Limit no. of address to avoid denial of service attack */
+ if (s->n_addr >= MAX_ADDR_PER_SUBSCRIPTION) {
+ wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: "
+ "Ignoring excessive addresses");
+ break;
+ }
+
+ a = os_zalloc(sizeof(*a) + alloc_len);
+ if (a == NULL)
+ continue;
+ a->s = s;
+ mem = (void *) (a + 1);
+ a->domain_and_port = mem;
+ strcpy(mem, domain_and_port);
+ mem += 1 + strlen(mem);
+ a->path = mem;
+ if (path[0] != '/')
+ *mem++ = '/';
+ strcpy(mem, path);
+ mem += 1 + strlen(mem);
+ os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr));
+ a->saddr.sin_port = htons(port);
+
+ subscr_addr_link(s, a);
+ a = NULL; /* don't free it below */
+ }
+
+fail:
+ if (result)
+ freeaddrinfo(result);
+ os_free(scratch_mem);
+ os_free(a);
+}
+
+
+/* subscr_addr_list_create -- create list from urls in string.
+ * Each url is enclosed by angle brackets.
+ */
+static void subscr_addr_list_create(struct subscription *s,
+ const char *url_list)
+{
+ char *end;
+ for (;;) {
+ while (*url_list == ' ' || *url_list == '\t')
+ url_list++;
+ if (*url_list != '<')
+ break;
+ url_list++;
+ end = os_strchr(url_list, '>');
+ if (end == NULL)
+ break;
+ *end++ = 0;
+ subscr_addr_add_url(s, url_list);
+ url_list = end;
+ }
+}
+
+
+int send_wpabuf(int fd, struct wpabuf *buf)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message",
+ (unsigned long) wpabuf_len(buf));
+ errno = 0;
+ if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) !=
+ (int) wpabuf_len(buf)) {
+ wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: "
+ "errno=%d (%s)",
+ errno, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void wpabuf_put_property(struct wpabuf *buf, const char *name,
+ const char *value)
+{
+ wpabuf_put_str(buf, "<e:property>");
+ wpabuf_printf(buf, "<%s>", name);
+ if (value)
+ wpabuf_put_str(buf, value);
+ wpabuf_printf(buf, "</%s>", name);
+ wpabuf_put_str(buf, "</e:property>\n");
+}
+
+
+/**
+ * upnp_wps_device_send_event - Queue event messages for subscribers
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ *
+ * This function queues the last WLANEvent to be sent for all currently
+ * subscribed UPnP control points. sm->wlanevent must have been set with the
+ * encoded data before calling this function.
+ */
+static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
+{
+ /* Enqueue event message for all subscribers */
+ struct wpabuf *buf; /* holds event message */
+ int buf_size = 0;
+ struct subscription *s;
+ /* Actually, utf-8 is the default, but it doesn't hurt to specify it */
+ const char *format_head =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
+ const char *format_tail = "</e:propertyset>\n";
+
+ if (sm->subscriptions == NULL) {
+ /* optimize */
+ return;
+ }
+
+ /* Determine buffer size needed first */
+ buf_size += os_strlen(format_head);
+ buf_size += 50 + 2 * os_strlen("WLANEvent");
+ if (sm->wlanevent)
+ buf_size += os_strlen(sm->wlanevent);
+ buf_size += os_strlen(format_tail);
+
+ buf = wpabuf_alloc(buf_size);
+ if (buf == NULL)
+ return;
+ wpabuf_put_str(buf, format_head);
+ wpabuf_put_property(buf, "WLANEvent", sm->wlanevent);
+ wpabuf_put_str(buf, format_tail);
+
+ wpa_printf(MSG_MSGDUMP, "WPS UPnP: WLANEvent message:\n%s",
+ (char *) wpabuf_head(buf));
+
+ s = sm->subscriptions;
+ do {
+ if (event_add(s, buf)) {
+ struct subscription *s_old = s;
+ wpa_printf(MSG_INFO, "WPS UPnP: Dropping "
+ "subscriber due to event backlog");
+ s = s_old->next;
+ subscription_unlink(s_old);
+ subscription_destroy(s_old);
+ } else {
+ s = s->next;
+ }
+ } while (s != sm->subscriptions);
+
+ wpabuf_free(buf);
+}
+
+
+/*
+ * Event subscription (subscriber machines register with us to receive event
+ * messages).
+ * This is the result of an incoming HTTP over TCP SUBSCRIBE request.
+ */
+
+/* subscription_unlink -- remove from the active list */
+void subscription_unlink(struct subscription *s)
+{
+ struct upnp_wps_device_sm *sm = s->sm;
+
+ if (s->next == s) {
+ /* only one? */
+ sm->subscriptions = NULL;
+ } else {
+ if (sm->subscriptions == s)
+ sm->subscriptions = s->next;
+ s->next->prev = s->prev;
+ s->prev->next = s->next;
+ }
+ sm->n_subscriptions--;
+}
+
+
+/* subscription_link_to_end -- link to end of active list
+ * (should have high expiry time!)
+ */
+static void subscription_link_to_end(struct subscription *s)
+{
+ struct upnp_wps_device_sm *sm = s->sm;
+
+ if (sm->subscriptions) {
+ s->next = sm->subscriptions;
+ s->prev = s->next->prev;
+ s->prev->next = s;
+ s->next->prev = s;
+ } else {
+ sm->subscriptions = s->next = s->prev = s;
+ }
+ sm->n_subscriptions++;
+}
+
+
+/* subscription_destroy -- destroy an unlinked subscription
+ * Be sure to unlink first if necessary.
+ */
+void subscription_destroy(struct subscription *s)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Destroy subscription %p", s);
+ if (s->addr_list)
+ subscr_addr_free_all(s);
+ event_delete_all(s);
+ os_free(s);
+}
+
+
+/* subscription_list_age -- remove expired subscriptions */
+static void subscription_list_age(struct upnp_wps_device_sm *sm, time_t now)
+{
+ struct subscription *s;
+ while ((s = sm->subscriptions) != NULL && s->timeout_time < now) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Removing aged subscription");
+ subscription_unlink(s);
+ subscription_destroy(s);
+ }
+}
+
+
+/* subscription_find -- return existing subscription matching uuid, if any
+ * returns NULL if not found
+ */
+struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
+ const u8 uuid[UUID_LEN])
+{
+ struct subscription *s0 = sm->subscriptions;
+ struct subscription *s = s0;
+
+ if (s0 == NULL)
+ return NULL;
+ do {
+ if (os_memcmp(s->uuid, uuid, UUID_LEN) == 0)
+ return s; /* Found match */
+ s = s->next;
+ } while (s != s0);
+
+ return NULL;
+}
+
+
+/* subscription_first_event -- send format/queue event that is automatically
+ * sent on a new subscription.
+ */
+static int subscription_first_event(struct subscription *s)
+{
+ /*
+ * Actually, utf-8 is the default, but it doesn't hurt to specify it.
+ *
+ * APStatus is apparently a bit set,
+ * 0x1 = configuration change (but is always set?)
+ * 0x10 = ap is locked
+ *
+ * Per UPnP spec, we send out the last value of each variable, even
+ * for WLANEvent, whatever it was.
+ */
+ char *wlan_event;
+ struct wpabuf *buf;
+ int ap_status = 1; /* TODO: add 0x10 if access point is locked */
+ const char *head =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
+ const char *tail = "</e:propertyset>\n";
+ char txt[10];
+
+ wlan_event = s->sm->wlanevent;
+ if (wlan_event == NULL || *wlan_event == '\0') {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: WLANEvent not known for "
+ "initial event message");
+ wlan_event = "";
+ }
+ buf = wpabuf_alloc(500 + os_strlen(wlan_event));
+ if (buf == NULL)
+ return 1;
+
+ wpabuf_put_str(buf, head);
+ wpabuf_put_property(buf, "STAStatus", "1");
+ os_snprintf(txt, sizeof(txt), "%d", ap_status);
+ wpabuf_put_property(buf, "APStatus", txt);
+ if (*wlan_event)
+ wpabuf_put_property(buf, "WLANEvent", wlan_event);
+ wpabuf_put_str(buf, tail);
+
+ if (event_add(s, buf)) {
+ wpabuf_free(buf);
+ return 1;
+ }
+ wpabuf_free(buf);
+
+ return 0;
+}
+
+
+/**
+ * subscription_start - Rremember a UPnP control point to send events to.
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @callback_urls: malloc' mem given to the subscription
+ * Returns: %NULL on error, or pointer to new subscription structure.
+ */
+struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
+ char *callback_urls)
+{
+ struct subscription *s;
+ time_t now = time(NULL);
+ time_t expire = now + UPNP_SUBSCRIBE_SEC;
+
+ /* Get rid of expired subscriptions so we have room */
+ subscription_list_age(sm, now);
+
+ /* If too many subscriptions, remove oldest */
+ if (sm->n_subscriptions >= MAX_SUBSCRIPTIONS) {
+ s = sm->subscriptions;
+ wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, "
+ "trashing oldest");
+ subscription_unlink(s);
+ subscription_destroy(s);
+ }
+
+ s = os_zalloc(sizeof(*s));
+ if (s == NULL)
+ return NULL;
+
+ s->sm = sm;
+ s->timeout_time = expire;
+ uuid_make(s->uuid);
+ subscr_addr_list_create(s, callback_urls);
+ /* Add to end of list, since it has the highest expiration time */
+ subscription_link_to_end(s);
+ /* Queue up immediate event message (our last event)
+ * as required by UPnP spec.
+ */
+ if (subscription_first_event(s)) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Dropping subscriber due to "
+ "event backlog");
+ subscription_unlink(s);
+ subscription_destroy(s);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription %p started with %s",
+ s, callback_urls);
+ os_free(callback_urls);
+ /* Schedule sending this */
+ event_send_all_later(sm);
+ return s;
+}
+
+
+/* subscription_renew -- find subscription and reset timeout */
+struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
+ const u8 uuid[UUID_LEN])
+{
+ time_t now = time(NULL);
+ time_t expire = now + UPNP_SUBSCRIBE_SEC;
+ struct subscription *s = subscription_find(sm, uuid);
+ if (s == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewed");
+ subscription_unlink(s);
+ s->timeout_time = expire;
+ /* add back to end of list, since it now has highest expiry */
+ subscription_link_to_end(s);
+ return s;
+}
+
+
+/**
+ * upnp_wps_device_send_wlan_event - Event notification
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @from_mac_addr: Source (Enrollee) MAC address for the event
+ * @ev_type: Event type
+ * @msg: Event data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Tell external Registrars (UPnP control points) that something happened. In
+ * particular, events include WPS messages from clients that are proxied to
+ * external Registrars.
+ */
+int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
+ const u8 from_mac_addr[ETH_ALEN],
+ enum upnp_wps_wlanevent_type ev_type,
+ const struct wpabuf *msg)
+{
+ int ret = -1;
+ char type[2];
+ const u8 *mac = from_mac_addr;
+ char mac_text[18];
+ u8 *raw = NULL;
+ size_t raw_len;
+ char *val;
+ size_t val_len;
+ int pos = 0;
+
+ if (!sm)
+ goto fail;
+
+ os_snprintf(type, sizeof(type), "%1u", ev_type);
+
+ raw_len = 1 + 17 + (msg ? wpabuf_len(msg) : 0);
+ raw = os_zalloc(raw_len);
+ if (!raw)
+ goto fail;
+
+ *(raw + pos) = (u8) ev_type;
+ pos += 1;
+ os_snprintf(mac_text, sizeof(mac_text), MACSTR, MAC2STR(mac));
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Proxying WLANEvent from %s",
+ mac_text);
+ os_memcpy(raw + pos, mac_text, 17);
+ pos += 17;
+ if (msg) {
+ os_memcpy(raw + pos, wpabuf_head(msg), wpabuf_len(msg));
+ pos += wpabuf_len(msg);
+ }
+ raw_len = pos;
+
+ val = (char *) base64_encode(raw, raw_len, &val_len);
+ if (val == NULL)
+ goto fail;
+
+ os_free(sm->wlanevent);
+ sm->wlanevent = val;
+ upnp_wps_device_send_event(sm);
+
+ ret = 0;
+
+fail:
+ os_free(raw);
+
+ return ret;
+}
+
+
+/**
+ * get_netif_info - Get hw and IP addresses for network device
+ * @net_if: Selected network interface name
+ * @ip_addr: Buffer for returning IP address in network byte order
+ * @ip_addr_text: Buffer for returning a pointer to allocated IP address text
+ * @mac: Buffer for returning MAC address
+ * @mac_addr_text: Buffer for returning allocated MAC address text
+ * Returns: 0 on success, -1 on failure
+ */
+static int get_netif_info(const char *net_if, unsigned *ip_addr,
+ char **ip_addr_text, u8 mac[ETH_ALEN],
+ char **mac_addr_text)
+{
+ struct ifreq req;
+ int sock = -1;
+ struct sockaddr_in *addr;
+ struct in_addr in_addr;
+
+ *ip_addr_text = os_zalloc(16);
+ *mac_addr_text = os_zalloc(18);
+ if (*ip_addr_text == NULL || *mac_addr_text == NULL)
+ goto fail;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ goto fail;
+
+ os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
+ if (ioctl(sock, SIOCGIFADDR, &req) < 0) {
+ wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFADDR failed: %d (%s)",
+ errno, strerror(errno));
+ goto fail;
+ }
+ addr = (void *) &req.ifr_addr;
+ *ip_addr = addr->sin_addr.s_addr;
+ in_addr.s_addr = *ip_addr;
+ os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr));
+
+ os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
+ if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) {
+ wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFHWADDR failed: "
+ "%d (%s)", errno, strerror(errno));
+ goto fail;
+ }
+ os_memcpy(mac, req.ifr_addr.sa_data, 6);
+ os_snprintf(*mac_addr_text, 18, MACSTR, MAC2STR(req.ifr_addr.sa_data));
+
+ close(sock);
+ return 0;
+
+fail:
+ if (sock >= 0)
+ close(sock);
+ os_free(*ip_addr_text);
+ *ip_addr_text = NULL;
+ os_free(*mac_addr_text);
+ *mac_addr_text = NULL;
+ return -1;
+}
+
+
+/**
+ * upnp_wps_device_stop - Stop WPS UPnP operations on an interface
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ */
+void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
+{
+ if (!sm || !sm->started)
+ return;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
+ web_listener_stop(sm);
+ while (sm->web_connections)
+ web_connection_stop(sm->web_connections);
+ while (sm->msearch_replies)
+ msearchreply_state_machine_stop(sm->msearch_replies);
+ while (sm->subscriptions) {
+ struct subscription *s = sm->subscriptions;
+ subscription_unlink(s);
+ subscription_destroy(s);
+ }
+
+ advertisement_state_machine_stop(sm);
+ /* TODO: send byebye notifications */
+
+ event_send_stop_all(sm);
+ os_free(sm->wlanevent);
+ sm->wlanevent = NULL;
+ os_free(sm->net_if);
+ sm->net_if = NULL;
+ os_free(sm->mac_addr_text);
+ sm->mac_addr_text = NULL;
+ os_free(sm->ip_addr_text);
+ sm->ip_addr_text = NULL;
+ if (sm->multicast_sd >= 0)
+ close(sm->multicast_sd);
+ sm->multicast_sd = -1;
+ ssdp_listener_stop(sm);
+
+ sm->started = 0;
+}
+
+
+/**
+ * upnp_wps_device_start - Start WPS UPnP operations on an interface
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @net_if: Selected network interface name
+ * Returns: 0 on success, -1 on failure
+ */
+int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
+{
+ if (!sm || !net_if)
+ return -1;
+
+ if (sm->started)
+ upnp_wps_device_stop(sm);
+
+ sm->net_if = strdup(net_if);
+ sm->multicast_sd = -1;
+ sm->ssdp_sd = -1;
+ sm->started = 1;
+ sm->advertise_count = 0;
+
+ /* Fix up linux multicast handling */
+ if (add_ssdp_network(net_if))
+ goto fail;
+
+ /* Determine which IP and mac address we're using */
+ if (get_netif_info(net_if,
+ &sm->ip_addr, &sm->ip_addr_text,
+ sm->mac_addr, &sm->mac_addr_text)) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
+ "for %s. Does it have IP address?", net_if);
+ goto fail;
+ }
+
+ /* Listen for incoming TCP connections so that others
+ * can fetch our "xml files" from us.
+ */
+ if (web_listener_start(sm))
+ goto fail;
+
+ /* Set up for receiving discovery (UDP) packets */
+ if (ssdp_listener_start(sm))
+ goto fail;
+
+ /* Set up for sending multicast */
+ if (ssdp_open_multicast(sm) < 0)
+ goto fail;
+
+ /*
+ * Broadcast NOTIFY messages to let the world know we exist.
+ * This is done via a state machine since the messages should not be
+ * all sent out at once.
+ */
+ if (advertisement_state_machine_start(sm))
+ goto fail;
+
+ return 0;
+
+fail:
+ upnp_wps_device_stop(sm);
+ return -1;
+}
+
+
+/**
+ * upnp_wps_device_deinit - Deinitialize WPS UPnP
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ */
+void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm)
+{
+ if (!sm)
+ return;
+
+ upnp_wps_device_stop(sm);
+
+ if (sm->peer.wps)
+ wps_deinit(sm->peer.wps);
+ os_free(sm->root_dir);
+ os_free(sm->desc_url);
+ os_free(sm->ctx);
+ os_free(sm);
+}
+
+
+/**
+ * upnp_wps_device_init - Initialize WPS UPnP
+ * @ctx: callback table; we must eventually free it
+ * @wps: Pointer to longterm WPS context
+ * @priv: External context data that will be used in callbacks
+ * Returns: WPS UPnP state or %NULL on failure
+ */
+struct upnp_wps_device_sm *
+upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
+ void *priv)
+{
+ struct upnp_wps_device_sm *sm;
+
+ sm = os_zalloc(sizeof(*sm));
+ if (!sm) {
+ wpa_printf(MSG_ERROR, "WPS UPnP: upnp_wps_device_init failed");
+ return NULL;
+ }
+
+ sm->ctx = ctx;
+ sm->wps = wps;
+ sm->priv = priv;
+
+ return sm;
+}
+
+
+/**
+ * upnp_wps_subscribers - Check whether there are any event subscribers
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 if no subscribers, 1 if subscribers
+ */
+int upnp_wps_subscribers(struct upnp_wps_device_sm *sm)
+{
+ return sm->subscriptions != NULL;
+}
Added: wpasupplicant/branches/upstream/current/src/wps/wps_upnp.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_upnp.h?rev=1324&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_upnp.h (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_upnp.h Sun Feb 15 19:38:55 2009
@@ -1,0 +1,67 @@
+/*
+ * UPnP WPS Device
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#ifndef WPS_UPNP_H
+#define WPS_UPNP_H
+
+struct upnp_wps_device_sm;
+struct wps_context;
+struct wps_data;
+
+struct upnp_wps_peer {
+ struct wps_data *wps;
+};
+
+enum upnp_wps_wlanevent_type {
+ UPNP_WPS_WLANEVENT_TYPE_PROBE = 1,
+ UPNP_WPS_WLANEVENT_TYPE_EAP = 2
+};
+
+struct upnp_wps_device_ctx {
+ struct wpabuf * (*rx_req_get_device_info)(
+ void *priv, struct upnp_wps_peer *peer);
+ struct wpabuf * (*rx_req_put_message)(
+ void *priv, struct upnp_wps_peer *peer,
+ const struct wpabuf *msg);
+ struct wpabuf * (*rx_req_get_ap_settings)(void *priv,
+ const struct wpabuf *msg);
+ int (*rx_req_set_ap_settings)(void *priv, const struct wpabuf *msg);
+ int (*rx_req_del_ap_settings)(void *priv, const struct wpabuf *msg);
+ struct wpabuf * (*rx_req_get_sta_settings)(void *priv,
+ const struct wpabuf *msg);
+ int (*rx_req_set_sta_settings)(void *priv, const struct wpabuf *msg);
+ int (*rx_req_del_sta_settings)(void *priv, const struct wpabuf *msg);
+ int (*rx_req_put_wlan_response)(
+ void *priv, enum upnp_wps_wlanevent_type ev_type,
+ const u8 *mac_addr, const struct wpabuf *msg,
+ enum wps_msg_type msg_type);
+ int (*rx_req_set_selected_registrar)(void *priv,
+ const struct wpabuf *msg);
+ int (*rx_req_reboot_ap)(void *priv, const struct wpabuf *msg);
+ int (*rx_req_reset_ap)(void *priv, const struct wpabuf *msg);
+ int (*rx_req_reboot_sta)(void *priv, const struct wpabuf *msg);
+ int (*rx_req_reset_sta)(void *priv, const struct wpabuf *msg);
+};
+
+struct upnp_wps_device_sm *
+upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
+ void *priv);
+void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm);
+
+int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if);
+void upnp_wps_device_stop(struct upnp_wps_device_sm *sm);
+
+int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
+ const u8 from_mac_addr[ETH_ALEN],
+ enum upnp_wps_wlanevent_type ev_type,
+ const struct wpabuf *msg);
+int upnp_wps_subscribers(struct upnp_wps_device_sm *sm);
+
+#endif /* WPS_UPNP_H */
Added: wpasupplicant/branches/upstream/current/src/wps/wps_upnp_event.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_upnp_event.c?rev=1324&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_upnp_event.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_upnp_event.c Sun Feb 15 19:38:55 2009
@@ -1,0 +1,534 @@
+/*
+ * UPnP WPS Device - Event processing
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#include "includes.h"
+#include <assert.h>
+#include <fcntl.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "uuid.h"
+#include "httpread.h"
+#include "wps_defs.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+/*
+ * Event message generation (to subscribers)
+ *
+ * We make a separate copy for each message for each subscriber. This memory
+ * wasted could be limited (adding code complexity) by sharing copies, keeping
+ * a usage count and freeing when zero.
+ *
+ * Sending a message requires using a HTTP over TCP NOTIFY
+ * (like a PUT) which requires a number of states..
+ */
+
+#define MAX_EVENTS_QUEUED 20 /* How far behind queued events */
+#define EVENT_TIMEOUT_SEC 30 /* Drop sending event after timeout */
+
+/* How long to wait before sending event */
+#define EVENT_DELAY_SECONDS 0
+#define EVENT_DELAY_MSEC 0
+
+/*
+ * Event information that we send to each subscriber is remembered in this
+ * struct. The event cannot be sent by simple UDP; it has to be sent by a HTTP
+ * over TCP transaction which requires various states.. It may also need to be
+ * retried at a different address (if more than one is available).
+ *
+ * TODO: As an optimization we could share data between subscribers.
+ */
+struct wps_event_ {
+ struct wps_event_ *next;
+ struct wps_event_ *prev; /* double linked list */
+ struct subscription *s; /* parent */
+ unsigned subscriber_sequence; /* which event for this subscription*/
+ int retry; /* which retry */
+ struct subscr_addr *addr; /* address to connect to */
+ struct wpabuf *data; /* event data to send */
+ /* The following apply while we are sending an event message. */
+ int sd; /* -1 or socket descriptor for open connection */
+ int sd_registered; /* nonzero if we must cancel registration */
+ struct httpread *hread; /* NULL or open connection for event msg */
+};
+
+
+static void event_timeout_handler(void *eloop_data, void *user_ctx);
+
+/* event_clean -- clean sockets etc. of event
+ * Leaves data, retry count etc. alone.
+ */
+static void event_clean(struct wps_event_ *e)
+{
+ if (e->s->current_event == e) {
+ eloop_cancel_timeout(event_timeout_handler, NULL, e);
+ e->s->current_event = NULL;
+ }
+ if (e->sd_registered) {
+ eloop_unregister_sock(e->sd, EVENT_TYPE_WRITE);
+ e->sd_registered = 0;
+ }
+ if (e->sd != -1) {
+ close(e->sd);
+ e->sd = -1;
+ }
+ if (e->hread)
+ httpread_destroy(e->hread);
+ e->hread = NULL;
+}
+
+
+/* event_delete -- delete single unqueued event
+ * (be sure to dequeue first if need be)
+ */
+void event_delete(struct wps_event_ *e)
+{
+ event_clean(e);
+ wpabuf_free(e->data);
+ os_free(e);
+}
+
+
+/* event_dequeue -- get next event from the queue
+ * Returns NULL if empty.
+ */
+static struct wps_event_ *event_dequeue(struct subscription *s)
+{
+ struct wps_event_ **event_head = &s->event_queue;
+ struct wps_event_ *e = *event_head;
+ if (e == NULL)
+ return NULL;
+ e->next->prev = e->prev;
+ e->prev->next = e->next;
+ if (*event_head == e) {
+ if (e == e->next) {
+ /* last in queue */
+ *event_head = NULL;
+ } else {
+ *event_head = e->next;
+ }
+ }
+ s->n_queue--;
+ e->next = e->prev = NULL;
+ /* but parent "s" is still valid */
+ return e;
+}
+
+
+/* event_enqueue_at_end -- add event to end of queue */
+static void event_enqueue_at_end(struct subscription *s, struct wps_event_ *e)
+{
+ struct wps_event_ **event_head = &s->event_queue;
+ if (*event_head == NULL) {
+ *event_head = e->next = e->prev = e;
+ } else {
+ e->next = *event_head;
+ e->prev = e->next->prev;
+ e->prev->next = e;
+ e->next->prev = e;
+ }
+ s->n_queue++;
+}
+
+
+/* event_enqueue_at_begin -- add event to begin of queue
+ * (appropriate for retrying event only)
+ */
+static void event_enqueue_at_begin(struct subscription *s,
+ struct wps_event_ *e)
+{
+ struct wps_event_ **event_head = &s->event_queue;
+ if (*event_head == NULL) {
+ *event_head = e->next = e->prev = e;
+ } else {
+ e->prev = *event_head;
+ e->next = e->prev->next;
+ e->prev->next = e;
+ e->next->prev = e;
+ *event_head = e;
+ }
+ s->n_queue++;
+}
+
+
+/* event_delete_all -- delete entire event queue and current event */
+void event_delete_all(struct subscription *s)
+{
+ struct wps_event_ *e;
+ while ((e = event_dequeue(s)) != NULL)
+ event_delete(e);
+ if (s->current_event) {
+ event_delete(s->current_event);
+ /* will set: s->current_event = NULL; */
+ }
+}
+
+
+/**
+ * event_retry - Called when we had a failure delivering event msg
+ * @e: Event
+ * @do_next_address: skip address e.g. on connect fail
+ */
+static void event_retry(struct wps_event_ *e, int do_next_address)
+{
+ struct subscription *s = e->s;
+ struct upnp_wps_device_sm *sm = s->sm;
+
+ event_clean(e);
+ /* will set: s->current_event = NULL; */
+
+ if (do_next_address)
+ e->retry++;
+ if (e->retry >= s->n_addr) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Giving up on sending event "
+ "for %s", e->addr->domain_and_port);
+ return;
+ }
+ event_enqueue_at_begin(s, e);
+ event_send_all_later(sm);
+}
+
+
+/* called if the overall event-sending process takes too long */
+static void event_timeout_handler(void *eloop_data, void *user_ctx)
+{
+ struct wps_event_ *e = user_ctx;
+ struct subscription *s = e->s;
+
+ assert(e == s->current_event);
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout");
+ event_retry(e, 1);
+}
+
+
+/* event_got_response_handler -- called back when http response is received. */
+static void event_got_response_handler(struct httpread *handle, void *cookie,
+ enum httpread_event en)
+{
+ struct wps_event_ *e = cookie;
+ struct subscription *s = e->s;
+ struct upnp_wps_device_sm *sm = s->sm;
+ struct httpread *hread = e->hread;
+ int reply_code = 0;
+
+ assert(e == s->current_event);
+ eloop_cancel_timeout(event_timeout_handler, NULL, e);
+
+ if (en == HTTPREAD_EVENT_FILE_READY) {
+ if (httpread_hdr_type_get(hread) == HTTPREAD_HDR_TYPE_REPLY) {
+ reply_code = httpread_reply_code_get(hread);
+ if (reply_code == HTTP_OK) {
+ wpa_printf(MSG_DEBUG,
+ "WPS UPnP: Got event reply OK from "
+ "%s", e->addr->domain_and_port);
+ event_delete(e);
+ goto send_more;
+ } else {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Got event "
+ "error reply code %d from %s",
+ reply_code,
+ e->addr->domain_and_port);
+ goto bad;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Got bogus event "
+ "response %d from %s", en,
+ e->addr->domain_and_port);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Event response timeout/fail "
+ "for %s", e->addr->domain_and_port);
+ goto bad;
+ }
+ event_retry(e, 1);
+ goto send_more;
+
+send_more:
+ /* Schedule sending more if there is more to send */
+ if (s->event_queue)
+ event_send_all_later(sm);
+ return;
+
+bad:
+ /*
+ * If other side doesn't like what we say, forget about them.
+ * (There is no way to tell other side that we are dropping
+ * them...).
+ * Alternately, we could just do event_delete(e)
+ */
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription due to errors");
+ subscription_unlink(s);
+ subscription_destroy(s);
+}
+
+
+/* event_send_tx_ready -- actually write event message
+ *
+ * Prequisite: subscription socket descriptor has become ready to
+ * write (because connection to subscriber has been made).
+ *
+ * It is also possible that we are called because the connect has failed;
+ * it is possible to test for this, or we can just go ahead and then
+ * the write will fail.
+ */
+static void event_send_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wps_event_ *e = sock_ctx;
+ struct subscription *s = e->s;
+ struct wpabuf *buf;
+ char *b;
+
+ assert(e == s->current_event);
+ assert(e->sd == sock);
+
+ buf = wpabuf_alloc(1000 + wpabuf_len(e->data));
+ if (buf == NULL) {
+ event_retry(e, 0);
+ goto bad;
+ }
+ wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
+ wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
+ wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port);
+ wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
+ "NT: upnp:event\r\n"
+ "NTS: upnp:propchange\r\n");
+ wpabuf_put_str(buf, "SID: uuid:");
+ b = wpabuf_put(buf, 0);
+ uuid_bin2str(s->uuid, b, 80);
+ wpabuf_put(buf, os_strlen(b));
+ wpabuf_put_str(buf, "\r\n");
+ wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence);
+ wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n",
+ (int) wpabuf_len(e->data));
+ wpabuf_put_str(buf, "\r\n"); /* terminating empty line */
+ wpabuf_put_buf(buf, e->data);
+
+ /* Since the message size is pretty small, we should be
+ * able to get the operating system to buffer what we give it
+ * and not have to come back again later to write more...
+ */
+#if 0
+ /* we could: Turn blocking back on? */
+ fcntl(e->sd, F_SETFL, 0);
+#endif
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Sending event to %s",
+ e->addr->domain_and_port);
+ if (send_wpabuf(e->sd, buf) < 0) {
+ event_retry(e, 1);
+ goto bad;
+ }
+ wpabuf_free(buf);
+ buf = NULL;
+
+ if (e->sd_registered) {
+ e->sd_registered = 0;
+ eloop_unregister_sock(e->sd, EVENT_TYPE_WRITE);
+ }
+ /* Set up to read the reply */
+ e->hread = httpread_create(e->sd, event_got_response_handler,
+ e /* cookie */,
+ 0 /* no data expected */,
+ EVENT_TIMEOUT_SEC);
+ if (e->hread == NULL) {
+ wpa_printf(MSG_ERROR, "WPS UPnP: httpread_create failed");
+ event_retry(e, 0);
+ goto bad;
+ }
+ return;
+
+bad:
+ /* Schedule sending more if there is more to send */
+ if (s->event_queue)
+ event_send_all_later(s->sm);
+ wpabuf_free(buf);
+}
+
+
+/* event_send_start -- prepare to send a event message to subscriber
+ *
+ * This gets complicated because:
+ * -- The message is sent via TCP and we have to keep the stream open
+ * for 30 seconds to get a response... then close it.
+ * -- But we might have other event happen in the meantime...
+ * we have to queue them, if we lose them then the subscriber will
+ * be forced to unsubscribe and subscribe again.
+ * -- If multiple URLs are provided then we are supposed to try successive
+ * ones after 30 second timeout.
+ * -- The URLs might use domain names instead of dotted decimal addresses,
+ * and resolution of those may cause unwanted sleeping.
+ * -- Doing the initial TCP connect can take a while, so we have to come
+ * back after connection and then send the data.
+ *
+ * Returns nonzero on error;
+ *
+ * Prerequisite: No current event send (s->current_event == NULL)
+ * and non-empty queue.
+ */
+static int event_send_start(struct subscription *s)
+{
+ struct wps_event_ *e;
+ int itry;
+
+ /*
+ * Assume we are called ONLY with no current event and ONLY with
+ * nonempty event queue and ONLY with at least one address to send to.
+ */
+ assert(s->addr_list != NULL);
+ assert(s->current_event == NULL);
+ assert(s->event_queue != NULL);
+
+ s->current_event = e = event_dequeue(s);
+
+ /* Use address acc. to no. of retries */
+ e->addr = s->addr_list;
+ for (itry = 0; itry < e->retry; itry++)
+ e->addr = e->addr->next;
+
+ e->sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (e->sd < 0) {
+ event_retry(e, 0);
+ return -1;
+ }
+ /* set non-blocking so we don't sleep waiting for connection */
+ if (fcntl(e->sd, F_SETFL, O_NONBLOCK) != 0) {
+ event_retry(e, 0);
+ return -1;
+ }
+ /*
+ * Start the connect. It might succeed immediately but more likely will
+ * return errno EINPROGRESS.
+ */
+ if (connect(e->sd, (struct sockaddr *) &e->addr->saddr,
+ sizeof(e->addr->saddr))) {
+ if (errno != EINPROGRESS) {
+ event_retry(e, 1);
+ return -1;
+ }
+ }
+ /* Call back when ready for writing (or on failure...). */
+ if (eloop_register_sock(e->sd, EVENT_TYPE_WRITE, event_send_tx_ready,
+ NULL, e)) {
+ event_retry(e, 0);
+ return -1;
+ }
+ e->sd_registered = 1;
+ /* Don't wait forever! */
+ if (eloop_register_timeout(EVENT_TIMEOUT_SEC, 0, event_timeout_handler,
+ NULL, e)) {
+ event_retry(e, 0);
+ return -1;
+ }
+ return 0;
+}
+
+
+/* event_send_all_later_handler -- actually send events as needed */
+void event_send_all_later_handler(void *eloop_data, void *user_ctx)
+{
+ struct upnp_wps_device_sm *sm = user_ctx;
+ struct subscription *s;
+ struct subscription *s_old;
+ int nerrors = 0;
+
+ sm->event_send_all_queued = 0;
+ s = sm->subscriptions;
+ if (s == NULL)
+ return;
+ do {
+ if (s->addr_list == NULL) {
+ /* if we've given up on all addresses */
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Removing "
+ "subscription with no addresses");
+ s_old = s;
+ s = s_old->next;
+ subscription_unlink(s_old);
+ subscription_destroy(s_old);
+ } else {
+ if (s->current_event == NULL /* not busy */ &&
+ s->event_queue != NULL /* more to do */) {
+ if (event_send_start(s))
+ nerrors++;
+ }
+ s = s->next;
+ }
+ } while (sm->subscriptions != NULL && s != sm->subscriptions);
+
+ if (nerrors) {
+ /* Try again later */
+ event_send_all_later(sm);
+ }
+}
+
+
+/* event_send_all_later -- schedule sending events to all subscribers
+ * that need it.
+ * This avoids two problems:
+ * -- After getting a subscription, we should not send the first event
+ * until after our reply is fully queued to be sent back,
+ * -- Possible stack depth or infinite recursion issues.
+ */
+void event_send_all_later(struct upnp_wps_device_sm *sm)
+{
+ /*
+ * The exact time in the future isn't too important. Waiting a bit
+ * might let us do several together.
+ */
+ if (sm->event_send_all_queued)
+ return;
+ sm->event_send_all_queued = 1;
+ eloop_register_timeout(EVENT_DELAY_SECONDS, EVENT_DELAY_MSEC,
+ event_send_all_later_handler, NULL, sm);
+}
+
+
+/* event_send_stop_all -- cleanup */
+void event_send_stop_all(struct upnp_wps_device_sm *sm)
+{
+ if (sm->event_send_all_queued)
+ eloop_cancel_timeout(event_send_all_later_handler, NULL, sm);
+ sm->event_send_all_queued = 0;
+}
+
+
+/**
+ * event_add - Add a new event to a queue
+ * @s: Subscription
+ * @data: Event data (is copied; caller retains ownership)
+ * Returns: 0 on success, 1 on error
+ */
+int event_add(struct subscription *s, const struct wpabuf *data)
+{
+ struct wps_event_ *e;
+
+ if (s->n_queue >= MAX_EVENTS_QUEUED) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for "
+ "subscriber");
+ return 1;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return 1;
+ e->s = s;
+ e->sd = -1;
+ e->data = wpabuf_dup(data);
+ if (e->data == NULL) {
+ os_free(e);
+ return 1;
+ }
+ e->subscriber_sequence = s->next_subscriber_sequence++;
+ if (s->next_subscriber_sequence == 0)
+ s->next_subscriber_sequence++;
+ event_enqueue_at_end(s, e);
+ event_send_all_later(s->sm);
+ return 0;
+}
Added: wpasupplicant/branches/upstream/current/src/wps/wps_upnp_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_upnp_i.h?rev=1324&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_upnp_i.h (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_upnp_i.h Sun Feb 15 19:38:55 2009
@@ -1,0 +1,193 @@
+/*
+ * UPnP for WPS / internal definitions
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#ifndef WPS_UPNP_I_H
+#define WPS_UPNP_I_H
+
+#define UPNP_MULTICAST_ADDRESS "239.255.255.250" /* for UPnP multicasting */
+#define UPNP_MULTICAST_PORT 1900 /* UDP port to monitor for UPnP */
+
+/* min subscribe time per UPnP standard */
+#define UPNP_SUBSCRIBE_SEC_MIN 1800
+/* subscribe time we use */
+#define UPNP_SUBSCRIBE_SEC (UPNP_SUBSCRIBE_SEC_MIN + 1)
+
+/* "filenames" used in URLs that we service via our "web server": */
+#define UPNP_WPS_DEVICE_XML_FILE "wps_device.xml"
+#define UPNP_WPS_SCPD_XML_FILE "wps_scpd.xml"
+#define UPNP_WPS_DEVICE_CONTROL_FILE "wps_control"
+#define UPNP_WPS_DEVICE_EVENT_FILE "wps_event"
+
+
+struct web_connection;
+struct subscription;
+struct upnp_wps_device_sm;
+
+
+enum http_reply_code {
+ HTTP_OK = 200,
+ HTTP_BAD_REQUEST = 400,
+ UPNP_INVALID_ACTION = 401,
+ UPNP_INVALID_ARGS = 402,
+ HTTP_PRECONDITION_FAILED = 412,
+ HTTP_INTERNAL_SERVER_ERROR = 500,
+ HTTP_UNIMPLEMENTED = 501,
+ UPNP_ACTION_FAILED = 501,
+ UPNP_ARG_VALUE_INVALID = 600,
+ UPNP_ARG_VALUE_OUT_OF_RANGE = 601,
+ UPNP_OUT_OF_MEMORY = 603
+};
+
+
+enum advertisement_type_enum {
+ ADVERTISE_UP = 0,
+ ADVERTISE_DOWN = 1,
+ MSEARCH_REPLY = 2
+};
+
+/*
+ * Advertisements are broadcast via UDP NOTIFYs, and are also the essence of
+ * the reply to UDP M-SEARCH requests. This struct handles both cases.
+ *
+ * A state machine is needed because a number of variant forms must be sent in
+ * separate packets and spread out in time to avoid congestion.
+ */
+struct advertisement_state_machine {
+ /* double-linked list */
+ struct advertisement_state_machine *next;
+ struct advertisement_state_machine *prev;
+ struct upnp_wps_device_sm *sm; /* parent */
+ enum advertisement_type_enum type;
+ int state;
+ int nerrors;
+ struct sockaddr_in client; /* for M-SEARCH replies */
+};
+
+
+/*
+ * An address of a subscriber (who may have multiple addresses). We are
+ * supposed to send (via TCP) updates to each subscriber, trying each address
+ * for a subscriber until we find one that seems to work.
+ */
+struct subscr_addr {
+ /* double linked list */
+ struct subscr_addr *next;
+ struct subscr_addr *prev;
+ struct subscription *s; /* parent */
+ char *domain_and_port; /* domain and port part of url */
+ char *path; /* "filepath" part of url (from "mem") */
+ struct sockaddr_in saddr; /* address for doing connect */
+};
+
+
+/*
+ * Subscribers to our events are recorded in this struct. This includes a max
+ * of one outgoing connection (sending an "event message") per subscriber. We
+ * also have to age out subscribers unless they renew.
+ */
+struct subscription {
+ /* double linked list */
+ struct subscription *next;
+ struct subscription *prev;
+ struct upnp_wps_device_sm *sm; /* parent */
+ time_t timeout_time; /* when to age out the subscription */
+ unsigned next_subscriber_sequence; /* number our messages */
+ /*
+ * This uuid identifies the subscription and is randomly generated by
+ * us and given to the subscriber when the subscription is accepted;
+ * and is then included with each event sent to the subscriber.
+ */
+ u8 uuid[UUID_LEN];
+ /* Linked list of address alternatives (rotate through on failure) */
+ struct subscr_addr *addr_list;
+ int n_addr; /* Number of addresses in list */
+ struct wps_event_ *event_queue; /* Queued event messages. */
+ int n_queue; /* How many events are queued */
+ struct wps_event_ *current_event; /* non-NULL if being sent (not in q)
+ */
+};
+
+
+/*
+ * Our instance data corresponding to one WiFi network interface
+ * (multiple might share the same wired network interface!).
+ *
+ * This is known as an opaque struct declaration to users of the WPS UPnP code.
+ */
+struct upnp_wps_device_sm {
+ struct upnp_wps_device_ctx *ctx; /* callback table */
+ struct wps_context *wps;
+ void *priv;
+ char *root_dir;
+ char *desc_url;
+ int started; /* nonzero if we are active */
+ char *net_if; /* network interface we use */
+ char *mac_addr_text; /* mac addr of network i.f. we use */
+ u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
+ char *ip_addr_text; /* IP address of network i.f. we use */
+ unsigned ip_addr; /* IP address of network i.f. we use (host order) */
+ int multicast_sd; /* send multicast messages over this socket */
+ int ssdp_sd; /* receive discovery UPD packets on socket */
+ int ssdp_sd_registered; /* nonzero if we must unregister */
+ unsigned advertise_count; /* how many advertisements done */
+ struct advertisement_state_machine advertisement;
+ struct advertisement_state_machine *msearch_replies;
+ int n_msearch_replies; /* no. of pending M-SEARCH replies */
+ int web_port; /* our port that others get xml files from */
+ int web_sd; /* socket to listen for web requests */
+ int web_sd_registered; /* nonzero if we must cancel registration */
+ struct web_connection *web_connections; /* linked list */
+ int n_web_connections; /* no. of pending web connections */
+ /* Note: subscriptions are kept in expiry order */
+ struct subscription *subscriptions; /* linked list */
+ int n_subscriptions; /* no of current subscriptions */
+ int event_send_all_queued; /* if we are scheduled to send events soon
+ */
+
+ char *wlanevent; /* the last WLANEvent data */
+
+ /* FIX: maintain separate structures for each UPnP peer */
+ struct upnp_wps_peer peer;
+};
+
+/* wps_upnp.c */
+void format_date(struct wpabuf *buf);
+struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
+ char *callback_urls);
+struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
+ const u8 uuid[UUID_LEN]);
+void subscription_unlink(struct subscription *s);
+void subscription_destroy(struct subscription *s);
+struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
+ const u8 uuid[UUID_LEN]);
+int send_wpabuf(int fd, struct wpabuf *buf);
+
+/* wps_upnp_ssdp.c */
+void msearchreply_state_machine_stop(struct advertisement_state_machine *a);
+int advertisement_state_machine_start(struct upnp_wps_device_sm *sm);
+void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm);
+void ssdp_listener_stop(struct upnp_wps_device_sm *sm);
+int ssdp_listener_start(struct upnp_wps_device_sm *sm);
+int add_ssdp_network(char *net_if);
+int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
+
+/* wps_upnp_web.c */
+void web_connection_stop(struct web_connection *c);
+int web_listener_start(struct upnp_wps_device_sm *sm);
+void web_listener_stop(struct upnp_wps_device_sm *sm);
+
+/* wps_upnp_event.c */
+int event_add(struct subscription *s, const struct wpabuf *data);
+void event_delete(struct wps_event_ *e);
+void event_delete_all(struct subscription *s);
+void event_send_all_later(struct upnp_wps_device_sm *sm);
+void event_send_stop_all(struct upnp_wps_device_sm *sm);
+
+#endif /* WPS_UPNP_I_H */
Added: wpasupplicant/branches/upstream/current/src/wps/wps_upnp_ssdp.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_upnp_ssdp.c?rev=1324&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_upnp_ssdp.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_upnp_ssdp.c Sun Feb 15 19:38:55 2009
@@ -1,0 +1,886 @@
+/*
+ * UPnP SSDP for WPS
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#include "includes.h"
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <net/route.h>
+
+#include "common.h"
+#include "uuid.h"
+#include "eloop.h"
+#include "wps.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+#define UPNP_CACHE_SEC (UPNP_CACHE_SEC_MIN + 1) /* cache time we use */
+#define UPNP_CACHE_SEC_MIN 1800 /* min cachable time per UPnP standard */
+#define UPNP_ADVERTISE_REPEAT 2 /* no more than 3 */
+#define MULTICAST_MAX_READ 1600 /* max bytes we'll read for UPD request */
+#define MAX_MSEARCH 20 /* max simultaneous M-SEARCH replies ongoing */
+#define SSDP_TARGET "239.0.0.0"
+#define SSDP_NETMASK "255.0.0.0"
+
+
+/* Check tokens for equality, where tokens consist of letters, digits,
+ * underscore and hyphen, and are matched case insensitive.
+ */
+static int token_eq(const char *s1, const char *s2)
+{
+ int c1;
+ int c2;
+ int end1 = 0;
+ int end2 = 0;
+ for (;;) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if (isalpha(c1) && isupper(c1))
+ c1 = tolower(c1);
+ if (isalpha(c2) && isupper(c2))
+ c2 = tolower(c2);
+ end1 = !(isalnum(c1) || c1 == '_' || c1 == '-');
+ end2 = !(isalnum(c2) || c2 == '_' || c2 == '-');
+ if (end1 || end2 || c1 != c2)
+ break;
+ }
+ return end1 && end2; /* reached end of both words? */
+}
+
+
+/* Return length of token (see above for definition of token) */
+static int token_length(const char *s)
+{
+ const char *begin = s;
+ for (;; s++) {
+ int c = *s;
+ int end = !(isalnum(c) || c == '_' || c == '-');
+ if (end)
+ break;
+ }
+ return s - begin;
+}
+
+
+/* return length of interword separation.
+ * This accepts only spaces/tabs and thus will not traverse a line
+ * or buffer ending.
+ */
+static int word_separation_length(const char *s)
+{
+ const char *begin = s;
+ for (;; s++) {
+ int c = *s;
+ if (c == ' ' || c == '\t')
+ continue;
+ break;
+ }
+ return s - begin;
+}
+
+
+/* No. of chars through (including) end of line */
+static int line_length(const char *l)
+{
+ const char *lp = l;
+ while (*lp && *lp != '\n')
+ lp++;
+ if (*lp == '\n')
+ lp++;
+ return lp - l;
+}
+
+
+/* No. of chars excluding trailing whitespace */
+static int line_length_stripped(const char *l)
+{
+ const char *lp = l + line_length(l);
+ while (lp > l && !isgraph(lp[-1]))
+ lp--;
+ return lp - l;
+}
+
+
+static int str_starts(const char *str, const char *start)
+{
+ return os_strncmp(str, start, os_strlen(start)) == 0;
+}
+
+
+/***************************************************************************
+ * Advertisements.
+ * These are multicast to the world to tell them we are here.
+ * The individual packets are spread out in time to limit loss,
+ * and then after a much longer period of time the whole sequence
+ * is repeated again (for NOTIFYs only).
+ **************************************************************************/
+
+/**
+ * next_advertisement - Build next message and advance the state machine
+ * @a: Advertisement state
+ * @islast: Buffer for indicating whether this is the last message (= 1)
+ * Returns: The new message (caller is responsible for freeing this)
+ *
+ * Note: next_advertisement is shared code with msearchreply_* functions
+ */
+static struct wpabuf *
+next_advertisement(struct advertisement_state_machine *a, int *islast)
+{
+ struct wpabuf *msg;
+ char *NTString = "";
+ char uuid_string[80];
+
+ *islast = 0;
+ uuid_bin2str(a->sm->wps->uuid, uuid_string, sizeof(uuid_string));
+ msg = wpabuf_alloc(800); /* more than big enough */
+ if (msg == NULL)
+ goto fail;
+ switch (a->type) {
+ case ADVERTISE_UP:
+ case ADVERTISE_DOWN:
+ NTString = "NT";
+ wpabuf_put_str(msg, "NOTIFY * HTTP/1.1\r\n");
+ wpabuf_printf(msg, "HOST: %s:%d\r\n",
+ UPNP_MULTICAST_ADDRESS, UPNP_MULTICAST_PORT);
+ wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",
+ UPNP_CACHE_SEC);
+ wpabuf_printf(msg, "NTS: %s\r\n",
+ (a->type == ADVERTISE_UP ?
+ "ssdp:alive" : "ssdp:byebye"));
+ break;
+ case MSEARCH_REPLY:
+ NTString = "ST";
+ wpabuf_put_str(msg, "HTTP/1.1 200 OK\r\n");
+ wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",
+ UPNP_CACHE_SEC);
+
+ wpabuf_put_str(msg, "DATE: ");
+ format_date(msg);
+ wpabuf_put_str(msg, "\r\n");
+
+ wpabuf_put_str(msg, "EXT:\r\n");
+ break;
+ }
+
+ if (a->type != ADVERTISE_DOWN) {
+ /* Where others may get our XML files from */
+ wpabuf_printf(msg, "LOCATION: http://%s:%d/%s\r\n",
+ a->sm->ip_addr_text, a->sm->web_port,
+ UPNP_WPS_DEVICE_XML_FILE);
+ }
+
+ /* The SERVER line has three comma-separated fields:
+ * operating system / version
+ * upnp version
+ * software package / version
+ * However, only the UPnP version is really required, the
+ * others can be place holders... for security reasons
+ * it is better to NOT provide extra information.
+ */
+ wpabuf_put_str(msg, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
+
+ switch (a->state / UPNP_ADVERTISE_REPEAT) {
+ case 0:
+ wpabuf_printf(msg, "%s: upnp:rootdevice\r\n", NTString);
+ wpabuf_printf(msg, "USN: uuid:%s::upnp:rootdevice\r\n",
+ uuid_string);
+ break;
+ case 1:
+ wpabuf_printf(msg, "%s: uuid:%s\r\n", NTString, uuid_string);
+ wpabuf_printf(msg, "USN: uuid:%s\r\n", uuid_string);
+ break;
+ case 2:
+ wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:device:"
+ "WFADevice:1\r\n", NTString);
+ wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"
+ "org:device:WFADevice:1\r\n", uuid_string);
+ break;
+ case 3:
+ wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:service:"
+ "WFAWLANConfig:1\r\n", NTString);
+ wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"
+ "org:service:WFAWLANConfig:1\r\n", uuid_string);
+ break;
+ }
+ wpabuf_put_str(msg, "\r\n");
+
+ if (a->state + 1 >= 4 * UPNP_ADVERTISE_REPEAT)
+ *islast = 1;
+
+ return msg;
+
+fail:
+ wpabuf_free(msg);
+ return NULL;
+}
+
+
+static void advertisement_state_machine_handler(void *eloop_data,
+ void *user_ctx);
+
+
+/**
+ * advertisement_state_machine_stop - Stop SSDP advertisements
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ */
+void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm)
+{
+ eloop_cancel_timeout(advertisement_state_machine_handler, NULL, sm);
+}
+
+
+static void advertisement_state_machine_handler(void *eloop_data,
+ void *user_ctx)
+{
+ struct upnp_wps_device_sm *sm = user_ctx;
+ struct advertisement_state_machine *a = &sm->advertisement;
+ struct wpabuf *msg;
+ int next_timeout_msec = 100;
+ int next_timeout_sec = 0;
+ struct sockaddr_in dest;
+ int islast = 0;
+
+ /*
+ * Each is sent twice (in case lost) w/ 100 msec delay between;
+ * spec says no more than 3 times.
+ * One pair for rootdevice, one pair for uuid, and a pair each for
+ * each of the two urns.
+ * The entire sequence must be repeated before cache control timeout
+ * (which is min 1800 seconds),
+ * recommend random portion of half of the advertised cache control age
+ * to ensure against loss... perhaps 1800/4 + rand*1800/4 ?
+ * Delay random interval < 100 msec prior to initial sending.
+ * TTL of 4
+ */
+
+ wpa_printf(MSG_MSGDUMP, "WPS UPnP: Advertisement state=%d", a->state);
+ msg = next_advertisement(a, &islast);
+ if (msg == NULL)
+ return;
+
+ os_memset(&dest, 0, sizeof(dest));
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+ dest.sin_port = htons(UPNP_MULTICAST_PORT);
+
+ if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
+ (struct sockaddr *) &dest, sizeof(dest)) == -1) {
+ wpa_printf(MSG_ERROR, "WPS UPnP: Advertisement sendto failed:"
+ "%d (%s)", errno, strerror(errno));
+ next_timeout_msec = 0;
+ next_timeout_sec = 10; /* ... later */
+ } else if (islast) {
+ a->state = 0; /* wrap around */
+ if (a->type == ADVERTISE_DOWN) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_DOWN->UP");
+ a->type = ADVERTISE_UP;
+ /* do it all over again right away */
+ } else {
+ u16 r;
+ /*
+ * Start over again after a long timeout
+ * (see notes above)
+ */
+ next_timeout_msec = 0;
+ os_get_random((void *) &r, sizeof(r));
+ next_timeout_sec = UPNP_CACHE_SEC / 4 +
+ (((UPNP_CACHE_SEC / 4) * r) >> 16);
+ sm->advertise_count++;
+ wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_UP (#%u); "
+ "next in %d sec",
+ sm->advertise_count, next_timeout_sec);
+ }
+ } else {
+ a->state++;
+ }
+
+ wpabuf_free(msg);
+
+ eloop_register_timeout(next_timeout_sec, next_timeout_msec,
+ advertisement_state_machine_handler, NULL, sm);
+}
+
+
+/**
+ * advertisement_state_machine_start - Start SSDP advertisements
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int advertisement_state_machine_start(struct upnp_wps_device_sm *sm)
+{
+ struct advertisement_state_machine *a = &sm->advertisement;
+ int next_timeout_msec;
+
+ advertisement_state_machine_stop(sm);
+
+ /*
+ * Start out advertising down, this automatically switches
+ * to advertising up which signals our restart.
+ */
+ a->type = ADVERTISE_DOWN;
+ a->state = 0;
+ a->sm = sm;
+ /* (other fields not used here) */
+
+ /* First timeout should be random interval < 100 msec */
+ next_timeout_msec = (100 * (os_random() & 0xFF)) >> 8;
+ return eloop_register_timeout(0, next_timeout_msec,
+ advertisement_state_machine_handler,
+ NULL, sm);
+}
+
+
+/***************************************************************************
+ * M-SEARCH replies
+ * These are very similar to the multicast advertisements, with some
+ * small changes in data content; and they are sent (UDP) to a specific
+ * unicast address instead of multicast.
+ * They are sent in response to a UDP M-SEARCH packet.
+ **************************************************************************/
+
+static void msearchreply_state_machine_handler(void *eloop_data,
+ void *user_ctx);
+
+
+/**
+ * msearchreply_state_machine_stop - Stop M-SEARCH reply state machine
+ * @a: Selected advertisement/reply state
+ */
+void msearchreply_state_machine_stop(struct advertisement_state_machine *a)
+{
+ struct upnp_wps_device_sm *sm = a->sm;
+ wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH stop");
+ if (a->next == a) {
+ sm->msearch_replies = NULL;
+ } else {
+ if (sm->msearch_replies == a)
+ sm->msearch_replies = a->next;
+ a->next->prev = a->prev;
+ a->prev->next = a->next;
+ }
+ os_free(a);
+ sm->n_msearch_replies--;
+}
+
+
+static void msearchreply_state_machine_handler(void *eloop_data,
+ void *user_ctx)
+{
+ struct advertisement_state_machine *a = user_ctx;
+ struct upnp_wps_device_sm *sm = a->sm;
+ struct wpabuf *msg;
+ int next_timeout_msec = 100;
+ int next_timeout_sec = 0;
+ int islast = 0;
+
+ /*
+ * Each response is sent twice (in case lost) w/ 100 msec delay
+ * between; spec says no more than 3 times.
+ * One pair for rootdevice, one pair for uuid, and a pair each for
+ * each of the two urns.
+ */
+
+ /* TODO: should only send the requested response types */
+
+ wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply state=%d (%s:%d)",
+ a->state, inet_ntoa(a->client.sin_addr),
+ ntohs(a->client.sin_port));
+ msg = next_advertisement(a, &islast);
+ if (msg == NULL)
+ return;
+
+ /*
+ * Send it on the multicast socket to avoid having to set up another
+ * socket.
+ */
+ if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
+ (struct sockaddr *) &a->client, sizeof(a->client)) < 0) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply sendto "
+ "errno %d (%s) for %s:%d",
+ errno, strerror(errno),
+ inet_ntoa(a->client.sin_addr),
+ ntohs(a->client.sin_port));
+ /* Ignore error and hope for the best */
+ }
+ wpabuf_free(msg);
+ if (islast) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply done");
+ msearchreply_state_machine_stop(a);
+ return;
+ }
+ a->state++;
+
+ wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply in %d.%03d sec",
+ next_timeout_sec, next_timeout_msec);
+ eloop_register_timeout(next_timeout_sec, next_timeout_msec,
+ msearchreply_state_machine_handler, sm, a);
+}
+
+
+/**
+ * msearchreply_state_machine_start - Reply to M-SEARCH discovery request
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @client: Client address
+ * @mx: Maximum delay in seconds
+ *
+ * Use TTL of 4 (this was done when socket set up).
+ * A response should be given in randomized portion of min(MX,120) seconds
+ *
+ * UPnP-arch-DeviceArchitecture, 1.2.3:
+ * To be found, a device must send a UDP response to the source IP address and
+ * port that sent the request to the multicast channel. Devices respond if the
+ * ST header of the M-SEARCH request is "ssdp:all", "upnp:rootdevice", "uuid:"
+ * followed by a UUID that exactly matches one advertised by the device.
+ */
+static void msearchreply_state_machine_start(struct upnp_wps_device_sm *sm,
+ struct sockaddr_in *client,
+ int mx)
+{
+ struct advertisement_state_machine *a;
+ int next_timeout_sec;
+ int next_timeout_msec;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply start (%d "
+ "outstanding)", sm->n_msearch_replies);
+ if (sm->n_msearch_replies >= MAX_MSEARCH) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Too many outstanding "
+ "M-SEARCH replies");
+ return;
+ }
+
+ a = os_zalloc(sizeof(*a));
+ if (a == NULL)
+ return;
+ a->type = MSEARCH_REPLY;
+ a->state = 0;
+ a->sm = sm;
+ os_memcpy(&a->client, client, sizeof(client));
+ /* Wait time depending on MX value */
+ next_timeout_msec = (1000 * mx * (os_random() & 0xFF)) >> 8;
+ next_timeout_sec = next_timeout_msec / 1000;
+ next_timeout_msec = next_timeout_msec % 1000;
+ if (eloop_register_timeout(next_timeout_sec, next_timeout_msec,
+ msearchreply_state_machine_handler, sm,
+ a)) {
+ /* No way to recover (from malloc failure) */
+ goto fail;
+ }
+ /* Remember for future cleanup */
+ if (sm->msearch_replies) {
+ a->next = sm->msearch_replies;
+ a->prev = a->next->prev;
+ a->prev->next = a;
+ a->next->prev = a;
+ } else {
+ sm->msearch_replies = a->next = a->prev = a;
+ }
+ sm->n_msearch_replies++;
+ return;
+
+fail:
+ wpa_printf(MSG_INFO, "WPS UPnP: M-SEARCH reply failure!");
+ eloop_cancel_timeout(msearchreply_state_machine_handler, sm, a);
+ os_free(a);
+}
+
+
+/**
+ * ssdp_parse_msearch - Process a received M-SEARCH
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @client: Client address
+ * @data: NULL terminated M-SEARCH message
+ *
+ * Given that we have received a header w/ M-SEARCH, act upon it
+ *
+ * Format of M-SEARCH (case insensitive!):
+ *
+ * First line must be:
+ * M-SEARCH * HTTP/1.1
+ * Other lines in arbitrary order:
+ * HOST:239.255.255.250:1900
+ * ST:<varies -- must match>
+ * MAN:"ssdp:discover"
+ * MX:<varies>
+ *
+ * It should be noted that when Microsoft Vista is still learning its IP
+ * address, it sends out host lines like: HOST:[FF02::C]:1900
+ */
+static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
+ struct sockaddr_in *client, const char *data)
+{
+ const char *start = data;
+ const char *end;
+ int got_host = 0;
+ int got_st = 0, st_match = 0;
+ int got_man = 0;
+ int got_mx = 0;
+ int mx = 0;
+
+ /*
+ * Skip first line M-SEARCH * HTTP/1.1
+ * (perhaps we should check remainder of the line for syntax)
+ */
+ data += line_length(data);
+
+ /* Parse remaining lines */
+ for (; *data != '\0'; data += line_length(data)) {
+ end = data + line_length_stripped(data);
+ if (token_eq(data, "host")) {
+ /* The host line indicates who the packet
+ * is addressed to... but do we really care?
+ * Note that Microsoft sometimes does funny
+ * stuff with the HOST: line.
+ */
+#if 0 /* could be */
+ data += token_length(data);
+ data += word_separation_length(data);
+ if (*data != ':')
+ goto bad;
+ data++;
+ data += word_separation_length(data);
+ /* UPNP_MULTICAST_ADDRESS */
+ if (!str_starts(data, "239.255.255.250"))
+ goto bad;
+ data += os_strlen("239.255.255.250");
+ if (*data == ':') {
+ if (!str_starts(data, ":1900"))
+ goto bad;
+ }
+#endif /* could be */
+ got_host = 1;
+ continue;
+ } else if (token_eq(data, "st")) {
+ /* There are a number of forms; we look
+ * for one that matches our case.
+ */
+ got_st = 1;
+ data += token_length(data);
+ data += word_separation_length(data);
+ if (*data != ':')
+ continue;
+ data++;
+ data += word_separation_length(data);
+ if (str_starts(data, "ssdp:all")) {
+ st_match = 1;
+ continue;
+ }
+ if (str_starts(data, "upnp:rootdevice")) {
+ st_match = 1;
+ continue;
+ }
+ if (str_starts(data, "uuid:")) {
+ char uuid_string[80];
+ data += os_strlen("uuid:");
+ uuid_bin2str(sm->wps->uuid, uuid_string,
+ sizeof(uuid_string));
+ if (str_starts(data, uuid_string))
+ st_match = 1;
+ continue;
+ }
+#if 0
+ /* FIX: should we really reply to IGD string? */
+ if (str_starts(data, "urn:schemas-upnp-org:device:"
+ "InternetGatewayDevice:1")) {
+ st_match = 1;
+ continue;
+ }
+#endif
+ if (str_starts(data, "urn:schemas-wifialliance-org:"
+ "service:WFAWLANConfig:1")) {
+ st_match = 1;
+ continue;
+ }
+ if (str_starts(data, "urn:schemas-wifialliance-org:"
+ "device:WFADevice:1")) {
+ st_match = 1;
+ continue;
+ }
+ continue;
+ } else if (token_eq(data, "man")) {
+ data += token_length(data);
+ data += word_separation_length(data);
+ if (*data != ':')
+ continue;
+ data++;
+ data += word_separation_length(data);
+ if (!str_starts(data, "\"ssdp:discover\"")) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Unexpected "
+ "M-SEARCH man-field");
+ goto bad;
+ }
+ got_man = 1;
+ continue;
+ } else if (token_eq(data, "mx")) {
+ data += token_length(data);
+ data += word_separation_length(data);
+ if (*data != ':')
+ continue;
+ data++;
+ data += word_separation_length(data);
+ mx = atol(data);
+ got_mx = 1;
+ continue;
+ }
+ /* ignore anything else */
+ }
+ if (!got_host || !got_st || !got_man || !got_mx || mx < 0) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid M-SEARCH: %d %d %d "
+ "%d mx=%d", got_host, got_st, got_man, got_mx, mx);
+ goto bad;
+ }
+ if (!st_match) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored M-SEARCH (no ST "
+ "match)");
+ return;
+ }
+ if (mx > 120)
+ mx = 120; /* UPnP-arch-DeviceArchitecture, 1.2.3 */
+ msearchreply_state_machine_start(sm, client, mx);
+ return;
+
+bad:
+ wpa_printf(MSG_INFO, "WPS UPnP: Failed to parse M-SEARCH");
+ wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH data:\n%s", start);
+}
+
+
+/* Listening for (UDP) discovery (M-SEARCH) packets */
+
+/**
+ * ssdp_listener_stop - Stop SSDP listered
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ *
+ * This function stops the SSDP listerner that was started by calling
+ * ssdp_listener_start().
+ */
+void ssdp_listener_stop(struct upnp_wps_device_sm *sm)
+{
+ if (sm->ssdp_sd_registered) {
+ eloop_unregister_sock(sm->ssdp_sd, EVENT_TYPE_READ);
+ sm->ssdp_sd_registered = 0;
+ }
+
+ if (sm->ssdp_sd != -1) {
+ close(sm->ssdp_sd);
+ sm->ssdp_sd = -1;
+ }
+
+ eloop_cancel_timeout(msearchreply_state_machine_handler, sm,
+ ELOOP_ALL_CTX);
+}
+
+
+static void ssdp_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct upnp_wps_device_sm *sm = sock_ctx;
+ struct sockaddr_in addr; /* client address */
+ socklen_t addr_len;
+ int nread;
+ char buf[MULTICAST_MAX_READ], *pos;
+
+ addr_len = sizeof(addr);
+ nread = recvfrom(sm->ssdp_sd, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &addr, &addr_len);
+ if (nread <= 0)
+ return;
+ buf[nread] = '\0'; /* need null termination for algorithm */
+
+ if (str_starts(buf, "NOTIFY ")) {
+ /*
+ * Silently ignore NOTIFYs to avoid filling debug log with
+ * unwanted messages.
+ */
+ return;
+ }
+
+ pos = os_strchr(buf, '\n');
+ if (pos)
+ *pos = '\0';
+ wpa_printf(MSG_MSGDUMP, "WPS UPnP: Received SSDP packet from %s:%d: "
+ "%s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), buf);
+ if (pos)
+ *pos = '\n';
+
+ /* Parse first line */
+ if (os_strncasecmp(buf, "M-SEARCH", os_strlen("M-SEARCH")) == 0 &&
+ !isgraph(buf[strlen("M-SEARCH")])) {
+ ssdp_parse_msearch(sm, &addr, buf);
+ return;
+ }
+
+ /* Ignore anything else */
+}
+
+
+/**
+ * ssdp_listener_start - Set up for receiving discovery (UDP) packets
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * The SSDP listerner is stopped by calling ssdp_listener_stop().
+ */
+int ssdp_listener_start(struct upnp_wps_device_sm *sm)
+{
+ int sd = -1;
+ struct sockaddr_in addr;
+ struct ip_mreq mcast_addr;
+ int on = 1;
+ /* per UPnP spec, keep IP packet time to live (TTL) small */
+ unsigned char ttl = 4;
+
+ sm->ssdp_sd = sd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sd < 0)
+ goto fail;
+ if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
+ goto fail;
+ if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
+ goto fail;
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = htons(UPNP_MULTICAST_PORT);
+ if (bind(sd, (struct sockaddr *) &addr, sizeof(addr)))
+ goto fail;
+ os_memset(&mcast_addr, 0, sizeof(mcast_addr));
+ mcast_addr.imr_interface.s_addr = htonl(INADDR_ANY);
+ mcast_addr.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+ if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *) &mcast_addr, sizeof(mcast_addr)))
+ goto fail;
+ if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
+ &ttl, sizeof(ttl)))
+ goto fail;
+ if (eloop_register_sock(sd, EVENT_TYPE_READ, ssdp_listener_handler,
+ NULL, sm))
+ goto fail;
+ sm->ssdp_sd_registered = 1;
+ return 0;
+
+fail:
+ /* Error */
+ wpa_printf(MSG_ERROR, "WPS UPnP: ssdp_listener_start failed");
+ ssdp_listener_stop(sm);
+ return -1;
+}
+
+
+/**
+ * add_ssdp_network - Add routing entry for SSDP
+ * @net_if: Selected network interface name
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function assures that the multicast address will be properly
+ * handled by Linux networking code (by a modification to routing tables).
+ * This must be done per network interface. It really only needs to be done
+ * once after booting up, but it does not hurt to call this more frequently
+ * "to be safe".
+ */
+int add_ssdp_network(char *net_if)
+{
+ int ret = -1;
+ int sock = -1;
+ struct rtentry rt;
+ struct sockaddr_in *sin;
+
+ if (!net_if)
+ goto fail;
+
+ os_memset(&rt, 0, sizeof(rt));
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ goto fail;
+
+ rt.rt_dev = net_if;
+ sin = (struct sockaddr_in *) &rt.rt_dst;
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+ sin->sin_addr.s_addr = inet_addr(SSDP_TARGET);
+ sin = (struct sockaddr_in *) &rt.rt_genmask;
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+ sin->sin_addr.s_addr = inet_addr(SSDP_NETMASK);
+ rt.rt_flags = RTF_UP;
+ if (ioctl(sock, SIOCADDRT, &rt) < 0) {
+ if (errno == EPERM) {
+ wpa_printf(MSG_DEBUG, "add_ssdp_network: No "
+ "permissions to add routing table entry");
+ /* Continue to allow testing as non-root */
+ } else if (errno != EEXIST) {
+ wpa_printf(MSG_INFO, "add_ssdp_network() ioctl errno "
+ "%d (%s)", errno, strerror(errno));
+ goto fail;
+ }
+ }
+
+ ret = 0;
+
+fail:
+ if (sock >= 0)
+ close(sock);
+
+ return ret;
+}
+
+
+/**
+ * ssdp_open_multicast - Open socket for sending multicast SSDP messages
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
+{
+ int sd = -1;
+ /* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet
+ * time to live (TTL) small */
+ unsigned char ttl = 4;
+
+ sm->multicast_sd = sd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sd < 0)
+ return -1;
+
+#if 0 /* maybe ok if we sometimes block on writes */
+ if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
+ return -1;
+#endif
+
+ if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
+ &sm->ip_addr, sizeof(sm->ip_addr)))
+ return -1;
+ if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
+ &ttl, sizeof(ttl)))
+ return -1;
+
+#if 0 /* not needed, because we don't receive using multicast_sd */
+ {
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+ mreq.imr_interface.s_addr = sm->ip_addr;
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Multicast addr 0x%x if addr "
+ "0x%x",
+ mreq.imr_multiaddr.s_addr,
+ mreq.imr_interface.s_addr);
+ if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
+ sizeof(mreq))) {
+ wpa_printf(MSG_ERROR,
+ "WPS UPnP: setsockopt "
+ "IP_ADD_MEMBERSHIP errno %d (%s)",
+ errno, strerror(errno));
+ return -1;
+ }
+ }
+#endif /* not needed */
+
+ /*
+ * TODO: What about IP_MULTICAST_LOOP? It seems to be on by default?
+ * which aids debugging I suppose but isn't really necessary?
+ */
+
+ return 0;
+}
Added: wpasupplicant/branches/upstream/current/src/wps/wps_upnp_web.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_upnp_web.c?rev=1324&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_upnp_web.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_upnp_web.c Sun Feb 15 19:38:55 2009
@@ -1,0 +1,1964 @@
+/*
+ * UPnP WPS Device - Web connections
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#include "includes.h"
+#include <fcntl.h>
+
+#include "common.h"
+#include "base64.h"
+#include "eloop.h"
+#include "uuid.h"
+#include "httpread.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+/***************************************************************************
+ * Web connections (we serve pages of info about ourselves, handle
+ * requests, etc. etc.).
+ **************************************************************************/
+
+#define WEB_CONNECTION_TIMEOUT_SEC 30 /* Drop web connection after t.o. */
+#define WEB_CONNECTION_MAX_READ 8000 /* Max we'll read for TCP request */
+#define MAX_WEB_CONNECTIONS 10 /* max simultaneous web connects */
+
+
+static const char *urn_wfawlanconfig =
+ "urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
+static const char *http_server_hdr =
+ "Server: unspecified, UPnP/1.0, unspecified\r\n";
+static const char *http_connection_close =
+ "Connection: close\r\n";
+
+/*
+ * Incoming web connections are recorded in this struct.
+ * A web connection is a TCP connection to us, the server;
+ * it is called a "web connection" because we use http and serve
+ * data that looks like web pages.
+ * State information is need to track the connection until we figure
+ * out what they want and what we want to do about it.
+ */
+struct web_connection {
+ /* double linked list */
+ struct web_connection *next;
+ struct web_connection *prev;
+ struct upnp_wps_device_sm *sm; /* parent */
+ int sd; /* socket to read from */
+ struct sockaddr_in cli_addr;
+ int sd_registered; /* nonzero if we must cancel registration */
+ struct httpread *hread; /* state machine for reading socket */
+ int n_rcvd_data; /* how much data read so far */
+ int done; /* internal flag, set when we've finished */
+};
+
+
+/*
+ * XML parsing and formatting
+ *
+ * XML is a markup language based on unicode; usually (and in our case,
+ * always!) based on utf-8. utf-8 uses a variable number of bytes per
+ * character. utf-8 has the advantage that all non-ASCII unicode characters are
+ * represented by sequences of non-ascii (high bit set) bytes, whereas ASCII
+ * characters are single ascii bytes, thus we can use typical text processing.
+ *
+ * (One other interesting thing about utf-8 is that it is possible to look at
+ * any random byte and determine if it is the first byte of a character as
+ * versus a continuation byte).
+ *
+ * The base syntax of XML uses a few ASCII punctionation characters; any
+ * characters that would appear in the payload data are rewritten using
+ * sequences, e.g., & for ampersand(&) and < for left angle bracket (<).
+ * Five such escapes total (more can be defined but that does not apply to our
+ * case). Thus we can safely parse for angle brackets etc.
+ *
+ * XML describes tree structures of tagged data, with each element beginning
+ * with an opening tag <label> and ending with a closing tag </label> with
+ * matching label. (There is also a self-closing tag <label/> which is supposed
+ * to be equivalent to <label></label>, i.e., no payload, but we are unlikely
+ * to see it for our purpose).
+ *
+ * Actually the opening tags are a little more complicated because they can
+ * contain "attributes" after the label (delimited by ascii space or tab chars)
+ * of the form attribute_label="value" or attribute_label='value'; as it turns
+ * out we do not have to read any of these attributes, just ignore them.
+ *
+ * Labels are any sequence of chars other than space, tab, right angle bracket
+ * (and ?), but may have an inner structure of <namespace><colon><plain_label>.
+ * As it turns out, we can ignore the namespaces, in fact we can ignore the
+ * entire tree hierarchy, because the plain labels we are looking for will be
+ * unique (not in general, but for this application). We do however have to be
+ * careful to skip over the namespaces.
+ *
+ * In generating XML we have to be more careful, but that is easy because
+ * everything we do is pretty canned. The only real care to take is to escape
+ * any special chars in our payload.
+ */
+
+/**
+ * xml_next_tag - Advance to next tag
+ * @in: Input
+ * @out: OUT: start of tag just after '<'
+ * @out_tagname: OUT: start of name of tag, skipping namespace
+ * @end: OUT: one after tag
+ * Returns: 0 on success, 1 on failure
+ *
+ * A tag has form:
+ * <left angle bracket><...><right angle bracket>
+ * Within the angle brackets, there is an optional leading forward slash (which
+ * makes the tag an ending tag), then an optional leading label (followed by
+ * colon) and then the tag name itself.
+ *
+ * Note that angle brackets present in the original data must have been encoded
+ * as < and > so they will not trouble us.
+ */
+static int xml_next_tag(char *in, char **out, char **out_tagname,
+ char **end)
+{
+ while (*in && *in != '<')
+ in++;
+ if (*in != '<')
+ return 1;
+ *out = ++in;
+ if (*in == '/')
+ in++;
+ *out_tagname = in; /* maybe */
+ while (isalnum(*in) || *in == '-')
+ in++;
+ if (*in == ':')
+ *out_tagname = ++in;
+ while (*in && *in != '>')
+ in++;
+ if (*in != '>')
+ return 1;
+ *end = ++in;
+ return 0;
+}
+
+
+/* xml_data_encode -- format data for xml file, escaping special characters.
+ *
+ * Note that we assume we are using utf8 both as input and as output!
+ * In utf8, characters may be classed as follows:
+ * 0xxxxxxx(2) -- 1 byte ascii char
+ * 11xxxxxx(2) -- 1st byte of multi-byte char w/ unicode value >= 0x80
+ * 110xxxxx(2) -- 1st byte of 2 byte sequence (5 payload bits here)
+ * 1110xxxx(2) -- 1st byte of 3 byte sequence (4 payload bits here)
+ * 11110xxx(2) -- 1st byte of 4 byte sequence (3 payload bits here)
+ * 10xxxxxx(2) -- extension byte (6 payload bits per byte)
+ * Some values implied by the above are however illegal because they
+ * do not represent unicode chars or are not the shortest encoding.
+ * Actually, we can almost entirely ignore the above and just do
+ * text processing same as for ascii text.
+ *
+ * XML is written with arbitrary unicode characters, except that five
+ * characters have special meaning and so must be escaped where they
+ * appear in payload data... which we do here.
+ */
+static void xml_data_encode(struct wpabuf *buf, const char *data, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ u8 c = ((u8 *) data)[i];
+ if (c == '<') {
+ wpabuf_put_str(buf, "<");
+ continue;
+ }
+ if (c == '>') {
+ wpabuf_put_str(buf, ">");
+ continue;
+ }
+ if (c == '&') {
+ wpabuf_put_str(buf, "&");
+ continue;
+ }
+ if (c == '\'') {
+ wpabuf_put_str(buf, "'");
+ continue;
+ }
+ if (c == '"') {
+ wpabuf_put_str(buf, """);
+ continue;
+ }
+ /*
+ * We could try to represent control characters using the
+ * sequence: &#x; where x is replaced by a hex numeral, but not
+ * clear why we would do this.
+ */
+ wpabuf_put_u8(buf, c);
+ }
+}
+
+
+/* xml_add_tagged_data -- format tagged data as a new xml line.
+ *
+ * tag must not have any special chars.
+ * data may have special chars, which are escaped.
+ */
+static void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
+ const char *data)
+{
+ wpabuf_printf(buf, "<%s>", tag);
+ xml_data_encode(buf, data, os_strlen(data));
+ wpabuf_printf(buf, "</%s>\n", tag);
+}
+
+
+/* A POST body looks something like (per upnp spec):
+ * <?xml version="1.0"?>
+ * <s:Envelope
+ * xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
+ * s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ * <s:Body>
+ * <u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
+ * <argumentName>in arg value</argumentName>
+ * other in args and their values go here, if any
+ * </u:actionName>
+ * </s:Body>
+ * </s:Envelope>
+ *
+ * where :
+ * s: might be some other namespace name followed by colon
+ * u: might be some other namespace name followed by colon
+ * actionName will be replaced according to action requested
+ * schema following actionName will be WFA scheme instead
+ * argumentName will be actual argument name
+ * (in arg value) will be actual argument value
+ */
+static int
+upnp_get_first_document_item(char *doc, const char *item, char **value)
+{
+ const char *match = item;
+ int match_len = os_strlen(item);
+ char *tag;
+ char *tagname;
+ char *end;
+
+ *value = NULL; /* default, bad */
+
+ /*
+ * This is crude: ignore any possible tag name conflicts and go right
+ * to the first tag of this name. This should be ok for the limited
+ * domain of UPnP messages.
+ */
+ for (;;) {
+ if (xml_next_tag(doc, &tag, &tagname, &end))
+ return 1;
+ doc = end;
+ if (!os_strncasecmp(tagname, match, match_len) &&
+ *tag != '/' &&
+ (tagname[match_len] == '>' ||
+ !isgraph(tagname[match_len]))) {
+ break;
+ }
+ }
+ end = doc;
+ while (*end && *end != '<')
+ end++;
+ *value = os_zalloc(1 + (end - doc));
+ if (*value == NULL)
+ return 1;
+ os_memcpy(*value, doc, end - doc);
+ return 0;
+}
+
+
+/*
+ * "Files" that we serve via HTTP. The format of these files is given by
+ * WFA WPS specifications. Extra white space has been removed to save space.
+ */
+
+static const char wps_scpd_xml[] =
+"<?xml version=\"1.0\"?>\n"
+"<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\n"
+"<specVersion><major>1</major><minor>0</minor></specVersion>\n"
+"<actionList>\n"
+"<action>\n"
+"<name>GetDeviceInfo</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewDeviceInfo</name>\n"
+"<direction>out</direction>\n"
+"<relatedStateVariable>DeviceInfo</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>PutMessage</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewInMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>InMessage</relatedStateVariable>\n"
+"</argument>\n"
+"<argument>\n"
+"<name>NewOutMessage</name>\n"
+"<direction>out</direction>\n"
+"<relatedStateVariable>OutMessage</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>GetAPSettings</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>Message</relatedStateVariable>\n"
+"</argument>\n"
+"<argument>\n"
+"<name>NewAPSettings</name>\n"
+"<direction>out</direction>\n"
+"<relatedStateVariable>APSettings</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>SetAPSettings</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>APSettings</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>APSettings</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>DelAPSettings</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewAPSettings</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>APSettings</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>GetSTASettings</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>Message</relatedStateVariable>\n"
+"</argument>\n"
+"<argument>\n"
+"<name>NewSTASettings</name>\n"
+"<direction>out</direction>\n"
+"<relatedStateVariable>STASettings</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>SetSTASettings</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewSTASettings</name>\n"
+"<direction>out</direction>\n"
+"<relatedStateVariable>STASettings</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>DelSTASettings</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewSTASettings</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>STASettings</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>PutWLANResponse</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>Message</relatedStateVariable>\n"
+"</argument>\n"
+"<argument>\n"
+"<name>NewWLANEventType</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>WLANEventType</relatedStateVariable>\n"
+"</argument>\n"
+"<argument>\n"
+"<name>NewWLANEventMAC</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>WLANEventMAC</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>SetSelectedRegistrar</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>Message</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>RebootAP</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewAPSettings</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>APSettings</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>ResetAP</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>Message</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>RebootSTA</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewSTASettings</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>APSettings</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>ResetSTA</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>Message</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"</actionList>\n"
+"<serviceStateTable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>Message</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>InMessage</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>OutMessage</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>DeviceInfo</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>APSettings</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"yes\">\n"
+"<name>APStatus</name>\n"
+"<dataType>ui1</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>STASettings</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"yes\">\n"
+"<name>STAStatus</name>\n"
+"<dataType>ui1</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"yes\">\n"
+"<name>WLANEvent</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>WLANEventType</name>\n"
+"<dataType>ui1</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>WLANEventMAC</name>\n"
+"<dataType>string</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>WLANResponse</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"</serviceStateTable>\n"
+"</scpd>\n"
+;
+
+
+static const char *wps_device_xml_prefix =
+ "<?xml version=\"1.0\"?>\n"
+ "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
+ "<specVersion>\n"
+ "<major>1</major>\n"
+ "<minor>0</minor>\n"
+ "</specVersion>\n"
+ "<device>\n"
+ "<deviceType>urn:schemas-wifialliance-org:device:WFADevice:1"
+ "</deviceType>\n";
+
+static const char *wps_device_xml_postfix =
+ "<serviceList>\n"
+ "<service>\n"
+ "<serviceType>urn:schemas-wifialliance-org:service:WFAWLANConfig:1"
+ "</serviceType>\n"
+ "<serviceId>urn:wifialliance-org:serviceId:WFAWLANConfig1</serviceId>"
+ "\n"
+ "<SCPDURL>" UPNP_WPS_SCPD_XML_FILE "</SCPDURL>\n"
+ "<controlURL>" UPNP_WPS_DEVICE_CONTROL_FILE "</controlURL>\n"
+ "<eventSubURL>" UPNP_WPS_DEVICE_EVENT_FILE "</eventSubURL>\n"
+ "</service>\n"
+ "</serviceList>\n"
+ "</device>\n"
+ "</root>\n";
+
+
+/* format_wps_device_xml -- produce content of "file" wps_device.xml
+ * (UPNP_WPS_DEVICE_XML_FILE)
+ */
+static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
+ struct wpabuf *buf)
+{
+ const char *s;
+ char uuid_string[80];
+
+ wpabuf_put_str(buf, wps_device_xml_prefix);
+
+ /*
+ * Add required fields with default values if not configured. Add
+ * optional and recommended fields only if configured.
+ */
+ s = sm->wps->friendly_name;
+ s = ((s && *s) ? s : "WPS Access Point");
+ xml_add_tagged_data(buf, "friendlyName", s);
+
+ s = sm->wps->dev.manufacturer;
+ s = ((s && *s) ? s : "");
+ xml_add_tagged_data(buf, "manufacturer", s);
+
+ if (sm->wps->manufacturer_url)
+ xml_add_tagged_data(buf, "manufacturerURL",
+ sm->wps->manufacturer_url);
+
+ if (sm->wps->model_description)
+ xml_add_tagged_data(buf, "modelDescription",
+ sm->wps->model_description);
+
+ s = sm->wps->dev.model_name;
+ s = ((s && *s) ? s : "");
+ xml_add_tagged_data(buf, "modelName", s);
+
+ if (sm->wps->dev.model_number)
+ xml_add_tagged_data(buf, "modelNumber",
+ sm->wps->dev.model_number);
+
+ if (sm->wps->model_url)
+ xml_add_tagged_data(buf, "modelURL", sm->wps->model_url);
+
+ if (sm->wps->dev.serial_number)
+ xml_add_tagged_data(buf, "serialNumber",
+ sm->wps->dev.serial_number);
+
+ uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string));
+ s = uuid_string;
+ /* Need "uuid:" prefix, thus we can't use xml_add_tagged_data()
+ * easily...
+ */
+ wpabuf_put_str(buf, "<UDN>uuid:");
+ xml_data_encode(buf, s, os_strlen(s));
+ wpabuf_put_str(buf, "</UDN>\n");
+
+ if (sm->wps->upc)
+ xml_add_tagged_data(buf, "UPC", sm->wps->upc);
+
+ wpabuf_put_str(buf, wps_device_xml_postfix);
+}
+
+
+void web_connection_stop(struct web_connection *c)
+{
+ struct upnp_wps_device_sm *sm = c->sm;
+
+ httpread_destroy(c->hread);
+ c->hread = NULL;
+ close(c->sd);
+ c->sd = -1;
+ if (c->next == c) {
+ sm->web_connections = NULL;
+ } else {
+ if (sm->web_connections == c)
+ sm->web_connections = c->next;
+ c->next->prev = c->prev;
+ c->prev->next = c->next;
+ }
+ os_free(c);
+ sm->n_web_connections--;
+}
+
+
+static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
+{
+ wpabuf_put_str(buf, "HTTP/1.1 ");
+ switch (code) {
+ case HTTP_OK:
+ wpabuf_put_str(buf, "200 OK\r\n");
+ break;
+ case HTTP_BAD_REQUEST:
+ wpabuf_put_str(buf, "400 Bad request\r\n");
+ break;
+ case HTTP_PRECONDITION_FAILED:
+ wpabuf_put_str(buf, "412 Precondition failed\r\n");
+ break;
+ case HTTP_UNIMPLEMENTED:
+ wpabuf_put_str(buf, "501 Unimplemented\r\n");
+ break;
+ case HTTP_INTERNAL_SERVER_ERROR:
+ default:
+ wpabuf_put_str(buf, "500 Internal server error\r\n");
+ break;
+ }
+}
+
+
+static void http_put_date(struct wpabuf *buf)
+{
+ wpabuf_put_str(buf, "Date: ");
+ format_date(buf);
+ wpabuf_put_str(buf, "\r\n");
+}
+
+
+static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
+{
+ http_put_reply_code(buf, code);
+ wpabuf_put_str(buf, http_server_hdr);
+ wpabuf_put_str(buf, http_connection_close);
+ wpabuf_put_str(buf, "Content-Length: 0\r\n"
+ "\r\n");
+}
+
+
+/* Given that we have received a header w/ GET, act upon it
+ *
+ * Format of GET (case-insensitive):
+ *
+ * First line must be:
+ * GET /<file> HTTP/1.1
+ * Since we don't do anything fancy we just ignore other lines.
+ *
+ * Our response (if no error) which includes only required lines is:
+ * HTTP/1.1 200 OK
+ * Connection: close
+ * Content-Type: text/xml
+ * Date: <rfc1123-date>
+ *
+ * Header lines must end with \r\n
+ * Per RFC 2616, content-length: is not required but connection:close
+ * would appear to be required (given that we will be closing it!).
+ */
+static void web_connection_parse_get(struct web_connection *c, char *filename)
+{
+ struct upnp_wps_device_sm *sm = c->sm;
+ struct wpabuf *buf; /* output buffer, allocated */
+ char *put_length_here;
+ char *body_start;
+ enum {
+ GET_DEVICE_XML_FILE,
+ GET_SCPD_XML_FILE
+ } req;
+ size_t extra_len = 0;
+ int body_length;
+ char len_buf[10];
+
+ /*
+ * It is not required that filenames be case insensitive but it is
+ * allowed and cannot hurt here.
+ */
+ if (filename == NULL)
+ filename = "(null)"; /* just in case */
+ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
+ req = GET_DEVICE_XML_FILE;
+ extra_len = 3000;
+ if (sm->wps->friendly_name)
+ extra_len += os_strlen(sm->wps->friendly_name);
+ if (sm->wps->manufacturer_url)
+ extra_len += os_strlen(sm->wps->manufacturer_url);
+ if (sm->wps->model_description)
+ extra_len += os_strlen(sm->wps->model_description);
+ if (sm->wps->model_url)
+ extra_len += os_strlen(sm->wps->model_url);
+ if (sm->wps->upc)
+ extra_len += os_strlen(sm->wps->upc);
+ } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
+ req = GET_SCPD_XML_FILE;
+ extra_len = os_strlen(wps_scpd_xml);
+ } else {
+ /* File not found */
+ wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
+ filename);
+ buf = wpabuf_alloc(200);
+ if (buf == NULL)
+ return;
+ wpabuf_put_str(buf,
+ "HTTP/1.1 404 Not Found\r\n"
+ "Connection: close\r\n");
+
+ http_put_date(buf);
+
+ /* terminating empty line */
+ wpabuf_put_str(buf, "\r\n");
+
+ goto send_buf;
+ }
+
+ buf = wpabuf_alloc(1000 + extra_len);
+ if (buf == NULL)
+ return;
+
+ wpabuf_put_str(buf,
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/xml; charset=\"utf-8\"\r\n");
+ wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n");
+ wpabuf_put_str(buf, "Connection: close\r\n");
+ wpabuf_put_str(buf, "Content-Length: ");
+ /*
+ * We will paste the length in later, leaving some extra whitespace.
+ * HTTP code is supposed to be tolerant of extra whitespace.
+ */
+ put_length_here = wpabuf_put(buf, 0);
+ wpabuf_put_str(buf, " \r\n");
+
+ http_put_date(buf);
+
+ /* terminating empty line */
+ wpabuf_put_str(buf, "\r\n");
+
+ body_start = wpabuf_put(buf, 0);
+
+ switch (req) {
+ case GET_DEVICE_XML_FILE:
+ format_wps_device_xml(sm, buf);
+ break;
+ case GET_SCPD_XML_FILE:
+ wpabuf_put_str(buf, wps_scpd_xml);
+ break;
+ }
+
+ /* Now patch in the content length at the end */
+ body_length = (char *) wpabuf_put(buf, 0) - body_start;
+ os_snprintf(len_buf, 10, "%d", body_length);
+ os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
+
+send_buf:
+ send_wpabuf(c->sd, buf);
+ wpabuf_free(buf);
+}
+
+
+static struct wpabuf * web_get_item(char *data, const char *name,
+ enum http_reply_code *ret)
+{
+ char *msg;
+ struct wpabuf *buf;
+ unsigned char *decoded;
+ size_t len;
+
+ if (upnp_get_first_document_item(data, name, &msg)) {
+ *ret = UPNP_ARG_VALUE_INVALID;
+ return NULL;
+ }
+
+ decoded = base64_decode((unsigned char *) msg, os_strlen(msg), &len);
+ os_free(msg);
+ if (decoded == NULL) {
+ *ret = UPNP_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ buf = wpabuf_alloc_ext_data(decoded, len);
+ if (buf == NULL) {
+ os_free(decoded);
+ *ret = UPNP_OUT_OF_MEMORY;
+ return NULL;
+ }
+ return buf;
+}
+
+
+static enum http_reply_code
+web_process_get_device_info(struct upnp_wps_device_sm *sm,
+ struct wpabuf **reply, const char **replyname)
+{
+ static const char *name = "NewDeviceInfo";
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
+ if (sm->ctx->rx_req_get_device_info == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ *reply = sm->ctx->rx_req_get_device_info(sm->priv, &sm->peer);
+ if (*reply == NULL) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ *replyname = name;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ static const char *name = "NewOutMessage";
+ enum http_reply_code ret;
+
+ /*
+ * PutMessage is used by external UPnP-based Registrar to perform WPS
+ * operation with the access point itself; as compared with
+ * PutWLANResponse which is for proxying.
+ */
+ wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
+ if (sm->ctx->rx_req_put_message == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ msg = web_get_item(data, "NewInMessage", &ret);
+ if (msg == NULL)
+ return ret;
+ *reply = sm->ctx->rx_req_put_message(sm->priv, &sm->peer, msg);
+ wpabuf_free(msg);
+ if (*reply == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ *replyname = name;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_get_ap_settings(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ static const char *name = "NewAPSettings";
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: GetAPSettings");
+ if (sm->ctx->rx_req_get_ap_settings == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ msg = web_get_item(data, "NewMessage", &ret);
+ if (msg == NULL)
+ return ret;
+ *reply = sm->ctx->rx_req_get_ap_settings(sm->priv, msg);
+ wpabuf_free(msg);
+ if (*reply == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ *replyname = name;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_set_ap_settings(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: SetAPSettings");
+ msg = web_get_item(data, "NewAPSettings", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_set_ap_settings ||
+ sm->ctx->rx_req_set_ap_settings(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_del_ap_settings(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: DelAPSettings");
+ msg = web_get_item(data, "NewAPSettings", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_del_ap_settings ||
+ sm->ctx->rx_req_del_ap_settings(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_get_sta_settings(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ static const char *name = "NewSTASettings";
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: GetSTASettings");
+ if (sm->ctx->rx_req_get_sta_settings == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ msg = web_get_item(data, "NewMessage", &ret);
+ if (msg == NULL)
+ return ret;
+ *reply = sm->ctx->rx_req_get_sta_settings(sm->priv, msg);
+ wpabuf_free(msg);
+ if (*reply == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ *replyname = name;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_set_sta_settings(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: SetSTASettings");
+ msg = web_get_item(data, "NewSTASettings", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_set_sta_settings ||
+ sm->ctx->rx_req_set_sta_settings(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_del_sta_settings(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: DelSTASettings");
+ msg = web_get_item(data, "NewSTASettings", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_del_sta_settings ||
+ sm->ctx->rx_req_del_sta_settings(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+ u8 macaddr[ETH_ALEN];
+ int ev_type;
+ int type;
+ char *val;
+
+ /*
+ * External UPnP-based Registrar is passing us a message to be proxied
+ * over to a Wi-Fi -based client of ours.
+ */
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
+ msg = web_get_item(data, "NewMessage", &ret);
+ if (msg == NULL)
+ return ret;
+ if (upnp_get_first_document_item(data, "NewWLANEventType", &val)) {
+ wpabuf_free(msg);
+ return UPNP_ARG_VALUE_INVALID;
+ }
+ ev_type = atol(val);
+ os_free(val);
+ val = NULL;
+ if (upnp_get_first_document_item(data, "NewWLANEventMAC", &val) ||
+ hwaddr_aton(val, macaddr)) {
+ wpabuf_free(msg);
+ os_free(val);
+ return UPNP_ARG_VALUE_INVALID;
+ }
+ os_free(val);
+ if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
+ struct wps_parse_attr attr;
+ if (wps_parse_msg(msg, &attr) < 0 ||
+ attr.msg_type == NULL)
+ type = -1;
+ else
+ type = *attr.msg_type;
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
+ } else
+ type = -1;
+ if (!sm->ctx->rx_req_put_wlan_response ||
+ sm->ctx->rx_req_put_wlan_response(sm->priv, ev_type, macaddr, msg,
+ type)) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
+ "rx_req_put_wlan_response");
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_set_selected_registrar(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply,
+ const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
+ msg = web_get_item(data, "NewMessage", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_set_selected_registrar ||
+ sm->ctx->rx_req_set_selected_registrar(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_reboot_ap(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: RebootAP");
+ msg = web_get_item(data, "NewAPSettings", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_reboot_ap ||
+ sm->ctx->rx_req_reboot_ap(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_reset_ap(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: ResetAP");
+ msg = web_get_item(data, "NewMessage", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_reset_ap ||
+ sm->ctx->rx_req_reset_ap(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_reboot_sta(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: RebootSTA");
+ msg = web_get_item(data, "NewSTASettings", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_reboot_sta ||
+ sm->ctx->rx_req_reboot_sta(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_reset_sta(struct upnp_wps_device_sm *sm, char *data,
+ struct wpabuf **reply, const char **replyname)
+{
+ struct wpabuf *msg;
+ enum http_reply_code ret;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: ResetSTA");
+ msg = web_get_item(data, "NewMessage", &ret);
+ if (msg == NULL)
+ return ret;
+ if (!sm->ctx->rx_req_reset_sta ||
+ sm->ctx->rx_req_reset_sta(sm->priv, msg)) {
+ wpabuf_free(msg);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ wpabuf_free(msg);
+ *replyname = NULL;
+ *reply = NULL;
+ return HTTP_OK;
+}
+
+
+static const char *soap_prefix =
+ "<?xml version=\"1.0\"?>\n"
+ "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+ "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
+ "<s:Body>\n";
+static const char *soap_postfix =
+ "</s:Body>\n</s:Envelope>\n";
+
+static const char *soap_error_prefix =
+ "<s:Fault>\n"
+ "<faultcode>s:Client</faultcode>\n"
+ "<faultstring>UPnPError</faultstring>\n"
+ "<detail>\n"
+ "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n";
+static const char *soap_error_postfix =
+ "<errorDescription>Error</errorDescription>\n"
+ "</UPnPError>\n"
+ "</detail>\n"
+ "</s:Fault>\n";
+
+static void web_connection_send_reply(struct web_connection *c,
+ enum http_reply_code ret,
+ const char *action, int action_len,
+ const struct wpabuf *reply,
+ const char *replyname)
+{
+ struct wpabuf *buf;
+ char *replydata;
+ char *put_length_here = NULL;
+ char *body_start = NULL;
+
+ if (reply) {
+ size_t len;
+ replydata = (char *) base64_encode(wpabuf_head(reply),
+ wpabuf_len(reply), &len);
+ } else
+ replydata = NULL;
+
+ /* Parameters of the response:
+ * action(action_len) -- action we are responding to
+ * replyname -- a name we need for the reply
+ * replydata -- NULL or null-terminated string
+ */
+ buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) +
+ (action_len > 0 ? action_len * 2 : 0));
+ if (buf == NULL) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
+ "POST");
+ wpabuf_free(buf);
+ os_free(replydata);
+ return;
+ }
+
+ /*
+ * Assuming we will be successful, put in the output header first.
+ * Note: we do not keep connections alive (and httpread does
+ * not support it)... therefore we must have Connection: close.
+ */
+ if (ret == HTTP_OK) {
+ wpabuf_put_str(buf,
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/xml; "
+ "charset=\"utf-8\"\r\n");
+ } else {
+ wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret);
+ }
+ wpabuf_put_str(buf, http_connection_close);
+
+ wpabuf_put_str(buf, "Content-Length: ");
+ /*
+ * We will paste the length in later, leaving some extra whitespace.
+ * HTTP code is supposed to be tolerant of extra whitespace.
+ */
+ put_length_here = wpabuf_put(buf, 0);
+ wpabuf_put_str(buf, " \r\n");
+
+ http_put_date(buf);
+
+ /* terminating empty line */
+ wpabuf_put_str(buf, "\r\n");
+
+ body_start = wpabuf_put(buf, 0);
+
+ if (ret == HTTP_OK) {
+ wpabuf_put_str(buf, soap_prefix);
+ wpabuf_put_str(buf, "<u:");
+ wpabuf_put_data(buf, action, action_len);
+ wpabuf_put_str(buf, "Response xmlns:u=\"");
+ wpabuf_put_str(buf, urn_wfawlanconfig);
+ wpabuf_put_str(buf, "\">\n");
+ if (replydata && replyname) {
+ /* TODO: might possibly need to escape part of reply
+ * data? ...
+ * probably not, unlikely to have ampersand(&) or left
+ * angle bracket (<) in it...
+ */
+ wpabuf_printf(buf, "<%s>", replyname);
+ wpabuf_put_str(buf, replydata);
+ wpabuf_printf(buf, "</%s>\n", replyname);
+ }
+ wpabuf_put_str(buf, "</u:");
+ wpabuf_put_data(buf, action, action_len);
+ wpabuf_put_str(buf, "Response>\n");
+ wpabuf_put_str(buf, soap_postfix);
+ } else {
+ /* Error case */
+ wpabuf_put_str(buf, soap_prefix);
+ wpabuf_put_str(buf, soap_error_prefix);
+ wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret);
+ wpabuf_put_str(buf, soap_error_postfix);
+ wpabuf_put_str(buf, soap_postfix);
+ }
+ os_free(replydata);
+
+ /* Now patch in the content length at the end */
+ if (body_start && put_length_here) {
+ int body_length = (char *) wpabuf_put(buf, 0) - body_start;
+ char len_buf[10];
+ os_snprintf(len_buf, sizeof(len_buf), "%d", body_length);
+ os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
+ }
+
+ send_wpabuf(c->sd, buf);
+ wpabuf_free(buf);
+}
+
+
+static const char * web_get_action(struct web_connection *c,
+ const char *filename, size_t *action_len)
+{
+ const char *match;
+ int match_len;
+ char *b;
+ char *action;
+
+ *action_len = 0;
+ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
+ filename);
+ return NULL;
+ }
+ /* The SOAPAction line of the header tells us what we want to do */
+ b = httpread_hdr_line_get(c->hread, "SOAPAction:");
+ if (b == NULL)
+ return NULL;
+ if (*b == '"')
+ b++;
+ else
+ return NULL;
+ match = urn_wfawlanconfig;
+ match_len = os_strlen(urn_wfawlanconfig) - 1;
+ if (os_strncasecmp(b, match, match_len))
+ return NULL;
+ b += match_len;
+ /* skip over version */
+ while (isgraph(*b) && *b != '#')
+ b++;
+ if (*b != '#')
+ return NULL;
+ b++;
+ /* Following the sharp(#) should be the action and a double quote */
+ action = b;
+ while (isgraph(*b) && *b != '"')
+ b++;
+ if (*b != '"')
+ return NULL;
+ *action_len = b - action;
+ return action;
+}
+
+
+/* Given that we have received a header w/ POST, act upon it
+ *
+ * Format of POST (case-insensitive):
+ *
+ * First line must be:
+ * POST /<file> HTTP/1.1
+ * Since we don't do anything fancy we just ignore other lines.
+ *
+ * Our response (if no error) which includes only required lines is:
+ * HTTP/1.1 200 OK
+ * Connection: close
+ * Content-Type: text/xml
+ * Date: <rfc1123-date>
+ *
+ * Header lines must end with \r\n
+ * Per RFC 2616, content-length: is not required but connection:close
+ * would appear to be required (given that we will be closing it!).
+ */
+static void web_connection_parse_post(struct web_connection *c,
+ const char *filename)
+{
+ enum http_reply_code ret;
+ struct upnp_wps_device_sm *sm = c->sm;
+ char *data = httpread_data_get(c->hread); /* body of http msg */
+ const char *action;
+ size_t action_len;
+ const char *replyname = NULL; /* argument name for the reply */
+ struct wpabuf *reply = NULL; /* data for the reply */
+
+ ret = UPNP_INVALID_ACTION;
+ action = web_get_action(c, filename, &action_len);
+ if (action == NULL)
+ goto bad;
+
+ /*
+ * There are quite a few possible actions. Although we appear to
+ * support them all here, not all of them are necessarily supported by
+ * callbacks at higher levels.
+ */
+ if (!os_strncasecmp("GetDeviceInfo", action, action_len))
+ ret = web_process_get_device_info(sm, &reply, &replyname);
+ else if (!os_strncasecmp("PutMessage", action, action_len))
+ ret = web_process_put_message(sm, data, &reply, &replyname);
+ else if (!os_strncasecmp("GetAPSettings", action, action_len))
+ ret = web_process_get_ap_settings(sm, data, &reply,
+ &replyname);
+ else if (!os_strncasecmp("SetAPSettings", action, action_len))
+ ret = web_process_set_ap_settings(sm, data, &reply,
+ &replyname);
+ else if (!os_strncasecmp("DelAPSettings", action, action_len))
+ ret = web_process_del_ap_settings(sm, data, &reply,
+ &replyname);
+ else if (!os_strncasecmp("GetSTASettings", action, action_len))
+ ret = web_process_get_sta_settings(sm, data, &reply,
+ &replyname);
+ else if (!os_strncasecmp("SetSTASettings", action, action_len))
+ ret = web_process_set_sta_settings(sm, data, &reply,
+ &replyname);
+ else if (!os_strncasecmp("DelSTASettings", action, action_len))
+ ret = web_process_del_sta_settings(sm, data, &reply,
+ &replyname);
+ else if (!os_strncasecmp("PutWLANResponse", action, action_len))
+ ret = web_process_put_wlan_response(sm, data, &reply,
+ &replyname);
+ else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
+ ret = web_process_set_selected_registrar(sm, data, &reply,
+ &replyname);
+ else if (!os_strncasecmp("RebootAP", action, action_len))
+ ret = web_process_reboot_ap(sm, data, &reply, &replyname);
+ else if (!os_strncasecmp("ResetAP", action, action_len))
+ ret = web_process_reset_ap(sm, data, &reply, &replyname);
+ else if (!os_strncasecmp("RebootSTA", action, action_len))
+ ret = web_process_reboot_sta(sm, data, &reply, &replyname);
+ else if (!os_strncasecmp("ResetSTA", action, action_len))
+ ret = web_process_reset_sta(sm, data, &reply, &replyname);
+ else
+ wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
+
+bad:
+ if (ret != HTTP_OK)
+ wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
+ web_connection_send_reply(c, ret, action, action_len, reply,
+ replyname);
+ wpabuf_free(reply);
+}
+
+
+/* Given that we have received a header w/ SUBSCRIBE, act upon it
+ *
+ * Format of SUBSCRIBE (case-insensitive):
+ *
+ * First line must be:
+ * SUBSCRIBE /wps_event HTTP/1.1
+ *
+ * Our response (if no error) which includes only required lines is:
+ * HTTP/1.1 200 OK
+ * Server: xx, UPnP/1.0, xx
+ * SID: uuid:xxxxxxxxx
+ * Timeout: Second-<n>
+ * Content-Length: 0
+ * Date: xxxx
+ *
+ * Header lines must end with \r\n
+ * Per RFC 2616, content-length: is not required but connection:close
+ * would appear to be required (given that we will be closing it!).
+ */
+static void web_connection_parse_subscribe(struct web_connection *c,
+ const char *filename)
+{
+ struct upnp_wps_device_sm *sm = c->sm;
+ struct wpabuf *buf;
+ char *b;
+ char *hdr = httpread_hdr_get(c->hread);
+ char *h;
+ char *match;
+ int match_len;
+ char *end;
+ int len;
+ int got_nt = 0;
+ u8 uuid[UUID_LEN];
+ int got_uuid = 0;
+ char *callback_urls = NULL;
+ struct subscription *s = NULL;
+ enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
+
+ buf = wpabuf_alloc(1000);
+ if (buf == NULL)
+ return;
+
+ /* Parse/validate headers */
+ h = hdr;
+ /* First line: SUBSCRIBE /wps_event HTTP/1.1
+ * has already been parsed.
+ */
+ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
+ ret = HTTP_PRECONDITION_FAILED;
+ goto error;
+ }
+ wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
+ end = os_strchr(h, '\n');
+
+ for (; end != NULL; h = end + 1) {
+ /* Option line by option line */
+ h = end + 1;
+ end = os_strchr(h, '\n');
+ if (end == NULL)
+ break; /* no unterminated lines allowed */
+
+ /* NT assures that it is our type of subscription;
+ * not used for a renewl.
+ **/
+ match = "NT:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) == 0) {
+ h += match_len;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ match = "upnp:event";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) != 0) {
+ ret = HTTP_BAD_REQUEST;
+ goto error;
+ }
+ got_nt = 1;
+ continue;
+ }
+ /* HOST should refer to us */
+#if 0
+ match = "HOST:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) == 0) {
+ h += match_len;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ .....
+ }
+#endif
+ /* CALLBACK gives one or more URLs for NOTIFYs
+ * to be sent as a result of the subscription.
+ * Each URL is enclosed in angle brackets.
+ */
+ match = "CALLBACK:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) == 0) {
+ h += match_len;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ len = end - h;
+ os_free(callback_urls);
+ callback_urls = os_malloc(len + 1);
+ if (callback_urls == NULL) {
+ ret = HTTP_INTERNAL_SERVER_ERROR;
+ goto error;
+ }
+ os_memcpy(callback_urls, h, len);
+ callback_urls[len] = 0;
+ continue;
+ }
+ /* SID is only for renewal */
+ match = "SID:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) == 0) {
+ h += match_len;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ match = "uuid:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) != 0) {
+ ret = HTTP_BAD_REQUEST;
+ goto error;
+ }
+ h += match_len;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ if (uuid_str2bin(h, uuid)) {
+ ret = HTTP_BAD_REQUEST;
+ goto error;
+ }
+ got_uuid = 1;
+ continue;
+ }
+ /* TIMEOUT is requested timeout, but apparently we can
+ * just ignore this.
+ */
+ }
+
+ if (got_uuid) {
+ /* renewal */
+ if (callback_urls) {
+ ret = HTTP_BAD_REQUEST;
+ goto error;
+ }
+ s = subscription_renew(sm, uuid);
+ if (s == NULL) {
+ ret = HTTP_PRECONDITION_FAILED;
+ goto error;
+ }
+ } else if (callback_urls) {
+ if (!got_nt) {
+ ret = HTTP_PRECONDITION_FAILED;
+ goto error;
+ }
+ s = subscription_start(sm, callback_urls);
+ if (s == NULL) {
+ ret = HTTP_INTERNAL_SERVER_ERROR;
+ goto error;
+ }
+ callback_urls = NULL; /* is now owned by subscription */
+ } else {
+ ret = HTTP_PRECONDITION_FAILED;
+ goto error;
+ }
+
+ /* success */
+ http_put_reply_code(buf, HTTP_OK);
+ wpabuf_put_str(buf, http_server_hdr);
+ wpabuf_put_str(buf, http_connection_close);
+ wpabuf_put_str(buf, "Content-Length: 0\r\n");
+ wpabuf_put_str(buf, "SID: uuid:");
+ /* subscription id */
+ b = wpabuf_put(buf, 0);
+ uuid_bin2str(s->uuid, b, 80);
+ wpabuf_put(buf, os_strlen(b));
+ wpabuf_put_str(buf, "\r\n");
+ wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
+ http_put_date(buf);
+ /* And empty line to terminate header: */
+ wpabuf_put_str(buf, "\r\n");
+
+ send_wpabuf(c->sd, buf);
+ wpabuf_free(buf);
+ os_free(callback_urls);
+ return;
+
+error:
+ /* Per UPnP spec:
+ * Errors
+ * Incompatible headers
+ * 400 Bad Request. If SID header and one of NT or CALLBACK headers
+ * are present, the publisher must respond with HTTP error
+ * 400 Bad Request.
+ * Missing or invalid CALLBACK
+ * 412 Precondition Failed. If CALLBACK header is missing or does not
+ * contain a valid HTTP URL, the publisher must respond with HTTP
+ * error 412 Precondition Failed.
+ * Invalid NT
+ * 412 Precondition Failed. If NT header does not equal upnp:event,
+ * the publisher must respond with HTTP error 412 Precondition
+ * Failed.
+ * [For resubscription, use 412 if unknown uuid].
+ * Unable to accept subscription
+ * 5xx. If a publisher is not able to accept a subscription (such as
+ * due to insufficient resources), it must respond with a
+ * HTTP 500-series error code.
+ * 599 Too many subscriptions (not a standard HTTP error)
+ */
+ http_put_empty(buf, ret);
+ send_wpabuf(c->sd, buf);
+ wpabuf_free(buf);
+}
+
+
+/* Given that we have received a header w/ UNSUBSCRIBE, act upon it
+ *
+ * Format of UNSUBSCRIBE (case-insensitive):
+ *
+ * First line must be:
+ * UNSUBSCRIBE /wps_event HTTP/1.1
+ *
+ * Our response (if no error) which includes only required lines is:
+ * HTTP/1.1 200 OK
+ * Content-Length: 0
+ *
+ * Header lines must end with \r\n
+ * Per RFC 2616, content-length: is not required but connection:close
+ * would appear to be required (given that we will be closing it!).
+ */
+static void web_connection_parse_unsubscribe(struct web_connection *c,
+ const char *filename)
+{
+ struct upnp_wps_device_sm *sm = c->sm;
+ struct wpabuf *buf;
+ char *hdr = httpread_hdr_get(c->hread);
+ char *h;
+ char *match;
+ int match_len;
+ char *end;
+ u8 uuid[UUID_LEN];
+ int got_uuid = 0;
+ struct subscription *s = NULL;
+ enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
+
+ /* Parse/validate headers */
+ h = hdr;
+ /* First line: UNSUBSCRIBE /wps_event HTTP/1.1
+ * has already been parsed.
+ */
+ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
+ ret = HTTP_PRECONDITION_FAILED;
+ goto send_msg;
+ }
+ wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
+ end = os_strchr(h, '\n');
+
+ for (; end != NULL; h = end + 1) {
+ /* Option line by option line */
+ h = end + 1;
+ end = os_strchr(h, '\n');
+ if (end == NULL)
+ break; /* no unterminated lines allowed */
+
+ /* HOST should refer to us */
+#if 0
+ match = "HOST:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) == 0) {
+ h += match_len;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ .....
+ }
+#endif
+ /* SID is only for renewal */
+ match = "SID:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) == 0) {
+ h += match_len;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ match = "uuid:";
+ match_len = os_strlen(match);
+ if (os_strncasecmp(h, match, match_len) != 0) {
+ ret = HTTP_BAD_REQUEST;
+ goto send_msg;
+ }
+ h += match_len;
+ while (*h == ' ' || *h == '\t')
+ h++;
+ if (uuid_str2bin(h, uuid)) {
+ ret = HTTP_BAD_REQUEST;
+ goto send_msg;
+ }
+ got_uuid = 1;
+ continue;
+ }
+ }
+
+ if (got_uuid) {
+ s = subscription_find(sm, uuid);
+ if (s) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s",
+ s,
+ (s && s->addr_list &&
+ s->addr_list->domain_and_port) ?
+ s->addr_list->domain_and_port : "-null-");
+ subscription_unlink(s);
+ subscription_destroy(s);
+ }
+ } else {
+ wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
+ "found)");
+ ret = HTTP_PRECONDITION_FAILED;
+ goto send_msg;
+ }
+
+ ret = HTTP_OK;
+
+send_msg:
+ buf = wpabuf_alloc(200);
+ if (buf == NULL)
+ return;
+ http_put_empty(buf, ret);
+ send_wpabuf(c->sd, buf);
+ wpabuf_free(buf);
+}
+
+
+/* Send error in response to unknown requests */
+static void web_connection_unimplemented(struct web_connection *c)
+{
+ struct wpabuf *buf;
+ buf = wpabuf_alloc(200);
+ if (buf == NULL)
+ return;
+ http_put_empty(buf, HTTP_UNIMPLEMENTED);
+ send_wpabuf(c->sd, buf);
+ wpabuf_free(buf);
+}
+
+
+
+/* Called when we have gotten an apparently valid http request.
+ */
+static void web_connection_check_data(struct web_connection *c)
+{
+ struct httpread *hread = c->hread;
+ enum httpread_hdr_type htype = httpread_hdr_type_get(hread);
+ /* char *data = httpread_data_get(hread); */
+ char *filename = httpread_uri_get(hread);
+
+ c->done = 1;
+ if (!filename) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
+ return;
+ }
+ /* Trim leading slashes from filename */
+ while (*filename == '/')
+ filename++;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
+ htype, inet_ntoa(c->cli_addr.sin_addr),
+ htons(c->cli_addr.sin_port));
+
+ switch (htype) {
+ case HTTPREAD_HDR_TYPE_GET:
+ web_connection_parse_get(c, filename);
+ break;
+ case HTTPREAD_HDR_TYPE_POST:
+ web_connection_parse_post(c, filename);
+ break;
+ case HTTPREAD_HDR_TYPE_SUBSCRIBE:
+ web_connection_parse_subscribe(c, filename);
+ break;
+ case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
+ web_connection_parse_unsubscribe(c, filename);
+ break;
+ /* We are not required to support M-POST; just plain
+ * POST is supposed to work, so we only support that.
+ * If for some reason we need to support M-POST, it is
+ * mostly the same as POST, with small differences.
+ */
+ default:
+ /* Send 501 for anything else */
+ web_connection_unimplemented(c);
+ break;
+ }
+}
+
+
+
+/* called back when we have gotten request */
+static void web_connection_got_file_handler(struct httpread *handle,
+ void *cookie,
+ enum httpread_event en)
+{
+ struct web_connection *c = cookie;
+
+ if (en == HTTPREAD_EVENT_FILE_READY)
+ web_connection_check_data(c);
+ web_connection_stop(c);
+}
+
+
+/* web_connection_start - Start web connection
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @sd: Socket descriptor
+ * @addr: Client address
+ *
+ * The socket descriptor sd is handed over for ownership by the WPS UPnP
+ * state machine.
+ */
+static void web_connection_start(struct upnp_wps_device_sm *sm,
+ int sd, struct sockaddr_in *addr)
+{
+ struct web_connection *c = NULL;
+
+ /* if too many connections, bail */
+ if (sm->n_web_connections >= MAX_WEB_CONNECTIONS) {
+ close(sd);
+ return;
+ }
+
+ c = os_zalloc(sizeof(*c));
+ if (c == NULL)
+ return;
+ os_memcpy(&c->cli_addr, addr, sizeof(c->cli_addr));
+ c->sm = sm;
+ c->sd = sd;
+#if 0
+ /*
+ * Setting non-blocking should not be necessary for read, and can mess
+ * up sending where blocking might be better.
+ */
+ if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
+ break;
+#endif
+ c->hread = httpread_create(c->sd, web_connection_got_file_handler,
+ c /* cookie */,
+ WEB_CONNECTION_MAX_READ,
+ WEB_CONNECTION_TIMEOUT_SEC);
+ if (c->hread == NULL)
+ goto fail;
+ if (sm->web_connections) {
+ c->next = sm->web_connections;
+ c->prev = c->next->prev;
+ c->prev->next = c;
+ c->next->prev = c;
+ } else {
+ sm->web_connections = c->next = c->prev = c;
+ }
+ sm->n_web_connections++;
+ return;
+
+fail:
+ if (c)
+ web_connection_stop(c);
+}
+
+
+/*
+ * Listening for web connections
+ * We have a single TCP listening port, and hand off connections as we get
+ * them.
+ */
+
+void web_listener_stop(struct upnp_wps_device_sm *sm)
+{
+ if (sm->web_sd_registered) {
+ sm->web_sd_registered = 0;
+ eloop_unregister_sock(sm->web_sd, EVENT_TYPE_READ);
+ }
+ if (sm->web_sd >= 0)
+ close(sm->web_sd);
+ sm->web_sd = -1;
+}
+
+
+static void web_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+ struct upnp_wps_device_sm *sm = sock_ctx;
+ int new_sd;
+
+ /* Create state for new connection */
+ /* Remember so we can cancel if need be */
+ new_sd = accept(sm->web_sd, (struct sockaddr *) &addr, &addr_len);
+ if (new_sd < 0) {
+ wpa_printf(MSG_ERROR, "WPS UPnP: web listener accept "
+ "errno=%d (%s) web_sd=%d",
+ errno, strerror(errno), sm->web_sd);
+ return;
+ }
+ web_connection_start(sm, new_sd, &addr);
+}
+
+
+int web_listener_start(struct upnp_wps_device_sm *sm)
+{
+ struct sockaddr_in addr;
+ int port;
+
+ sm->web_sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sm->web_sd < 0)
+ goto fail;
+ if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0)
+ goto fail;
+ port = 49152; /* first non-reserved port */
+ for (;;) {
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = sm->ip_addr;
+ addr.sin_port = htons(port);
+ if (bind(sm->web_sd, (struct sockaddr *) &addr,
+ sizeof(addr)) == 0)
+ break;
+ if (errno == EADDRINUSE) {
+ /* search for unused port */
+ if (++port == 65535)
+ goto fail;
+ continue;
+ }
+ goto fail;
+ }
+ if (listen(sm->web_sd, 10 /* max backlog */) != 0)
+ goto fail;
+ if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0)
+ goto fail;
+ if (eloop_register_sock(sm->web_sd, EVENT_TYPE_READ,
+ web_listener_handler, NULL, sm))
+ goto fail;
+ sm->web_sd_registered = 1;
+ sm->web_port = port;
+
+ return 0;
+
+fail:
+ /* Error */
+ web_listener_stop(sm);
+ return -1;
+}
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog Sun Feb 15 19:38:55 2009
@@ -1,4 +1,10 @@
ChangeLog for wpa_supplicant
+
+2009-02-15 - v0.6.8
+ * increased wpa_cli ping interval to 5 seconds and made this
+ configurable with a new command line options (-G<seconds>)
+ * fixed scan buffer processing with WEXT to handle up to 65535
+ byte result buffer (previously, limited to 32768 bytes)
2009-01-06 - v0.6.7
* added support for Wi-Fi Protected Setup (WPS)
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile Sun Feb 15 19:38:55 2009
@@ -5,6 +5,9 @@
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
+
+export LIBDIR ?= /usr/local/lib/
+export BINDIR ?= /usr/local/sbin/
CFLAGS += -I../src
CFLAGS += -I../src/crypto
@@ -35,8 +38,9 @@
echo CONFIG_WIRELESS_EXTENSION=y >> .config
install: all
- mkdir -p $(DESTDIR)/usr/local/sbin/
- for i in $(ALL); do cp $$i $(DESTDIR)/usr/local/sbin/$$i; done
+ mkdir -p $(DESTDIR)$(BINDIR)
+ for i in $(ALL); do cp $$i $(DESTDIR)$(BINDIR)/$$i; done
+ $(MAKE) -C ../src install
OBJS = config.o
OBJS += ../src/utils/common.o
@@ -505,10 +509,6 @@
ifdef CONFIG_WPS
# EAP-WSC
-ifeq ($(CONFIG_EAP_WSC), dyn)
-CFLAGS += -DCONFIG_WPS -DEAP_WSC_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_wsc.so
-else
CFLAGS += -DCONFIG_WPS -DEAP_WSC
OBJS += wps_supplicant.o
OBJS += ../src/utils/uuid.o
@@ -522,11 +522,20 @@
OBJS += ../src/wps/wps_enrollee.o
OBJS += ../src/wps/wps_registrar.o
OBJS_h += ../src/eap_server/eap_wsc.o
-endif
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_SHA256=y
NEED_BASE64=y
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/httpread.o
+endif
+
endif
ifdef CONFIG_EAP_IKEV2
@@ -564,6 +573,9 @@
OBJS += ../src/eap_peer/eap_tnc.o
OBJS += ../src/eap_peer/tncc.o
NEED_BASE64=y
+ifndef CONFIG_NATIVE_WINDOWS
+LIBS += -ldl
+endif
endif
ifdef CONFIG_IEEE8021X_EAPOL
@@ -1017,6 +1029,7 @@
OBJS_priv += ../src/utils/$(CONFIG_ELOOP).o
OBJS_priv += ../src/utils/common.o
OBJS_priv += ../src/utils/wpa_debug.o
+OBJS_priv += ../src/utils/wpabuf.o
OBJS_priv += wpa_priv.o
ifdef CONFIG_DRIVER_TEST
OBJS_priv += ../src/crypto/sha1.o
@@ -1126,7 +1139,7 @@
%.so: %.c
$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
- -D$(*:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
+ -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
wpa_supplicant.exe: wpa_supplicant
@@ -1170,7 +1183,7 @@
./test-sha1
rm test-sha1
-TEST_SHA256_OBJS = ../src/crypto/sha256.o ../src/crypto/md5.o tests/test_sha256.o ../src/crypto/crypto_openssl.o
+TEST_SHA256_OBJS = ../src/crypto/sha256.o ../src/crypto/md5.o tests/test_sha256.o ../src/utils/os_unix.o ../src/crypto/crypto_openssl.o
test-sha256: $(TEST_SHA256_OBJS)
$(LDO) $(LDFLAGS) -o $@ $(TEST_SHA256_OBJS) $(LIBS)
./test-sha256
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/README
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/README?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/README (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/README Sun Feb 15 19:38:55 2009
@@ -166,7 +166,7 @@
Linux ndiswrapper (http://ndiswrapper.sourceforge.net/) with
Windows NDIS driver.
- Broadcom wl.o driver
+ Broadcom wl.o driver (old version only)
This is a generic Linux driver for Broadcom IEEE 802.11a/g cards.
However, it is proprietary driver that is not publicly available
except for couple of exceptions, mainly Broadcom-based APs/wireless
@@ -176,7 +176,10 @@
the needed header file, wlioctl.h, for compiling wpa_supplicant.
This driver support in wpa_supplicant is expected to work also with
other devices based on Broadcom driver (assuming the driver includes
- client mode support).
+ client mode support). Please note that the newer Broadcom driver
+ ("hybrid Linux driver") supports Linux wireless extensions and does
+ not need (or even work) with the specific driver wrapper. Use -Dwext
+ with that driver.
Intel ipw2100 driver
(http://sourceforge.net/projects/ipw2100/)
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS Sun Feb 15 19:38:55 2009
@@ -163,3 +163,22 @@
WPS tab that guides user through WPS registration with automatic AP
selection. In addition, it shows how WPS can be started manually by
selecting an AP from scan results.
+
+
+Credential processing
+---------------------
+
+By default, wpa_supplicant processes received credentials and updates
+its configuration internally. However, it is possible to
+control these operations from external programs, if desired.
+
+This internal processing can be disabled with wps_cred_processing=1
+option. When this is used, an external program is responsible for
+processing the credential attributes and updating wpa_supplicant
+configuration based on them.
+
+Following control interface messages are sent out for external programs:
+
+WPS-CRED-RECEIVED <hexdump of Credential attribute(s)>
+For example:
+<2>WPS-CRED-RECEIVED 100e006f10260001011045000c6a6b6d2d7770732d74657374100300020020100f000200081027004030653462303435366332363666653064333961643135353461316634626637313234333761636664623766333939653534663166316230323061643434386235102000060266a0ee1727
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config.h Sun Feb 15 19:38:55 2009
@@ -312,6 +312,17 @@
* in
*/
char country[2];
+
+ /**
+ * wps_cred_processing - Credential processing
+ *
+ * 0 = process received credentials internally
+ * 1 = do not process received credentials; just pass them over
+ * ctrl_iface to external program(s)
+ * 2 = process received credentials internally and pass them over
+ * ctrl_iface to external program(s)
+ */
+ int wps_cred_processing;
};
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c Sun Feb 15 19:38:55 2009
@@ -456,6 +456,7 @@
{ STR_RANGE(serial_number, 0, 32) },
{ STR(device_type) },
{ FUNC(os_version) },
+ { INT_RANGE(wps_cred_processing, 0, 2) },
#endif /* CONFIG_WPS */
{ FUNC(country) }
};
@@ -881,6 +882,9 @@
if (WPA_GET_BE32(config->os_version))
fprintf(f, "os_version=%08x\n",
WPA_GET_BE32(config->os_version));
+ if (config->wps_cred_processing)
+ fprintf(f, "wps_cred_processing=%d\n",
+ config->wps_cred_processing);
#endif /* CONFIG_WPS */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c Sun Feb 15 19:38:55 2009
@@ -251,6 +251,8 @@
hk, TEXT("device_type"));
if (wpa_config_read_global_os_version(config, hk))
errors++;
+ wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
+ &config->wps_cred_processing);
#endif /* CONFIG_WPS */
return errors ? -1 : 0;
@@ -573,6 +575,8 @@
WPA_GET_BE32(config->os_version));
wpa_config_write_reg_string(hk, "os_version", vbuf);
}
+ wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
+ config->wps_cred_processing, 0);
#endif /* CONFIG_WPS */
return 0;
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c Sun Feb 15 19:38:55 2009
@@ -18,6 +18,7 @@
#include "eloop.h"
#include "config.h"
#include "wpa_supplicant_i.h"
+#include "wps/wps.h"
#include "ctrl_iface_dbus.h"
#include "ctrl_iface_dbus_handlers.h"
@@ -547,7 +548,8 @@
/* If the message was handled, send back the reply */
if (reply) {
- dbus_connection_send(connection, reply, NULL);
+ if (!dbus_message_get_no_reply(message))
+ dbus_connection_send(connection, reply, NULL);
dbus_message_unref(reply);
}
@@ -606,7 +608,8 @@
/* If the message was handled, send back the reply */
if (reply) {
- dbus_connection_send(connection, reply, NULL);
+ if (!dbus_message_get_no_reply(message))
+ dbus_connection_send(connection, reply, NULL);
dbus_message_unref(reply);
}
@@ -736,6 +739,63 @@
out:
dbus_message_unref(_signal);
}
+
+
+#ifdef CONFIG_WPS
+void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+ const struct wps_credential *cred)
+{
+ struct ctrl_iface_dbus_priv *iface;
+ DBusMessage *_signal = NULL;
+ const char *path;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s->global == NULL)
+ return;
+ iface = wpa_s->global->dbus_ctrl_iface;
+ if (iface == NULL)
+ return;
+
+ path = wpa_supplicant_get_dbus_path(wpa_s);
+ if (path == NULL) {
+ perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: "
+ "interface didn't have a dbus path");
+ wpa_printf(MSG_ERROR,
+ "wpa_supplicant_dbus_notify_wps_cred[dbus]: "
+ "interface didn't have a dbus path; can't send "
+ "signal.");
+ return;
+ }
+ _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
+ "WpsCred");
+ if (_signal == NULL) {
+ perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: "
+ "couldn't create dbus signal; likely out of memory");
+ wpa_printf(MSG_ERROR,
+ "wpa_supplicant_dbus_notify_wps_cred[dbus]: "
+ "couldn't create dbus signal; likely out of "
+ "memory.");
+ return;
+ }
+
+ if (!dbus_message_append_args(_signal,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &cred->cred_attr, cred->cred_attr_len,
+ DBUS_TYPE_INVALID)) {
+ perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: "
+ "not enough memory to construct signal.");
+ wpa_printf(MSG_ERROR,
+ "wpa_supplicant_dbus_notify_wps_cred[dbus]: "
+ "not enough memory to construct signal.");
+ goto out;
+ }
+
+ dbus_connection_send(iface->con, _signal, NULL);
+
+out:
+ dbus_message_unref(_signal);
+}
+#endif /* CONFIG_WPS */
/**
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.h Sun Feb 15 19:38:55 2009
@@ -14,6 +14,8 @@
#ifndef CTRL_IFACE_DBUS_H
#define CTRL_IFACE_DBUS_H
+
+struct wps_credential;
#ifdef CONFIG_CTRL_IFACE_DBUS
@@ -84,6 +86,8 @@
void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
wpa_states new_state,
wpa_states old_state);
+void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+ const struct wps_credential *cred);
char * wpas_dbus_decompose_object_path(const char *path, char **network,
char **bssid);
@@ -129,6 +133,12 @@
{
}
+static inline void
+wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+ const struct wps_credential *cred)
+{
+}
+
static inline int
wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
{
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig Sun Feb 15 19:38:55 2009
@@ -51,8 +51,8 @@
# Driver interface for madwifi driver
#CONFIG_DRIVER_MADWIFI=y
-# Change include directories to match with the local setup
-#CFLAGS += -I../madwifi/wpa
+# Set include directory to the madwifi source tree
+#CFLAGS += -I../../madwifi
# Driver interface for Prism54 driver
# (Note: Prism54 is not yet supported, i.e., this will not work as-is and is
@@ -65,7 +65,10 @@
# Driver interface for Atmel driver
CONFIG_DRIVER_ATMEL=y
-# Driver interface for Broadcom driver
+# Driver interface for old Broadcom driver
+# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+# Linux wireless extensions and does not need (or even work) with the old
+# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
#CONFIG_DRIVER_BROADCOM=y
# Example path for wlioctl.h; change to match your configuration
#CFLAGS += -I/opt/WRT54GS/release/src/include
@@ -78,6 +81,9 @@
# Driver interface for generic Linux wireless extensions
CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+#CONFIG_DRIVER_NL80211=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
@@ -357,15 +363,10 @@
# Include client MLME (management frame processing).
# This can be used to move MLME processing of Linux mac80211 stack into user
-# space.
+# space. Please note that this is currently only available with
+# driver_nl80211.c and only with a modified version of Linux kernel and
+# wpa_supplicant.
#CONFIG_CLIENT_MLME=y
-# Currently, driver_nl80211.c build requires some additional parameters to be
-# able to include some of the kernel header files. Following lines can be used
-# to set these (WIRELESS_DEV must point to the root directory of the
-# wireless-testing.git tree). In addition, mac80211 may need external patches
-# to enable userspace MLME support.
-#WIRELESS_DEV=/usr/src/wireless-testing
-#CFLAGS += -I$(WIRELESS_DEV)/net/mac80211
# IEEE Std 802.11r-2008 (Fast BSS Transition)
#CONFIG_IEEE80211R=y
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8 Sun Feb 15 19:38:55 2009
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_BACKGROUND" "8" "06 January 2009" "" ""
+.TH "WPA_BACKGROUND" "8" "15 February 2009" "" ""
.SH NAME
wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8 Sun Feb 15 19:38:55 2009
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_CLI" "8" "06 January 2009" "" ""
+.TH "WPA_CLI" "8" "15 February 2009" "" ""
.SH NAME
wpa_cli \- WPA command line client
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8 Sun Feb 15 19:38:55 2009
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_GUI" "8" "06 January 2009" "" ""
+.TH "WPA_GUI" "8" "15 February 2009" "" ""
.SH NAME
wpa_gui \- WPA Graphical User Interface
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8 Sun Feb 15 19:38:55 2009
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_PASSPHRASE" "8" "06 January 2009" "" ""
+.TH "WPA_PASSPHRASE" "8" "15 February 2009" "" ""
.SH NAME
wpa_passphrase \- Generate a WPA PSK from an ASCII passphrase for a SSID
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8 Sun Feb 15 19:38:55 2009
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_PRIV" "8" "06 January 2009" "" ""
+.TH "WPA_PRIV" "8" "15 February 2009" "" ""
.SH NAME
wpa_priv \- wpa_supplicant privilege separation helper
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8 Sun Feb 15 19:38:55 2009
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_SUPPLICANT" "8" "06 January 2009" "" ""
+.TH "WPA_SUPPLICANT" "8" "15 February 2009" "" ""
.SH NAME
wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 Sun Feb 15 19:38:55 2009
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_SUPPLICANT.CONF" "5" "06 January 2009" "" ""
+.TH "WPA_SUPPLICANT.CONF" "5" "15 February 2009" "" ""
.SH NAME
wpa_supplicant.conf \- configuration file for wpa_supplicant
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c Sun Feb 15 19:38:55 2009
@@ -156,6 +156,18 @@
}
+static struct extra_radius_attr *
+find_extra_attr(struct extra_radius_attr *attrs, u8 type)
+{
+ struct extra_radius_attr *p;
+ for (p = attrs; p; p = p->next) {
+ if (p->type == type)
+ return p;
+ }
+ return NULL;
+}
+
+
static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
const u8 *eap, size_t len)
{
@@ -200,7 +212,8 @@
goto fail;
}
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &e->own_ip_addr, 4)) {
printf("Could not add NAS-IP-Address\n");
goto fail;
@@ -208,7 +221,9 @@
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(e->wpa_s->own_addr));
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID)
+ &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Calling-Station-Id\n");
goto fail;
@@ -217,19 +232,22 @@
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
printf("Could not add Framed-MTU\n");
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
printf("Could not add NAS-Port-Type\n");
goto fail;
}
os_snprintf(buf, sizeof(buf), "%s", e->connect_info);
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/events.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/events.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/events.c Sun Feb 15 19:38:55 2009
@@ -270,7 +270,8 @@
}
-static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
+static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
struct wpa_scan_res *bss)
{
struct wpa_ie_data ie;
@@ -278,7 +279,7 @@
const u8 *rsn_ie, *wpa_ie;
int ret;
- ret = wpas_wps_ssid_bss_match(ssid, bss);
+ ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
if (ret >= 0)
return ret;
@@ -424,7 +425,7 @@
#ifdef CONFIG_WPS
if (ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(ssid, bss))
+ wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
check_ssid = 0;
#endif /* CONFIG_WPS */
@@ -444,7 +445,7 @@
continue;
}
- if (!wpa_supplicant_ssid_bss_match(ssid, bss))
+ if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
continue;
wpa_printf(MSG_DEBUG, " selected WPA AP "
@@ -514,7 +515,8 @@
* with our mode. */
check_ssid = 1;
if (ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(ssid, bss))
+ wpas_wps_ssid_wildcard_ok(wpa_s, ssid,
+ bss))
check_ssid = 0;
}
#endif /* CONFIG_WPS */
@@ -645,6 +647,7 @@
wpa_printf(MSG_DEBUG, "No APs found - clear blacklist "
"and try again");
wpa_blacklist_clear(wpa_s);
+ wpa_s->blacklist_cleared++;
} else if (selected == NULL) {
break;
}
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c Sun Feb 15 19:38:55 2009
@@ -1087,9 +1087,10 @@
status_code);
#ifdef CONFIG_IEEE80211W
if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
- elems.assoc_comeback && elems.assoc_comeback_len == 4) {
+ elems.timeout_int && elems.timeout_int_len == 5 &&
+ elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
u32 tu, ms;
- tu = WPA_GET_LE32(elems.assoc_comeback);
+ tu = WPA_GET_LE32(elems.timeout_int + 1);
ms = tu * 1024 / 1000;
wpa_printf(MSG_DEBUG, "MLME: AP rejected association "
"temporarily; comeback duration %u TU "
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/nmake.mak
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/nmake.mak?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/nmake.mak (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/nmake.mak Sun Feb 15 19:38:55 2009
@@ -81,12 +81,13 @@
$(OBJDIR)\eap_common.obj \
$(OBJDIR)\chap.obj \
$(OBJDIR)\eap_methods.obj \
- $(OBJDIR)\eap_tlv.obj \
$(OBJDIR)\eap_md5.obj \
$(OBJDIR)\eap_tls.obj \
$(OBJDIR)\eap_tls_common.obj \
$(OBJDIR)\eap_mschapv2.obj \
+ $(OBJDIR)\mschapv2.obj \
$(OBJDIR)\eap_peap.obj \
+ $(OBJDIR)\eap_peap_common.obj \
$(OBJDIR)\eap_ttls.obj \
$(OBJDIR)\eap_gtc.obj \
$(OBJDIR)\eap_otp.obj \
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c Sun Feb 15 19:38:55 2009
@@ -204,7 +204,8 @@
if (ret) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
wpa_supplicant_req_scan(wpa_s, 10, 0);
- }
+ } else
+ wpa_s->scan_runs++;
}
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_sha256.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_sha256.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_sha256.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_sha256.c Sun Feb 15 19:38:55 2009
@@ -323,7 +323,8 @@
}
printf("Test IEEE 802.11r KDF\n");
- sha256_prf("abc", 3, "KDF test", "data", 4, hash, sizeof(hash));
+ sha256_prf((u8 *) "abc", 3, "KDF test", (u8 *) "data", 4,
+ hash, sizeof(hash));
/* TODO: add proper test case for this */
return errors;
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c Sun Feb 15 19:38:55 2009
@@ -95,6 +95,7 @@
static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
+static int ping_interval = 5;
static void print_help();
@@ -104,7 +105,8 @@
{
printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
"[-a<action file>] \\\n"
- " [-P<pid file>] [-g<global ctrl>] [command..]\n"
+ " [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] "
+ "[command..]\n"
" -h = help (show this usage text)\n"
" -v = shown version information\n"
" -a = run in daemon mode executing the action file based on "
@@ -1563,7 +1565,7 @@
do {
wpa_cli_recv_pending(ctrl_conn, 0, 0);
#ifndef CONFIG_NATIVE_WINDOWS
- alarm(1);
+ alarm(ping_interval);
#endif /* CONFIG_NATIVE_WINDOWS */
#ifdef CONFIG_READLINE
cmd = readline("> ");
@@ -1667,7 +1669,7 @@
while (!wpa_cli_quit) {
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
- tv.tv_sec = 2;
+ tv.tv_sec = ping_interval;
tv.tv_usec = 0;
res = select(fd + 1, &rfds, NULL, NULL, &tv);
if (res < 0 && errno != EINTR) {
@@ -1721,7 +1723,7 @@
wpa_cli_reconnect();
if (ctrl_conn)
wpa_cli_recv_pending(ctrl_conn, 1, 0);
- alarm(1);
+ alarm(ping_interval);
}
#endif /* CONFIG_NATIVE_WINDOWS */
@@ -1794,7 +1796,7 @@
return -1;
for (;;) {
- c = getopt(argc, argv, "a:Bg:hi:p:P:v");
+ c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
if (c < 0)
break;
switch (c) {
@@ -1806,6 +1808,9 @@
break;
case 'g':
global = optarg;
+ break;
+ case 'G':
+ ping_interval = atoi(optarg);
break;
case 'h':
usage();
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/main.cpp
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/main.cpp?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/main.cpp (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/main.cpp Sun Feb 15 19:38:55 2009
@@ -18,10 +18,32 @@
#include <QApplication>
#include "wpagui.h"
+
+class WpaGuiApp : public QApplication
+{
+public:
+ WpaGuiApp(int &argc, char **argv);
+
+ virtual void saveState(QSessionManager &manager);
+
+ WpaGui *w;
+};
+
+WpaGuiApp::WpaGuiApp(int &argc, char **argv) : QApplication(argc, argv)
+{
+}
+
+void WpaGuiApp::saveState(QSessionManager &manager)
+{
+ QApplication::saveState(manager);
+ w->saveState();
+}
+
+
int main(int argc, char *argv[])
{
- QApplication app(argc, argv);
- WpaGui w;
+ WpaGuiApp app(argc, argv);
+ WpaGui w(&app);
int ret;
#ifdef CONFIG_NATIVE_WINDOWS
@@ -32,6 +54,8 @@
}
#endif /* CONFIG_NATIVE_WINDOWS */
+ app.w = &w;
+
ret = app.exec();
#ifdef CONFIG_NATIVE_WINDOWS
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp Sun Feb 15 19:38:55 2009
@@ -25,6 +25,7 @@
#include <QMessageBox>
#include <QCloseEvent>
#include <QImageReader>
+#include <QSettings>
#include "wpagui.h"
#include "dirent.h"
@@ -41,8 +42,8 @@
}
#endif
-WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
- : QMainWindow(parent)
+WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags)
+ : QMainWindow(parent), app(_app)
{
setupUi(this);
@@ -71,6 +72,13 @@
#endif /* CONFIG_NATIVE_WINDOWS */
(void) statusBar();
+
+ /*
+ * Disable WPS tab by default; it will be enabled if wpa_supplicant is
+ * built with WPS support.
+ */
+ wpsTab->setEnabled(false);
+ wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false);
connect(fileEventHistoryAction, SIGNAL(triggered()), this,
SLOT(eventHistory()));
@@ -137,6 +145,15 @@
parse_argv();
+ if (app->isSessionRestored()) {
+ QSettings settings("wpa_supplicant", "wpa_gui");
+ settings.beginGroup("state");
+ if (app->sessionId().compare(settings.value("session_id").
+ toString()) == 0)
+ startInTray = settings.value("in_tray").toBool();
+ settings.endGroup();
+ }
+
if (QSystemTrayIcon::isSystemTrayAvailable())
createTrayIcon(startInTray);
else
@@ -406,7 +423,10 @@
QString res(buf);
QStringList types = res.split(QChar(' '));
- actionWPS->setEnabled(types.contains("WSC"));
+ bool wps = types.contains("WSC");
+ actionWPS->setEnabled(wps);
+ wpsTab->setEnabled(wps);
+ wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps);
}
return 0;
@@ -1293,6 +1313,7 @@
if (!trayOnly)
show();
+ inTray = trayOnly;
}
@@ -1316,10 +1337,13 @@
* custom closeEvent handler take care of children */
case QSystemTrayIcon::Trigger:
ackTrayIcon = true;
- if (isVisible())
+ if (isVisible()) {
close();
- else
+ inTray = true;
+ } else {
show();
+ inTray = false;
+ }
break;
case QSystemTrayIcon::MiddleClick:
showTrayStatus();
@@ -1663,3 +1687,13 @@
add_iface->show();
add_iface->exec();
}
+
+
+void WpaGui::saveState()
+{
+ QSettings settings("wpa_supplicant", "wpa_gui");
+ settings.beginGroup("state");
+ settings.setValue("session_id", app->sessionId());
+ settings.setValue("in_tray", inTray);
+ settings.endGroup();
+}
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h Sun Feb 15 19:38:55 2009
@@ -28,7 +28,7 @@
Q_OBJECT
public:
- WpaGui(QWidget *parent = 0, const char *name = 0,
+ WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0,
Qt::WFlags fl = 0);
~WpaGui();
@@ -40,6 +40,7 @@
virtual void disableNetwork(const QString &sel);
virtual int getNetworkDisabled(const QString &sel);
void setBssFromScan(const QString &bssid);
+ void saveState();
public slots:
virtual void parse_argv();
@@ -136,6 +137,9 @@
AddInterface *add_iface;
bool connectedToService;
+
+ QApplication *app;
+ bool inTray;
};
#endif /* WPAGUI_H */
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui Sun Feb 15 19:38:55 2009
@@ -293,7 +293,7 @@
<attribute name="title" >
<string>WPS</string>
</attribute>
- <layout class="QGridLayout" name="gridLayout" >
+ <layout class="QGridLayout" name="wpsGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_priv.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_priv.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_priv.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_priv.c Sun Feb 15 19:38:55 2009
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / privileged helper program
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -575,10 +575,21 @@
}
+static void wpa_priv_cmd_set_country(struct wpa_priv_interface *iface,
+ char *buf)
+{
+ if (iface->drv_priv == NULL || iface->driver->set_country == NULL ||
+ *buf == '\0')
+ return;
+
+ iface->driver->set_country(iface->drv_priv, buf);
+}
+
+
static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
struct wpa_priv_interface *iface = eloop_ctx;
- char buf[2000];
+ char buf[2000], *pos;
void *cmd_buf;
size_t cmd_len;
int res, cmd;
@@ -648,6 +659,13 @@
break;
case PRIVSEP_CMD_SET_MODE:
wpa_priv_cmd_set_mode(iface, cmd_buf, cmd_len);
+ break;
+ case PRIVSEP_CMD_SET_COUNTRY:
+ pos = cmd_buf;
+ if (pos + cmd_len >= buf + sizeof(buf))
+ break;
+ pos[cmd_len] = '\0';
+ wpa_priv_cmd_set_country(iface, pos);
break;
}
}
@@ -1030,6 +1048,53 @@
perror("sendmsg(wpas_socket)");
}
+
+#ifdef CONFIG_CLIENT_MLME
+void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features,
+ size_t num_hw_features)
+{
+ size_t i;
+
+ if (hw_features == NULL)
+ return;
+
+ for (i = 0; i < num_hw_features; i++) {
+ os_free(hw_features[i].channels);
+ os_free(hw_features[i].rates);
+ }
+
+ os_free(hw_features);
+}
+
+
+void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct wpa_priv_interface *iface = ctx;
+ struct msghdr msg;
+ struct iovec io[3];
+ int event = PRIVSEP_EVENT_STA_RX;
+
+ wpa_printf(MSG_DEBUG, "STA RX from driver");
+ io[0].iov_base = &event;
+ io[0].iov_len = sizeof(event);
+ io[1].iov_base = (u8 *) rx_status;
+ io[1].iov_len = sizeof(*rx_status);
+ io[2].iov_base = (u8 *) buf;
+ io[2].iov_len = len;
+
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 3;
+ msg.msg_name = &iface->drv_addr;
+ msg.msg_namelen = sizeof(iface->drv_addr);
+
+ if (sendmsg(iface->fd, &msg, 0) < 0)
+ perror("sendmsg(wpas_socket)");
+}
+#endif /* CONFIG_CLIENT_MLME */
+
+
static void wpa_priv_terminate(int sig, void *eloop_ctx, void *signal_ctx)
{
wpa_printf(MSG_DEBUG, "wpa_priv termination requested");
@@ -1060,7 +1125,8 @@
static void usage(void)
{
printf("wpa_priv v" VERSION_STR "\n"
- "Copyright (c) 2007, Jouni Malinen <j at w1.fi> and contributors\n"
+ "Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi> and "
+ "contributors\n"
"\n"
"usage:\n"
" wpa_priv [-Bdd] [-P<pid file>] <driver:ifname> "
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c Sun Feb 15 19:38:55 2009
@@ -1219,7 +1219,7 @@
* @wpa_s: Pointer to wpa_supplicant data
* @reason_code: IEEE 802.11 reason code for the deauthenticate frame
*
- * This function is used to request %wpa_supplicant to disassociate with the
+ * This function is used to request %wpa_supplicant to deauthenticate from the
* current AP.
*/
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
@@ -2150,7 +2150,7 @@
eap_peer_unregister_methods();
- for (i = 0; wpa_supplicant_drivers[i]; i++) {
+ for (i = 0; wpa_supplicant_drivers[i] && global->drv_priv; i++) {
if (!global->drv_priv[i])
continue;
wpa_supplicant_drivers[i]->global_deinit(global->drv_priv[i]);
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf Sun Feb 15 19:38:55 2009
@@ -190,6 +190,13 @@
# 4-octet operating system version number (hex string)
#os_version=01020300
+# Credential processing
+# 0 = process received credentials internally (default)
+# 1 = do not process received credentials; just pass them over ctrl_iface to
+# external program(s)
+# 2 = process received credentials internally and pass them over ctrl_iface
+# to external program(s)
+#wps_cred_processing=0
# network block
#
@@ -255,8 +262,7 @@
#
# key_mgmt: list of accepted authenticated key management protocols
# WPA-PSK = WPA pre-shared key (this requires 'psk' field)
-# WPA-EAP = WPA using EAP authentication (this can use an external
-# program, e.g., Xsupplicant, for IEEE 802.1X EAP Authentication
+# WPA-EAP = WPA using EAP authentication
# IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
# generated WEP keys
# NONE = WPA is not used; plaintext or static WEP could be used
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h Sun Feb 15 19:38:55 2009
@@ -345,6 +345,7 @@
* results without a new scan request; this is used
* to speed up the first association if the driver
* has already available scan results. */
+ int scan_runs; /* number of scan runs since WPS was started */
struct wpa_client_mlme mlme;
int use_client_mlme;
@@ -355,6 +356,8 @@
int mic_errors_seen; /* Michael MIC errors with the current PTK */
struct wps_context *wps;
+ int wps_success; /* WPS success event received */
+ int blacklist_cleared;
};
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c Sun Feb 15 19:38:55 2009
@@ -23,9 +23,12 @@
#include "eloop.h"
#include "uuid.h"
#include "wpa_ctrl.h"
+#include "ctrl_iface_dbus.h"
#include "eap_common/eap_wsc_common.h"
+#include "blacklist.h"
#include "wps_supplicant.h"
+#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
@@ -33,6 +36,27 @@
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
{
+ if (!wpa_s->wps_success &&
+ wpa_s->current_ssid &&
+ eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
+ const u8 *bssid = wpa_s->bssid;
+ if (is_zero_ether_addr(bssid))
+ bssid = wpa_s->pending_bssid;
+
+ wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
+ " did not succeed - continue trying to find "
+ "suitable AP", MAC2STR(bssid));
+ wpa_blacklist_add(wpa_s, bssid);
+
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s,
+ wpa_s->blacklist_cleared ? 5 : 0, 0);
+ wpa_s->blacklist_cleared = 0;
+ return 1;
+ }
+
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
@@ -46,6 +70,15 @@
return 1;
}
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) {
+ wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
+ "for external credential processing");
+ wpas_clear_wps(wpa_s);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ return 1;
+ }
+
return 0;
}
@@ -56,7 +89,36 @@
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid = wpa_s->current_ssid;
- wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
+ if ((wpa_s->conf->wps_cred_processing == 1 ||
+ wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
+ size_t blen = cred->cred_attr_len * 2 + 1;
+ char *buf = os_malloc(blen);
+ if (buf) {
+ wpa_snprintf_hex(buf, blen,
+ cred->cred_attr, cred->cred_attr_len);
+ wpa_msg(wpa_s, MSG_INFO, "%s%s",
+ WPS_EVENT_CRED_RECEIVED, buf);
+ os_free(buf);
+ }
+ wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
+ } else
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
+
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
+ cred->cred_attr, cred->cred_attr_len);
+
+ if (wpa_s->conf->wps_cred_processing == 1)
+ return 0;
+
+ if (cred->auth_type != WPS_AUTH_OPEN &&
+ cred->auth_type != WPS_AUTH_SHARED &&
+ cred->auth_type != WPS_AUTH_WPAPSK &&
+ cred->auth_type != WPS_AUTH_WPA2PSK) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
+ "unsupported authentication type %d",
+ cred->auth_type);
+ return 0;
+ }
if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
@@ -87,11 +149,8 @@
switch (cred->encr_type) {
case WPS_ENCR_NONE:
- ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE;
break;
case WPS_ENCR_WEP:
- ssid->pairwise_cipher = ssid->group_cipher =
- WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104;
if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
cred->key_idx < NUM_WEP_KEYS) {
os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
@@ -102,11 +161,9 @@
break;
case WPS_ENCR_TKIP:
ssid->pairwise_cipher = WPA_CIPHER_TKIP;
- ssid->group_cipher = WPA_CIPHER_TKIP;
break;
case WPS_ENCR_AES:
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
- ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
break;
}
@@ -200,6 +257,7 @@
static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
{
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
+ wpa_s->wps_success = 1;
}
@@ -216,6 +274,8 @@
break;
case WPS_EV_SUCCESS:
wpa_supplicant_wps_event_success(wpa_s);
+ break;
+ case WPS_EV_PWD_AUTH_FAIL:
break;
}
}
@@ -257,7 +317,8 @@
static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- wpa_printf(MSG_DEBUG, "WPS: Requested operation timed out");
+ wpa_printf(MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
+ "out");
wpas_clear_wps(wpa_s);
}
@@ -329,6 +390,9 @@
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s->scan_runs = 0;
+ wpa_s->wps_success = 0;
+ wpa_s->blacklist_cleared = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -516,7 +580,8 @@
}
-int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss)
+int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpa_scan_res *bss)
{
struct wpabuf *wps_ie;
@@ -550,14 +615,24 @@
return 0;
}
+ /*
+ * Start with WPS APs that advertise active PIN Registrar and
+ * allow any WPS AP after third scan since some APs do not set
+ * Selected Registrar attribute properly when using external
+ * Registrar.
+ */
if (!wps_is_selected_pin_registrar(wps_ie)) {
- wpa_printf(MSG_DEBUG, " skip - WPS AP "
- "without active PIN Registrar");
- wpabuf_free(wps_ie);
- return 0;
- }
- wpa_printf(MSG_DEBUG, " selected based on WPS IE "
- "(Active PIN)");
+ if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
+ wpa_printf(MSG_DEBUG, " skip - WPS AP "
+ "without active PIN Registrar");
+ wpabuf_free(wps_ie);
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE");
+ } else {
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE "
+ "(Active PIN)");
+ }
wpabuf_free(wps_ie);
return 1;
}
@@ -572,7 +647,8 @@
}
-int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
+int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
struct wpa_scan_res *bss)
{
struct wpabuf *wps_ie = NULL;
@@ -586,7 +662,9 @@
}
} else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
- if (wps_ie && wps_is_selected_pin_registrar(wps_ie)) {
+ if (wps_ie &&
+ (wps_is_selected_pin_registrar(wps_ie) ||
+ wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
/* allow wildcard SSID for WPS PIN */
ret = 1;
}
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h?rev=1324&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h Sun Feb 15 19:38:55 2009
@@ -29,8 +29,10 @@
const char *pin);
int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin);
-int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss);
-int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid, struct wpa_scan_res *bss);
+int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpa_scan_res *bss);
+int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpa_scan_res *bss);
int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *selected,
struct wpa_ssid *ssid);
@@ -58,13 +60,15 @@
return 0;
}
-static inline int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid,
+static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
struct wpa_scan_res *bss)
{
return -1;
}
-static inline int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
+static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
struct wpa_scan_res *bss)
{
return 0;
More information about the Pkg-wpa-devel
mailing list