Home | History | Annotate | Download | only in eap_common
      1 /*
      2  * EAP common peer/server definitions
      3  * Copyright (c) 2004-2007, Jouni Malinen <j (at) w1.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 "includes.h"
     16 
     17 #include "common.h"
     18 #include "eap_defs.h"
     19 #include "eap_common.h"
     20 
     21 /**
     22  * eap_hdr_validate - Validate EAP header
     23  * @vendor: Expected EAP Vendor-Id (0 = IETF)
     24  * @eap_type: Expected EAP type number
     25  * @msg: EAP frame (starting with EAP header)
     26  * @plen: Pointer to variable to contain the returned payload length
     27  * Returns: Pointer to EAP payload (after type field), or %NULL on failure
     28  *
     29  * This is a helper function for EAP method implementations. This is usually
     30  * called in the beginning of struct eap_method::process() function to verify
     31  * that the received EAP request packet has a valid header. This function is
     32  * able to process both legacy and expanded EAP headers and in most cases, the
     33  * caller can just use the returned payload pointer (into *plen) for processing
     34  * the payload regardless of whether the packet used the expanded EAP header or
     35  * not.
     36  */
     37 const u8 * eap_hdr_validate(int vendor, EapType eap_type,
     38 			    const struct wpabuf *msg, size_t *plen)
     39 {
     40 	const struct eap_hdr *hdr;
     41 	const u8 *pos;
     42 	size_t len;
     43 
     44 	hdr = wpabuf_head(msg);
     45 
     46 	if (wpabuf_len(msg) < sizeof(*hdr)) {
     47 		wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
     48 		return NULL;
     49 	}
     50 
     51 	len = be_to_host16(hdr->length);
     52 	if (len < sizeof(*hdr) + 1 || len > wpabuf_len(msg)) {
     53 		wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
     54 		return NULL;
     55 	}
     56 
     57 	pos = (const u8 *) (hdr + 1);
     58 
     59 	if (*pos == EAP_TYPE_EXPANDED) {
     60 		int exp_vendor;
     61 		u32 exp_type;
     62 		if (len < sizeof(*hdr) + 8) {
     63 			wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
     64 				   "length");
     65 			return NULL;
     66 		}
     67 		pos++;
     68 		exp_vendor = WPA_GET_BE24(pos);
     69 		pos += 3;
     70 		exp_type = WPA_GET_BE32(pos);
     71 		pos += 4;
     72 		if (exp_vendor != vendor || exp_type != (u32) eap_type) {
     73 			wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
     74 				   "type");
     75 			return NULL;
     76 		}
     77 
     78 		*plen = len - sizeof(*hdr) - 8;
     79 		return pos;
     80 	} else {
     81 		if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
     82 			wpa_printf(MSG_INFO, "EAP: Invalid frame type");
     83 			return NULL;
     84 		}
     85 		*plen = len - sizeof(*hdr) - 1;
     86 		return pos + 1;
     87 	}
     88 }
     89 
     90 
     91 /**
     92  * eap_msg_alloc - Allocate a buffer for an EAP message
     93  * @vendor: Vendor-Id (0 = IETF)
     94  * @type: EAP type
     95  * @payload_len: Payload length in bytes (data after Type)
     96  * @code: Message Code (EAP_CODE_*)
     97  * @identifier: Identifier
     98  * Returns: Pointer to the allocated message buffer or %NULL on error
     99  *
    100  * This function can be used to allocate a buffer for an EAP message and fill
    101  * in the EAP header. This function is automatically using expanded EAP header
    102  * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
    103  * not need to separately select which header type to use when using this
    104  * function to allocate the message buffers. The returned buffer has room for
    105  * payload_len bytes and has the EAP header and Type field already filled in.
    106  */
    107 struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
    108 			      u8 code, u8 identifier)
    109 {
    110 	struct wpabuf *buf;
    111 	struct eap_hdr *hdr;
    112 	size_t len;
    113 
    114 	len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
    115 		payload_len;
    116 	buf = wpabuf_alloc(len);
    117 	if (buf == NULL)
    118 		return NULL;
    119 
    120 	hdr = wpabuf_put(buf, sizeof(*hdr));
    121 	hdr->code = code;
    122 	hdr->identifier = identifier;
    123 	hdr->length = host_to_be16(len);
    124 
    125 	if (vendor == EAP_VENDOR_IETF) {
    126 		wpabuf_put_u8(buf, type);
    127 	} else {
    128 		wpabuf_put_u8(buf, EAP_TYPE_EXPANDED);
    129 		wpabuf_put_be24(buf, vendor);
    130 		wpabuf_put_be32(buf, type);
    131 	}
    132 
    133 	return buf;
    134 }
    135 
    136 
    137 /**
    138  * eap_update_len - Update EAP header length
    139  * @msg: EAP message from eap_msg_alloc
    140  *
    141  * This function updates the length field in the EAP header to match with the
    142  * current length for the buffer. This allows eap_msg_alloc() to be used to
    143  * allocate a larger buffer than the exact message length (e.g., if exact
    144  * message length is not yet known).
    145  */
    146 void eap_update_len(struct wpabuf *msg)
    147 {
    148 	struct eap_hdr *hdr;
    149 	hdr = wpabuf_mhead(msg);
    150 	if (wpabuf_len(msg) < sizeof(*hdr))
    151 		return;
    152 	hdr->length = host_to_be16(wpabuf_len(msg));
    153 }
    154 
    155 
    156 /**
    157  * eap_get_id - Get EAP Identifier from wpabuf
    158  * @msg: Buffer starting with an EAP header
    159  * Returns: The Identifier field from the EAP header
    160  */
    161 u8 eap_get_id(const struct wpabuf *msg)
    162 {
    163 	const struct eap_hdr *eap;
    164 
    165 	if (wpabuf_len(msg) < sizeof(*eap))
    166 		return 0;
    167 
    168 	eap = wpabuf_head(msg);
    169 	return eap->identifier;
    170 }
    171 
    172 
    173 /**
    174  * eap_get_id - Get EAP Type from wpabuf
    175  * @msg: Buffer starting with an EAP header
    176  * Returns: The EAP Type after the EAP header
    177  */
    178 EapType eap_get_type(const struct wpabuf *msg)
    179 {
    180 	if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
    181 		return EAP_TYPE_NONE;
    182 
    183 	return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
    184 }
    185