~ubuntu-branches/ubuntu/lucid/wpasupplicant/lucid

« back to all changes in this revision

Viewing changes to eap_tlv.c

  • Committer: Bazaar Package Importer
  • Author(s): Kyle McMartin
  • Date: 2005-02-15 00:51:28 UTC
  • Revision ID: james.westby@ubuntu.com-20050215005128-xr4m8owiunur2008
Tags: upstream-0.3.8
ImportĀ upstreamĀ versionĀ 0.3.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * WPA Supplicant / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
 
3
 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License version 2 as
 
7
 * published by the Free Software Foundation.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include <stdlib.h>
 
16
#include <stdio.h>
 
17
#include <string.h>
 
18
 
 
19
#include "common.h"
 
20
#include "wpa_supplicant.h"
 
21
#include "eap_i.h"
 
22
#include "eap_tlv.h"
 
23
 
 
24
 
 
25
u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len)
 
26
{
 
27
        struct eap_hdr *hdr;
 
28
        u8 *pos;
 
29
 
 
30
        *resp_len = sizeof(struct eap_hdr) + 1 + 10;
 
31
        hdr = malloc(*resp_len);
 
32
        if (hdr == NULL)
 
33
                return NULL;
 
34
 
 
35
        hdr->code = EAP_CODE_RESPONSE;
 
36
        hdr->identifier = id;
 
37
        hdr->length = host_to_be16(*resp_len);
 
38
        pos = (u8 *) (hdr + 1);
 
39
        *pos++ = EAP_TYPE_TLV;
 
40
        *pos++ = 0x80; /* Mandatory */
 
41
        *pos++ = EAP_TLV_NAK_TLV;
 
42
        /* Length */
 
43
        *pos++ = 0;
 
44
        *pos++ = 6;
 
45
        /* Vendor-Id */
 
46
        *pos++ = 0;
 
47
        *pos++ = 0;
 
48
        *pos++ = 0;
 
49
        *pos++ = 0;
 
50
        /* NAK-Type */
 
51
        *pos++ = nak_type >> 8;
 
52
        *pos++ = nak_type & 0xff;
 
53
 
 
54
        return (u8 *) hdr;
 
55
}
 
56
 
 
57
 
 
58
u8 * eap_tlv_build_result(int id, int status, size_t *resp_len)
 
59
{
 
60
        struct eap_hdr *hdr;
 
61
        u8 *pos;
 
62
 
 
63
        *resp_len = sizeof(struct eap_hdr) + 1 + 6;
 
64
        hdr = malloc(*resp_len);
 
65
        if (hdr == NULL)
 
66
                return NULL;
 
67
 
 
68
        hdr->code = EAP_CODE_RESPONSE;
 
69
        hdr->identifier = id;
 
70
        hdr->length = host_to_be16(*resp_len);
 
71
        pos = (u8 *) (hdr + 1);
 
72
        *pos++ = EAP_TYPE_TLV;
 
73
        *pos++ = 0x80; /* Mandatory */
 
74
        *pos++ = EAP_TLV_RESULT_TLV;
 
75
        /* Length */
 
76
        *pos++ = 0;
 
77
        *pos++ = 2;
 
78
        /* Status */
 
79
        *pos++ = status >> 8;
 
80
        *pos++ = status & 0xff;
 
81
 
 
82
        return (u8 *) hdr;
 
83
}
 
84
 
 
85
 
 
86
int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
 
87
                    struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
 
88
{
 
89
        size_t left;
 
90
        u8 *pos;
 
91
        u8 *result_tlv = NULL;
 
92
        size_t result_tlv_len = 0;
 
93
        int tlv_type, mandatory, tlv_len;
 
94
 
 
95
        /* Parse TLVs */
 
96
        left = be_to_host16(hdr->length) - sizeof(struct eap_hdr) - 1;
 
97
        pos = (u8 *) (hdr + 1);
 
98
        pos++;
 
99
        wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
 
100
        while (left >= 4) {
 
101
                mandatory = !!(pos[0] & 0x80);
 
102
                tlv_type = pos[0] & 0x3f;
 
103
                tlv_type = (tlv_type << 8) | pos[1];
 
104
                tlv_len = ((int) pos[2] << 8) | pos[3];
 
105
                pos += 4;
 
106
                left -= 4;
 
107
                if (tlv_len > left) {
 
108
                        wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
 
109
                                   "(tlv_len=%d left=%lu)", tlv_len,
 
110
                                   (unsigned long) left);
 
111
                        return -1;
 
112
                }
 
113
                switch (tlv_type) {
 
114
                case EAP_TLV_RESULT_TLV:
 
115
                        result_tlv = pos;
 
116
                        result_tlv_len = tlv_len;
 
117
                        break;
 
118
                default:
 
119
                        wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
 
120
                                   "%d%s", tlv_type,
 
121
                                   mandatory ? " (mandatory)" : "");
 
122
                        if (mandatory) {
 
123
                                /* NAK TLV and ignore all TLVs in this packet.
 
124
                                 */
 
125
                                *resp = eap_tlv_build_nak(hdr->identifier,
 
126
                                                          tlv_type, resp_len);
 
127
                                return *resp == NULL ? -1 : 0;
 
128
                        }
 
129
                        /* Ignore this TLV, but process other TLVs */
 
130
                        break;
 
131
                }
 
132
 
 
133
                pos += tlv_len;
 
134
                left -= tlv_len;
 
135
        }
 
136
        if (left) {
 
137
                wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
 
138
                           "Request (left=%lu)", (unsigned long) left);
 
139
                return -1;
 
140
        }
 
141
 
 
142
        /* Process supported TLVs */
 
143
        if (result_tlv) {
 
144
                int status, resp_status;
 
145
                wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
 
146
                            result_tlv, result_tlv_len);
 
147
                if (result_tlv_len < 2) {
 
148
                        wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
 
149
                                   "(len=%lu)",
 
150
                                   (unsigned long) result_tlv_len);
 
151
                        return -1;
 
152
                }
 
153
                status = ((int) result_tlv[0] << 8) | result_tlv[1];
 
154
                if (status == EAP_TLV_RESULT_SUCCESS) {
 
155
                        wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
 
156
                                   "- EAP-TLV/Phase2 Completed");
 
157
                        resp_status = EAP_TLV_RESULT_SUCCESS;
 
158
                        ret->decision = DECISION_UNCOND_SUCC;
 
159
                } else if (status == EAP_TLV_RESULT_FAILURE) {
 
160
                        wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
 
161
                        resp_status = EAP_TLV_RESULT_FAILURE;
 
162
                        ret->decision = DECISION_FAIL;
 
163
                } else {
 
164
                        wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
 
165
                                   "Status %d", status);
 
166
                        resp_status = EAP_TLV_RESULT_FAILURE;
 
167
                        ret->decision = DECISION_FAIL;
 
168
                }
 
169
                ret->methodState = METHOD_DONE;
 
170
 
 
171
                *resp = eap_tlv_build_result(hdr->identifier, resp_status,
 
172
                                             resp_len);
 
173
        }
 
174
 
 
175
        return 0;
 
176
}