00001
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <stdint.h>
00026 #include <string.h>
00027 #include <sys/ioctl.h>
00028 #include <glib.h>
00029 #include <glib-object.h>
00030 #include <unistd.h>
00031 #include "common.h"
00032 #include "wpa.h"
00033 #include "wps.h"
00034 #include "log.h"
00035
00036 #define WPS_VERSION 0x10
00037 #define MAX_DEVICE_NAME 32
00038
00039 #define WPS_STATE_UNCONFIGURED 0x01
00040 #define WPS_STATE_CONFIGURED 0x02
00041
00042 #define WPS_PIN_CODE 0
00043 #define WPS_PUSH_BUTTON 4
00044
00045
00046 #define WPS_VERSION_TLV 0x104A
00047 #define WPS_STATE_TLV 0x1044
00048 #define WPS_APSETUPLOCKED_TLV 0x1057
00049 #define WPS_SELECTEDREGISTRAR_TLV 0x1041
00050 #define WPS_DEVICEPASSWORD_ID_TLV 0x1012
00051 #define WPS_SELECTEDREGISTRARCONFIGMETHODS_TLV 0x1053
00052 #define WPS_DEVICENAME_TLV 0x1011
00053 #define WPS_UUID_E_TLV 0x1047
00054
00064 static int get_tlv_value(guchar* msg, guint msg_size, guint type,
00065 guchar* value, guint value_len)
00066 {
00067 guint len = 0;
00068
00069 if (msg_size < 4) {
00070 DLOG_ERR("Message too short");
00071 return -1;
00072 }
00073
00074
00075 while (len + 4 < msg_size)
00076 {
00077 guint hi = msg[len];
00078 guint lo = msg[len+1];
00079 guint tmp_type = (hi << 8) + lo;
00080
00081
00082
00083 guint length = 0;
00084
00085 hi = msg[len+2];
00086 lo = msg[len+3];
00087
00088 length = (hi << 8) + lo;
00089
00090
00091 if (tmp_type == type)
00092 {
00093 if (length > value_len) {
00094 DLOG_ERR("Too much data for buffer (%d)",
00095 value_len);
00096 return -1;
00097 }
00098 if (len + 4 + length > msg_size) {
00099 DLOG_ERR("Message data too short?");
00100 return -1;
00101 }
00102
00103 memcpy(value, msg+len+4, length);
00104
00105
00106 return length;
00107 }
00108
00109 len = len + length + 4;
00110 }
00111
00112 return -1;
00113 }
00120 void handle_wps_ie(unsigned char* p,
00121 struct scan_results_t *scan_results,
00122 unsigned int length)
00123 {
00124 guint value = 0;
00125 char device_name[MAX_DEVICE_NAME+1];
00126 guchar *uuid_e;
00127 gint len;
00128
00129 if (length < 2) {
00130 DLOG_ERR("WPS IE too short");
00131 return;
00132 }
00133 #if 0
00134 unsigned int i;
00135 for (i=0;i<length;i++) {
00136 DLOG_DEBUG("%02x", p[i]);
00137 }
00138 #endif
00139
00140
00141 if (get_tlv_value(p, length, WPS_VERSION_TLV, (unsigned char*)&value,
00142 sizeof(value)) < 0 || value != WPS_VERSION) {
00143 DLOG_ERR("Unknown WPS version received (%02x)", value);
00144 return;
00145 }
00146
00147 if (get_tlv_value(p, length, WPS_STATE_TLV, (unsigned char*)&value,
00148 sizeof(value)) < 0) {
00149 DLOG_ERR("Could not get WPS state");
00150 return;
00151 }
00152
00153 DLOG_DEBUG("WPS state: %s", value == WPS_STATE_CONFIGURED?"configured":
00154 "unconfigured");
00155
00156 scan_results->cap_bits |= WLANCOND_WPS;
00157
00158
00159 if (get_tlv_value(p, length, WPS_APSETUPLOCKED_TLV,
00160 (unsigned char*)&value, sizeof(value)) < 0) {
00161
00162 } else {
00163 DLOG_DEBUG("ap_setup_locked: %d", value);
00164 }
00165
00166 if (get_tlv_value(p, length, WPS_SELECTEDREGISTRAR_TLV,
00167 (unsigned char*)&value, sizeof(value)) < 0) {
00168
00169 } else if (value) {
00170 DLOG_DEBUG("Device is selected registrar");
00171 scan_results->cap_bits |= WLANCOND_WPS_CONFIGURED;
00172 }
00173
00174 if (get_tlv_value(p, length, WPS_DEVICEPASSWORD_ID_TLV,
00175 (unsigned char*)&value, sizeof(value)) < 0) {
00176
00177
00178 scan_results->cap_bits |= WLANCOND_WPS_PIN;
00179 scan_results->cap_bits |= WLANCOND_WPS_PUSH_BUTTON;
00180 } else {
00181 if (GUINT16_FROM_BE(value) == WPS_PIN_CODE) {
00182 DLOG_DEBUG("PIN supported");
00183 scan_results->cap_bits |= WLANCOND_WPS_PIN;
00184 }
00185 if (GUINT16_FROM_BE(value) == WPS_PUSH_BUTTON) {
00186 DLOG_DEBUG("PBC supported");
00187 scan_results->cap_bits |= WLANCOND_WPS_PUSH_BUTTON;
00188 }
00189 }
00190
00191 if ((len = get_tlv_value(p, length, WPS_DEVICENAME_TLV,
00192 (unsigned char*)&device_name,
00193 sizeof(device_name)-1)) < 0) {
00194
00195 } else {
00196 device_name[len] = '\0';
00197 DLOG_DEBUG("Device name: %s", device_name);
00198 }
00199
00200 uuid_e = g_malloc(MAX_UUID_E_LEN);
00201
00202 if ((len = get_tlv_value(p, length, WPS_UUID_E_TLV,
00203 uuid_e, MAX_UUID_E_LEN)) < 0) {
00204 DLOG_DEBUG("Could not get UUID-E");
00205 g_free(uuid_e);
00206 } else {
00207 scan_results->uuid_e = uuid_e;
00208 }
00209
00210 #ifdef DEBUG_WPS
00211
00212 if (get_tlv_value(p, length, WPS_SELECTEDREGISTRARCONFIGMETHODS_TLV,
00213 (unsigned char*)&value, sizeof(value)) < 0) {
00214 DLOG_ERR("Could not get config_methods");
00215 } else {
00216 DLOG_DEBUG("Config_methods: %04x", GUINT16_FROM_BE(value));
00217 }
00218
00219 #endif
00220
00221 return;
00222 }