tls_nss.c
Go to the documentation of this file.
00001 /*
00002  * SSL/TLS interface functions for NSS
00003  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 #include <nspr/prtypes.h>
00017 #include <nspr/plarenas.h>
00018 #include <nspr/plhash.h>
00019 #include <nspr/prio.h>
00020 #include <nspr/prclist.h>
00021 #include <nspr/prlock.h>
00022 #include <nspr/prinit.h>
00023 #include <nspr/prerror.h>
00024 #include <nspr/prmem.h>
00025 #include <nss/nss.h>
00026 #include <nss/nssilckt.h>
00027 #include <nss/ssl.h>
00028 #include <nss/pk11func.h>
00029 #include <nss/secerr.h>
00030 
00031 #include "common.h"
00032 #include "tls.h"
00033 
00034 static int tls_nss_ref_count = 0;
00035 
00036 static PRDescIdentity nss_layer_id;
00037 
00038 
00039 struct tls_connection {
00040         PRFileDesc *fd;
00041 
00042         int established;
00043         int verify_peer;
00044         u8 *push_buf, *pull_buf, *pull_buf_offset;
00045         size_t push_buf_len, pull_buf_len;
00046 };
00047 
00048 
00049 static PRStatus nss_io_close(PRFileDesc *fd)
00050 {
00051         wpa_printf(MSG_DEBUG, "NSS: I/O close");
00052         return PR_SUCCESS;
00053 }
00054 
00055 
00056 static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
00057 {
00058         wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
00059         return PR_FAILURE;
00060 }
00061 
00062 
00063 static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
00064 {
00065         wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
00066         return PR_FAILURE;
00067 }
00068 
00069 
00070 static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
00071                              PRInt32 iov_size, PRIntervalTime timeout)
00072 {
00073         wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
00074         return PR_FAILURE;
00075 }
00076 
00077 
00078 static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
00079                            PRIntn flags, PRIntervalTime timeout)
00080 {
00081         struct tls_connection *conn = (struct tls_connection *) fd->secret;
00082         u8 *end;
00083 
00084         wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
00085 
00086         if (conn->pull_buf == NULL) {
00087                 wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
00088                 return PR_FAILURE;
00089         }
00090 
00091         end = conn->pull_buf + conn->pull_buf_len;
00092         if (end - conn->pull_buf_offset < amount)
00093                 amount = end - conn->pull_buf_offset;
00094         os_memcpy(buf, conn->pull_buf_offset, amount);
00095         conn->pull_buf_offset += amount;
00096         if (conn->pull_buf_offset == end) {
00097                 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
00098                 os_free(conn->pull_buf);
00099                 conn->pull_buf = conn->pull_buf_offset = NULL;
00100                 conn->pull_buf_len = 0;
00101         } else {
00102                 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
00103                            __func__,
00104                            (unsigned long) (end - conn->pull_buf_offset));
00105         }
00106         return amount;
00107 }
00108 
00109 
00110 static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
00111                            PRIntn flags, PRIntervalTime timeout)
00112 {
00113         struct tls_connection *conn = (struct tls_connection *) fd->secret;
00114         u8 *nbuf;
00115 
00116         wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
00117         wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
00118 
00119         nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
00120         if (nbuf == NULL) {
00121                 wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
00122                            "data to be sent");
00123                 return PR_FAILURE;
00124         }
00125         os_memcpy(nbuf + conn->push_buf_len, buf, amount);
00126         conn->push_buf = nbuf;
00127         conn->push_buf_len += amount;
00128 
00129         return amount;
00130 }
00131 
00132 
00133 static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
00134                                PRIntn flags, PRNetAddr *addr,
00135                                PRIntervalTime timeout)
00136 {
00137         wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
00138         return PR_FAILURE;
00139 }
00140 
00141 
00142 static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
00143                              PRIntn flags, const PRNetAddr *addr,
00144                              PRIntervalTime timeout)
00145 {
00146         wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
00147         return PR_FAILURE;
00148 }
00149 
00150 
00151 static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
00152 {
00153         wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
00154 
00155         /*
00156          * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
00157          * fake IPv4 address to work around this even though we are not really
00158          * using TCP.
00159          */
00160         os_memset(addr, 0, sizeof(*addr));
00161         addr->inet.family = PR_AF_INET;
00162 
00163         return PR_SUCCESS;
00164 }
00165 
00166 
00167 static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
00168                                        PRSocketOptionData *data)
00169 {
00170         switch (data->option) {
00171         case PR_SockOpt_Nonblocking:
00172                 wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
00173                 data->value.non_blocking = PR_TRUE;
00174                 return PR_SUCCESS;
00175         default:
00176                 wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
00177                            data->option);
00178                 return PR_FAILURE;
00179         }
00180 }
00181 
00182 
00183 static const PRIOMethods nss_io = {
00184         PR_DESC_LAYERED,
00185         nss_io_close,
00186         nss_io_read,
00187         nss_io_write,
00188         NULL /* available */,
00189         NULL /* available64 */,
00190         NULL /* fsync */,
00191         NULL /* fseek */,
00192         NULL /* fseek64 */,
00193         NULL /* fileinfo */,
00194         NULL /* fileinfo64 */,
00195         nss_io_writev,
00196         NULL /* connect */,
00197         NULL /* accept */,
00198         NULL /* bind */,
00199         NULL /* listen */,
00200         NULL /* shutdown */,
00201         nss_io_recv,
00202         nss_io_send,
00203         nss_io_recvfrom,
00204         nss_io_sendto,
00205         NULL /* poll */,
00206         NULL /* acceptread */,
00207         NULL /* transmitfile */,
00208         NULL /* getsockname */,
00209         nss_io_getpeername,
00210         NULL /* reserved_fn_6 */,
00211         NULL /* reserved_fn_5 */,
00212         nss_io_getsocketoption,
00213         NULL /* setsocketoption */,
00214         NULL /* sendfile */,
00215         NULL /* connectcontinue */,
00216         NULL /* reserved_fn_3 */,
00217         NULL /* reserved_fn_2 */,
00218         NULL /* reserved_fn_1 */,
00219         NULL /* reserved_fn_0 */
00220 };
00221 
00222 
00223 static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
00224 {
00225         wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
00226         return NULL;
00227 }
00228 
00229 
00230 void * tls_init(const struct tls_config *conf)
00231 {
00232         char *dir;
00233 
00234         tls_nss_ref_count++;
00235         if (tls_nss_ref_count > 1)
00236                 return (void *) 1;
00237 
00238         PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
00239 
00240         nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
00241 
00242         PK11_SetPasswordFunc(nss_password_cb);
00243 
00244         dir = getenv("SSL_DIR");
00245         if (dir) {
00246                 if (NSS_Init(dir) != SECSuccess) {
00247                         wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
00248                                    "failed", dir);
00249                         return NULL;
00250                 }
00251         } else {
00252                 if (NSS_NoDB_Init(NULL) != SECSuccess) {
00253                         wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
00254                                    "failed");
00255                         return NULL;
00256                 }
00257         }
00258 
00259         if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
00260             SECSuccess ||
00261             SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
00262             SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
00263             SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
00264                 wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
00265                 return NULL;
00266         }
00267 
00268         if (NSS_SetDomesticPolicy() != SECSuccess) {
00269                 wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
00270                 return NULL;
00271         }
00272 
00273         return (void *) 1;
00274 }
00275 
00276 void tls_deinit(void *ssl_ctx)
00277 {
00278         tls_nss_ref_count--;
00279         if (tls_nss_ref_count == 0) {
00280                 if (NSS_Shutdown() != SECSuccess)
00281                         wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
00282         }
00283 }
00284 
00285 
00286 int tls_get_errors(void *tls_ctx)
00287 {
00288         return 0;
00289 }
00290 
00291 
00292 static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
00293 {
00294         struct tls_connection *conn = arg;
00295         SECStatus res = SECSuccess;
00296         PRErrorCode err;
00297         CERTCertificate *cert;
00298         char *subject, *issuer;
00299 
00300         err = PR_GetError();
00301         if (IS_SEC_ERROR(err))
00302                 wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
00303                            "%d)", err - SEC_ERROR_BASE);
00304         else
00305                 wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
00306                            err);
00307         cert = SSL_PeerCertificate(fd);
00308         subject = CERT_NameToAscii(&cert->subject);
00309         issuer = CERT_NameToAscii(&cert->issuer);
00310         wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
00311                    subject, issuer);
00312         CERT_DestroyCertificate(cert);
00313         PR_Free(subject);
00314         PR_Free(issuer);
00315         if (conn->verify_peer)
00316                 res = SECFailure;
00317 
00318         return res;
00319 }
00320 
00321 
00322 static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
00323 {
00324         struct tls_connection *conn = client_data;
00325         wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
00326         conn->established = 1;
00327 }
00328 
00329 
00330 struct tls_connection * tls_connection_init(void *tls_ctx)
00331 {
00332         struct tls_connection *conn;
00333 
00334         conn = os_zalloc(sizeof(*conn));
00335         if (conn == NULL)
00336                 return NULL;
00337 
00338         conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
00339         if (conn->fd == NULL) {
00340                 os_free(conn);
00341                 return NULL;
00342         }
00343         conn->fd->secret = (void *) conn;
00344 
00345         conn->fd = SSL_ImportFD(NULL, conn->fd);
00346         if (conn->fd == NULL) {
00347                 os_free(conn);
00348                 return NULL;
00349         }
00350 
00351         if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
00352             SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
00353             SECSuccess ||
00354             SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
00355             SECSuccess ||
00356             SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
00357             SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
00358             SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
00359             SECSuccess) {
00360                 wpa_printf(MSG_ERROR, "NSS: Failed to set options");
00361                 PR_Close(conn->fd);
00362                 os_free(conn);
00363                 return NULL;
00364         }
00365 
00366         SSL_ResetHandshake(conn->fd, PR_FALSE);
00367 
00368         return conn;
00369 }
00370 
00371 
00372 void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
00373 {
00374         PR_Close(conn->fd);
00375         os_free(conn->push_buf);
00376         os_free(conn->pull_buf);
00377         os_free(conn);
00378 }
00379 
00380 
00381 int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
00382 {
00383         return conn->established;
00384 }
00385 
00386 
00387 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
00388 {
00389         return -1;
00390 }
00391 
00392 
00393 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
00394                               const struct tls_connection_params *params)
00395 {
00396         wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
00397         return 0;
00398 }
00399 
00400 
00401 int tls_global_set_params(void *tls_ctx,
00402                           const struct tls_connection_params *params)
00403 {
00404         return -1;
00405 }
00406 
00407 
00408 int tls_global_set_verify(void *tls_ctx, int check_crl)
00409 {
00410         return -1;
00411 }
00412 
00413 
00414 int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
00415                               int verify_peer)
00416 {
00417         conn->verify_peer = verify_peer;
00418         return 0;
00419 }
00420 
00421 
00422 int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
00423                           int tls_ia)
00424 {
00425         return -1;
00426 }
00427 
00428 
00429 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
00430                             struct tls_keys *keys)
00431 {
00432         /* NSS does not export master secret or client/server random. */
00433         return -1;
00434 }
00435 
00436 
00437 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
00438                        const char *label, int server_random_first,
00439                        u8 *out, size_t out_len)
00440 {
00441         if (conn == NULL || server_random_first) {
00442                 wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
00443                            "(server_random_first=%d)",
00444                            server_random_first);
00445                 return -1;
00446         }
00447 
00448         if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
00449             SECSuccess) {
00450                 wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
00451                            "(label='%s' out_len=%d", label, (int) out_len);
00452                 return -1;
00453         }
00454 
00455         return 0;
00456 }
00457 
00458 
00459 struct wpabuf * tls_connection_handshake(void *tls_ctx,
00460                                          struct tls_connection *conn,
00461                                          const struct wpabuf *in_data,
00462                                          struct wpabuf **appl_data)
00463 {
00464         struct wpabuf *out_data;
00465 
00466         wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
00467                    in_data ? (unsigned int) wpabuf_len(in_data) : 0);
00468 
00469         if (appl_data)
00470                 *appl_data = NULL;
00471 
00472         if (in_data && wpabuf_len(in_data) > 0) {
00473                 if (conn->pull_buf) {
00474                         wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
00475                                    "pull_buf", __func__,
00476                                    (unsigned long) conn->pull_buf_len);
00477                         os_free(conn->pull_buf);
00478                 }
00479                 conn->pull_buf = os_malloc(wpabuf_len(in_data));
00480                 if (conn->pull_buf == NULL)
00481                         return NULL;
00482                 os_memcpy(conn->pull_buf, wpabuf_head(in_data),
00483                           wpabuf_len(in_data));
00484                 conn->pull_buf_offset = conn->pull_buf;
00485                 conn->pull_buf_len = wpabuf_len(in_data);
00486         }
00487 
00488         SSL_ForceHandshake(conn->fd);
00489 
00490         if (conn->established && conn->push_buf == NULL) {
00491                 /* Need to return something to get final TLS ACK. */
00492                 conn->push_buf = os_malloc(1);
00493         }
00494 
00495         if (conn->push_buf == NULL)
00496                 return NULL;
00497         out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
00498         if (out_data == NULL)
00499                 os_free(conn->push_buf);
00500         conn->push_buf = NULL;
00501         conn->push_buf_len = 0;
00502         return out_data;
00503 }
00504 
00505 
00506 struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
00507                                                 struct tls_connection *conn,
00508                                                 const struct wpabuf *in_data,
00509                                                 struct wpabuf **appl_data)
00510 {
00511         return NULL;
00512 }
00513 
00514 
00515 struct wpabuf * tls_connection_encrypt(void *tls_ctx,
00516                                        struct tls_connection *conn,
00517                                        const struct wpabuf *in_data)
00518 {
00519         PRInt32 res;
00520         struct wpabuf *buf;
00521 
00522         wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
00523                    (int) wpabuf_len(in_data));
00524         res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
00525                       0);
00526         if (res < 0) {
00527                 wpa_printf(MSG_ERROR, "NSS: Encryption failed");
00528                 return NULL;
00529         }
00530         if (conn->push_buf == NULL)
00531                 return NULL;
00532         buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
00533         if (buf == NULL)
00534                 os_free(conn->push_buf);
00535         conn->push_buf = NULL;
00536         conn->push_buf_len = 0;
00537         return buf;
00538 }
00539 
00540 
00541 struct wpabuf * tls_connection_decrypt(void *tls_ctx,
00542                                        struct tls_connection *conn,
00543                                        const struct wpabuf *in_data)
00544 {
00545         PRInt32 res;
00546         struct wpabuf *out;
00547 
00548         wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
00549                    (int) wpabuf_len(in_data));
00550         if (conn->pull_buf) {
00551                 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
00552                            "pull_buf", __func__,
00553                            (unsigned long) conn->pull_buf_len);
00554                 os_free(conn->pull_buf);
00555         }
00556         conn->pull_buf = os_malloc(wpabuf_len(in_data));
00557         if (conn->pull_buf == NULL)
00558                 return NULL;
00559         os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
00560         conn->pull_buf_offset = conn->pull_buf;
00561         conn->pull_buf_len = wpabuf_len(in_data);
00562 
00563         /*
00564          * Even though we try to disable TLS compression, it is possible that
00565          * this cannot be done with all TLS libraries. Add extra buffer space
00566          * to handle the possibility of the decrypted data being longer than
00567          * input data.
00568          */
00569         out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
00570         if (out == NULL)
00571                 return NULL;
00572 
00573         res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
00574         wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
00575         if (res < 0) {
00576                 wpabuf_free(out);
00577                 return NULL;
00578         }
00579         wpabuf_put(out, res);
00580 
00581         return out;
00582 }
00583 
00584 
00585 int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
00586 {
00587         return 0;
00588 }
00589 
00590 
00591 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
00592                                    u8 *ciphers)
00593 {
00594         return -1;
00595 }
00596 
00597 
00598 int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
00599                    char *buf, size_t buflen)
00600 {
00601         return -1;
00602 }
00603 
00604 
00605 int tls_connection_enable_workaround(void *tls_ctx,
00606                                      struct tls_connection *conn)
00607 {
00608         return -1;
00609 }
00610 
00611 
00612 int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
00613                                     int ext_type, const u8 *data,
00614                                     size_t data_len)
00615 {
00616         return -1;
00617 }
00618 
00619 
00620 int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
00621 {
00622         return 0;
00623 }
00624 
00625 
00626 int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
00627 {
00628         return 0;
00629 }
00630 
00631 
00632 int tls_connection_get_write_alerts(void *tls_ctx,
00633                                     struct tls_connection *conn)
00634 {
00635         return 0;
00636 }
00637 
00638 
00639 int tls_connection_get_keyblock_size(void *tls_ctx,
00640                                      struct tls_connection *conn)
00641 {
00642         return -1;
00643 }
00644 
00645 
00646 unsigned int tls_capabilities(void *tls_ctx)
00647 {
00648         return 0;
00649 }
00650 
00651 
00652 struct wpabuf * tls_connection_ia_send_phase_finished(
00653         void *tls_ctx, struct tls_connection *conn, int final)
00654 {
00655         return NULL;
00656 }
00657 
00658 
00659 int tls_connection_ia_final_phase_finished(void *tls_ctx,
00660                                            struct tls_connection *conn)
00661 {
00662         return -1;
00663 }
00664 
00665 
00666 int tls_connection_ia_permute_inner_secret(void *tls_ctx,
00667                                            struct tls_connection *conn,
00668                                            const u8 *key, size_t key_len)
00669 {
00670         return -1;
00671 }
00672 
00673 
00674 int tls_connection_set_session_ticket_cb(void *tls_ctx,
00675                                          struct tls_connection *conn,
00676                                          tls_session_ticket_cb cb,
00677                                          void *ctx)
00678 {
00679         return -1;
00680 }


wpa_supplicant_node
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:25:14