wps.c

Go to the documentation of this file.
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 /* TLV defitions */
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         // Find the TLV value
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                 //DLOG_DEBUG("tmp_type: %04x", tmp_type);
00082 
00083                 guint length = 0;
00084                 
00085                 hi = msg[len+2];
00086                 lo = msg[len+3];
00087                 
00088                 length = (hi << 8) + lo;
00089                 
00090                 // check the type
00091                 if (tmp_type == type)
00092                 {
00093                         if (length > value_len) {
00094                                 DLOG_ERR("Too much data for buffer (%d)", value_len);
00095                                 return -1;
00096                         }
00097                         if (len + 4 + length > msg_size) {
00098                                 DLOG_ERR("Message data too short?");
00099                                 return -1;
00100                         }
00101 
00102                         memcpy(value, msg+len+4, length);
00103                         //DLOG_DEBUG("value: %04x", *value);
00104                         
00105                         return length;
00106                 }        
00107                 
00108                 len = len + length + 4; 
00109         }
00110         
00111         return -1;
00112 }
00120 int 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 #ifdef DEBUG_WPS
00127         char uuid_e[MAX_UUID_E_LEN];
00128 #endif
00129         gint len;
00130         
00131         int ret = -1;
00132 
00133         if (length < 2) {
00134                 DLOG_ERR("WPS IE too short");
00135                 return -1;
00136         }
00137 #if 0
00138         unsigned int i;
00139         for (i=0;i<length;i++) {
00140                 DLOG_DEBUG("%02x", p[i]);
00141         }
00142 #endif
00143 
00144         /* Mandatory fields */
00145         if (get_tlv_value(p, length, WPS_VERSION_TLV, (unsigned char*)&value, 
00146                           sizeof(value)) < 0 || value != WPS_VERSION) {
00147                 DLOG_ERR("Unknown WPS version received (%02x)", value);
00148                 return ret;
00149         }
00150         
00151         if (get_tlv_value(p, length, WPS_STATE_TLV, (unsigned char*)&value, 
00152                           sizeof(value)) < 0) {
00153                 DLOG_ERR("Could not get WPS state");
00154                 return ret;
00155         }
00156 
00157         DLOG_DEBUG("WPS state: %s", value == WPS_STATE_CONFIGURED?"configured":
00158                    "unconfigured");
00159         
00160         scan_results->cap_bits |= WLANCOND_WPS;
00161         
00162         ret = 0;
00163         
00164         /* Everything else is optional */
00165         if (get_tlv_value(p, length, WPS_APSETUPLOCKED_TLV, 
00166                           (unsigned char*)&value, sizeof(value)) < 0) {
00167                 //DLOG_ERR("Could not get ap_setup_locked");
00168         } else {
00169                 DLOG_DEBUG("ap_setup_locked: %d", value); 
00170         }
00171         
00172         if (get_tlv_value(p, length, WPS_SELECTEDREGISTRAR_TLV, 
00173                           (unsigned char*)&value, sizeof(value)) < 0) {
00174                 //DLOG_ERR("Could not get selected_registrar");
00175         } else if (value) {
00176                 DLOG_DEBUG("Device is selected registrar");
00177                 scan_results->cap_bits |= WLANCOND_WPS_CONFIGURED;
00178         }
00179         
00180         if (get_tlv_value(p, length, WPS_DEVICEPASSWORD_ID_TLV, 
00181                           (unsigned char*)&value, sizeof(value)) < 0) {
00182                 //DLOG_ERR("Assuming PUSH and PIN");
00183                 // If AP does not give this info, let's assume the following
00184                 scan_results->cap_bits |= WLANCOND_WPS_PIN; 
00185                 scan_results->cap_bits |= WLANCOND_WPS_PUSH_BUTTON;
00186         } else {
00187                 if (GUINT16_FROM_BE(value) == WPS_PIN_CODE) {
00188                         DLOG_ERR("PIN supported");
00189                         scan_results->cap_bits |= WLANCOND_WPS_PIN;
00190                 } 
00191                 if (GUINT16_FROM_BE(value) == WPS_PUSH_BUTTON) {
00192                         DLOG_ERR("PBC supported");
00193                         scan_results->cap_bits |= WLANCOND_WPS_PUSH_BUTTON;
00194                 }
00195         }
00196         
00197         if ((len = get_tlv_value(p, length, WPS_DEVICENAME_TLV, 
00198                                  (unsigned char*)&device_name, 
00199                                  sizeof(device_name)-1)) < 0) {
00200                 //DLOG_ERR("Could not get device name");
00201         } else {
00202                 device_name[len] = '\0';
00203                 DLOG_DEBUG("Device name: %s", device_name);
00204         }    
00205         
00206 #ifdef DEBUG_WPS        
00207 
00208         if (get_tlv_value(p, length, WPS_SELECTEDREGISTRARCONFIGMETHODS_TLV, 
00209                           (unsigned char*)&value, sizeof(value)) < 0) {
00210                 DLOG_ERR("Could not get config_methods");
00211         } else {
00212                 DLOG_DEBUG("Config_methods: %04x", GUINT16_FROM_BE(value));
00213         }
00214         
00215         if ((len = get_tlv_value(p, length, WPS_UUID_E_TLV, 
00216                                  (unsigned char*)&uuid_e, 
00217                                  sizeof(uuid_e))) < 0) {
00218                 DLOG_ERR("Could not get UUID-E");
00219         } else {
00220 #if 0
00221                 int j;
00222                 for (j=0;j<len;j++) {
00223                         DLOG_DEBUG("UUID-E: %d", uuid_e[j]);
00224                 }
00225 #endif
00226         } 
00227 #endif
00228 
00229         return ret;
00230 }

Generated on Sat Dec 6 22:17:00 2008 for WLAN Connection Daemon by  doxygen 1.5.1