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