From 6e1224868d0b300fe08d738abe130d170610d210 Mon Sep 17 00:00:00 2001
From: "7u83@mail.ru" <7u83@mail.ru@noemail.net>
Date: Mon, 6 Apr 2015 07:17:13 +0000
Subject: [PATCH] Fixed some bugx, pulled in code from other files.
FossilOrigin-Name: ee339494cc66985f8b16a60fc2d1d29861e8fedc588ca2ab9c4a82af47338d79
---
 src/capwap/cw_process_msg.c | 144 +++++++++++++++++++++++++++++++-----
 1 file changed, 126 insertions(+), 18 deletions(-)
diff --git a/src/capwap/cw_process_msg.c b/src/capwap/cw_process_msg.c
index bbcb8b84..1b4f7c43 100644
--- a/src/capwap/cw_process_msg.c
+++ b/src/capwap/cw_process_msg.c
@@ -1,3 +1,25 @@
+/*
+    This file is part of libcapwap.
+
+    libcapwap is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    libcapwap is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Foobar.  If not, see .
+
+*/
+
+/**
+ * @file 
+ * @brief Processing of incomming messaages.
+ */ 
 
 #include 
 #include 
@@ -12,26 +34,69 @@
 #include "dbg.h"
 
 
-//int cw_out_msg(struct conn *conn, uint8_t * rawout);
 
 int conn_send_msg(struct conn *conn, uint8_t * rawmsg);
 
+
+
+
+/**
+ * Init response message header
+ */ 
+void cw_init_response(struct conn * conn, uint8_t *req)
+{
+	uint8_t *buffer=conn->resp_buffer;
+	int shbytes = cw_get_hdr_msg_offset(req);
+	int dhbytes;
+	memcpy(buffer,req,shbytes);
+	cw_set_hdr_hlen(buffer,2);
+	cw_set_hdr_flags(buffer,CW_FLAG_HDR_M,1);
+	dhbytes = cw_get_hdr_msg_offset(buffer);
+
+	uint8_t * msgptr = req+shbytes;
+	uint8_t * dmsgptr = buffer+dhbytes;
+
+	cw_set_msg_type(dmsgptr,cw_get_msg_type(msgptr)+1);
+	cw_set_msg_seqnum(dmsgptr,cw_get_msg_seqnum(msgptr));
+	cw_set_msg_flags(dmsgptr,0);
+}
+
+/**
+ * send a response 
+ */ 
 int cw_send_response(struct conn *conn, uint8_t * rawmsg, int len)
 {
-//	struct priv priv;
-
 	cw_init_response(conn, rawmsg);
-
-
-//	uint8_t *msgptr = rawmsg + cw_get_hdr_msg_offset(rawmsg);
-
-//	cw_action_out_t as;
-
-
 	cw_put_msg(conn,conn->resp_buffer);
 	conn_send_msg(conn, conn->resp_buffer);
 	return 1;
+}
 
+
+
+
+/**
+ * Special case error message, which is sent when an unexpected messages 
+ * was received or somethin else happened.
+ * @param conn conection
+ * @param rawmsg the received request message, which the response belongs to
+ * @pqram result_code result code to send
+ * @return 1
+ */ 
+int cw_send_error_response(struct conn *conn,uint8_t *rawmsg, uint32_t result_code)
+{
+	cw_init_response(conn,rawmsg);
+	
+	uint8_t *out = conn->resp_buffer;
+
+	uint8_t *dst = cw_get_hdr_msg_elems_ptr(out);
+	int l = cw_put_elem_result_code(dst,result_code);
+	
+	cw_set_msg_elems_len(out+cw_get_hdr_msg_offset(out), l);
+
+	conn_send_msg(conn, conn->resp_buffer);
+
+	return 1;
 }
 
 
@@ -72,17 +137,39 @@ int cw_process_msg(struct conn *conn, uint8_t * rawmsg, int len)
 	as.capwap_state = conn->capwap_state;
 	as.msg_id = cw_get_msg_id(msg_ptr);
 	as.vendor_id = 0;
-	as.elem_id = -1;
+	as.elem_id = 0;
 	as.proto=0;
 
 
 	/* Search for state/message combination */
 	afm = cw_actionlist_in_get(conn->actions->in, &as);
 
-	/* Check if message comes in right state */
 	if (!afm) {
-		cw_dbg(DBG_MSG_ERR, "Message type %d (%s) not allowed in %s State.",
-		       as.msg_id, cw_strmsg(as.msg_id), cw_strstate(as.capwap_state));
+		/* Throw away unexpected response messages */
+		if (!(as.msg_id &1)) {
+			cw_dbg(DBG_MSG_ERR, "Message type %d (%s) unexpected, discarding.",
+			       as.msg_id, cw_strmsg(as.msg_id));
+			return 0;
+		}
+
+		/* Request message not found in current state, check if we know 
+		   anything else about this message type */ 
+		const char *str = cw_strheap_get(conn->actions->strmsg,as.msg_id);
+		int result_code=0;
+		if (str) {
+			/* Message found, but it was in wrong state */
+			cw_dbg(DBG_MSG_ERR, "Message type %d (%s) not allowed in %s State.",
+			       as.msg_id, cw_strmsg(as.msg_id), cw_strstate(as.capwap_state));
+			result_code = CW_RESULT_MSG_INVALID_IN_CURRENT_STATE;		
+		}
+		else {
+			/* Message is unknown */
+			cw_dbg(DBG_MSG_ERR, "Message type %d (%s) unknown.",
+			       as.msg_id, cw_strmsg(as.msg_id), cw_strstate(as.capwap_state));
+			result_code = CW_RESULT_MSG_UNRECOGNIZED;
+		
+		}
+		cw_send_error_response(conn,rawmsg,result_code);
 		return 0;
 	}
 
@@ -95,6 +182,9 @@ int cw_process_msg(struct conn *conn, uint8_t * rawmsg, int len)
 	uint8_t *elems_ptr = cw_get_msg_elems_ptr(msg_ptr);
 	uint8_t *elem;
 
+	conn->mand = intavltree_create();
+
+	/* iterate through message elements */
 	cw_foreach_elem(elem, elems_ptr, elems_len) {
 
 		as.elem_id = cw_get_elem_id(elem);
@@ -110,6 +200,12 @@ int cw_process_msg(struct conn *conn, uint8_t * rawmsg, int len)
 			       as.elem_id, as.msg_id, cw_strmsg(as.msg_id));
 			continue;
 		}
+	
+		if (af->mand){
+			/* add found mandatory message element 
+			   to mand list */	
+			intavltree_add(conn->mand,af->item_id);
+		}
 
 		if (af->start) {
 			af->start(conn, af, cw_get_elem_data(elem), elem_len);
@@ -117,13 +213,25 @@ int cw_process_msg(struct conn *conn, uint8_t * rawmsg, int len)
 
 	}
 
-
-	cw_send_response(conn, rawmsg, len);
-
+	int result_code=0;
 	if (afm->end) {
-		afm->end(conn, afm, rawmsg, len);
+		result_code=afm->end(conn, afm, rawmsg, len);
 	}
 
+	/* if we've got a request message, we have to send a response message */
+	if (as.msg_id & 1) {
+		if ( result_code>0 ) {
+			/* the end method gave us an result code, so
+			   send an error message */
+			cw_send_error_response(conn,rawmsg,result_code);
+		}
+		else{
+			/* regular response message */
+			cw_send_response(conn, rawmsg, len);
+		}
+	}
+
+	intavltree_destroy(conn->mand);
 
 	return 0;