dont require a buffer for subnegotiations with no data; more efficient for apps that dont use more advanced subnegotiation features
diff --git a/README b/README
index ce695bd..f3d7e1a 100644
--- a/README
+++ b/README
@@ -20,13 +20,11 @@
 
  - RFC 1143 option negotiation algorithm
  - automatic MCCP2 handling (controllable by host app)
- - efficient one-byte sub-requests
  ? MCCP1
  ? ZMP parsing
  ? MSSP parsing
  ? ENVIRON/NEW-ENVIRON parsing
  ? telnet-status testing tool
- ? few options to make telnet-proxy even more useful
 
 I. INTRODUCTION
 =====================================================================
diff --git a/libtelnet.c b/libtelnet.c
index 4a521e6..27513ef 100644
--- a/libtelnet.c
+++ b/libtelnet.c
@@ -263,11 +263,18 @@
 			telnet->state = LIBTELNET_STATE_DATA;
 			break;
 
-		/* subnegotiation -- buffer bytes until end request */
+		/* subnegotiation -- determine subnegotiation telopt */
 		case LIBTELNET_STATE_SB:
+			telnet->sb_telopt = byte;
+			telnet->length = 0;
+			telnet->state = LIBTELNET_STATE_SB_DATA;
+			break;
+
+		/* subnegotiation -- buffer bytes until end request */
+		case LIBTELNET_STATE_SB_DATA:
 			/* IAC command in subnegotiation -- either IAC SE or IAC IAC */
 			if (byte == LIBTELNET_IAC) {
-				telnet->state = LIBTELNET_STATE_SB_IAC;
+				telnet->state = LIBTELNET_STATE_SB_DATA_IAC;
 			/* buffer the byte, or bail if we can't */
 			} else if (_buffer_byte(telnet, byte, user_data) !=
 					LIBTELNET_EOK) {
@@ -277,7 +284,7 @@
 			break;
 
 		/* IAC escaping inside a subnegotiation */
-		case LIBTELNET_STATE_SB_IAC:
+		case LIBTELNET_STATE_SB_DATA_IAC:
 			switch (byte) {
 			/* end subnegotiation */
 			case LIBTELNET_SE:
@@ -285,25 +292,17 @@
 				start = i + 1;
 				telnet->state = LIBTELNET_STATE_DATA;
 
-				/* zero-size buffer is a protocol error */
-				if (telnet->length == 0) {
-					ERROR(telnet, LIBTELNET_EPROTOCOL, user_data,
-							"subnegotiation has zero data");
-					break;
-				}
-
 				/* invoke callback */
 				_event(telnet, LIBTELNET_EV_SUBNEGOTIATION, 0,
-						telnet->buffer[0], telnet->buffer + 1,
-						telnet->length - 1, user_data);
-				telnet->length = 0;
+						telnet->sb_telopt, telnet->buffer, telnet->length,
+						user_data);
 
 #ifdef HAVE_ZLIB
 				/* if we are a client or a proxy and just received the
 				 * COMPRESS2 begin marker, setup our zlib box and start
 				 * handling the compressed stream if it's not already.
 				 */
-				if (telnet->buffer[0] == LIBTELNET_TELOPT_COMPRESS2 &&
+				if (telnet->sb_telopt == LIBTELNET_TELOPT_COMPRESS2 &&
 						telnet->z_inflate == 0 &&
 						(telnet->mode == LIBTELNET_MODE_CLIENT ||
 						 telnet->mode == LIBTELNET_MODE_PROXY)) {
@@ -337,7 +336,7 @@
 					start = i + 1;
 					telnet->state = LIBTELNET_STATE_DATA;
 				} else {
-					telnet->state = LIBTELNET_STATE_SB;
+					telnet->state = LIBTELNET_STATE_SB_DATA;
 				}
 				break;
 			/* something else -- protocol error */
diff --git a/libtelnet.h b/libtelnet.h
index 87f0659..629dace 100644
--- a/libtelnet.h
+++ b/libtelnet.h
@@ -101,7 +101,8 @@
 	LIBTELNET_STATE_WILL,
 	LIBTELNET_STATE_WONT,
 	LIBTELNET_STATE_SB,
-	LIBTELNET_STATE_SB_IAC
+	LIBTELNET_STATE_SB_DATA,
+	LIBTELNET_STATE_SB_DATA_IAC
 };
 
 /* error codes */
@@ -160,6 +161,8 @@
 	enum libtelnet_state_t state;
 	/* processing mode */
 	enum libtelnet_mode_t mode;
+	/* current subnegotiation telopt */
+	unsigned char sb_telopt;
 };
 
 /* initialize a telnet state tracker */