[ofa-general] [PATCH 2/2] RDMA/nes: Handle MPA Reject message properly

Faisal Latif faisal.latif at intel.com
Thu Mar 5 12:59:36 PST 2009


While doing testing, there are failures as MPA Reject call is not
handled. 
To handle MPA Reject call, following changes are done.

*Handle inbound/outbound MPA Reject response message.
	When nes_reject() is called for pending MPA request reply, send the
	MPA Reject message to its peer (active side)cm_node. The peer
	cm_node (active side) will indicate Reject message event for the
	pending Connect Request.

*Handle MPA Reject response message for loopback connections and listener.
	When MPA Request is rejected, check if it is a loopback connection
	and if it is then it will send Reject message event to its peer
	loopback node. Also when destroying listener, check if the cm_nodes
	for that listener are loopback or not.

*Add gracefull connection close with the MPA Reject response message.
	Send gracefull close (FIN, FIN ACK..) to terminate the cm_nodes.
	
*Some code re-org while making the above changes.
	Removed recv_list and recv_list_lock from the cm_node structure as
	there can be only one receive close entry on the timer. Also
	implemented handle_recv_entry() as receive close entry is processed
	from both nes_rem_ref_cm_node() as well as nes_cm_timer_tick().


Signed-off-by: Faisal Latif <faisal.latif at intel.com>
---
 drivers/infiniband/hw/nes/nes_cm.c |  580 ++++++++++++++++++++++++------------
 drivers/infiniband/hw/nes/nes_cm.h |   10 +-
 2 files changed, 399 insertions(+), 191 deletions(-)

diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 6681d57..5242515 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -103,6 +103,7 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt);
 static void nes_disconnect_worker(struct work_struct *work);
 
 static int send_mpa_request(struct nes_cm_node *, struct sk_buff *);
+static int send_mpa_reject(struct nes_cm_node *);
 static int send_syn(struct nes_cm_node *, u32, struct sk_buff *);
 static int send_reset(struct nes_cm_node *, struct sk_buff *);
 static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb);
@@ -113,8 +114,7 @@ static void process_packet(struct nes_cm_node *, struct sk_buff *,
 static void active_open_err(struct nes_cm_node *, struct sk_buff *, int);
 static void passive_open_err(struct nes_cm_node *, struct sk_buff *, int);
 static void cleanup_retrans_entry(struct nes_cm_node *);
-static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *,
-	enum nes_cm_event_type);
+static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *);
 static void free_retrans_entry(struct nes_cm_node *cm_node);
 static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
 	struct sk_buff *skb, int optionsize, int passive);
@@ -124,6 +124,8 @@ static void cm_event_connected(struct nes_cm_event *);
 static void cm_event_connect_error(struct nes_cm_event *);
 static void cm_event_reset(struct nes_cm_event *);
 static void cm_event_mpa_req(struct nes_cm_event *);
+static void cm_event_mpa_reject(struct nes_cm_event *);
+static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node);
 
 static void print_core(struct nes_cm_core *core);
 
@@ -196,7 +198,6 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
  */
 static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
-	int ret;
 	if (!skb) {
 		nes_debug(NES_DBG_CM, "skb set to NULL\n");
 		return -1;
@@ -206,11 +207,27 @@ static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
 	form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
 			cm_node->mpa_frame_size, SET_ACK);
 
-	ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
-	if (ret < 0)
-		return ret;
+	return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+}
 
-	return 0;
+
+
+static int send_mpa_reject(struct nes_cm_node *cm_node)
+{
+	struct sk_buff  *skb = NULL;
+
+	skb = dev_alloc_skb(MAX_CM_BUFFER);
+	if (!skb) {
+		nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+		return -ENOMEM;
+	}
+
+	/* send an MPA reject frame */
+	form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
+			cm_node->mpa_frame_size, SET_ACK | SET_FIN);
+
+	cm_node->state = NES_CM_STATE_FIN_WAIT1;
+	return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
 }
 
 
@@ -218,14 +235,17 @@ static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
  * recv_mpa - process a received TCP pkt, we are expecting an
  * IETF MPA frame
  */
-static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
+static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,
+		u32 len)
 {
 	struct ietf_mpa_frame *mpa_frame;
 
+	*type = NES_MPA_REQUEST_ACCEPT;
+
 	/* assume req frame is in tcp data payload */
 	if (len < sizeof(struct ietf_mpa_frame)) {
 		nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);
-		return -1;
+		return -EINVAL;
 	}
 
 	mpa_frame = (struct ietf_mpa_frame *)buffer;
@@ -234,14 +254,25 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
 	if (cm_node->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {
 		nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
 				" complete (%x + %x != %x)\n",
-				cm_node->mpa_frame_size, (u32)sizeof(struct ietf_mpa_frame), len);
-		return -1;
+				cm_node->mpa_frame_size,
+				(u32)sizeof(struct ietf_mpa_frame), len);
+		return -EINVAL;
+	}
+	/* make sure it does not exceed the max size */
+	if (len > MAX_CM_BUFFER) {
+		nes_debug(NES_DBG_CM, "The received ietf buffer was too large"
+				" (%x + %x != %x)\n",
+				cm_node->mpa_frame_size,
+				(u32)sizeof(struct ietf_mpa_frame), len);
+		return -EINVAL;
 	}
 
 	/* copy entire MPA frame to our cm_node's frame */
 	memcpy(cm_node->mpa_frame_buf, buffer + sizeof(struct ietf_mpa_frame),
 			cm_node->mpa_frame_size);
 
+	if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)
+		*type = NES_MPA_REQUEST_REJECT;
 	return 0;
 }
 
@@ -380,7 +411,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
 
 	new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
 	if (!new_send)
-		return -1;
+		return -ENOMEM;
 
 	/* new_send->timetosend = currenttime */
 	new_send->retrycount = NES_DEFAULT_RETRYS;
@@ -394,9 +425,11 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
 
 	if (type == NES_TIMER_TYPE_CLOSE) {
 		new_send->timetosend += (HZ/10);
-		spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-		list_add_tail(&new_send->list, &cm_node->recv_list);
-		spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+		if (cm_node->recv_entry) {
+			WARN_ON(1);
+			return -EINVAL;
+		}
+		cm_node->recv_entry = new_send;
 	}
 
 	if (type == NES_TIMER_TYPE_SEND) {
@@ -435,24 +468,78 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
 	return ret;
 }
 
+static void nes_retrans_expired(struct nes_cm_node *cm_node)
+{
+	switch (cm_node->state) {
+	case NES_CM_STATE_SYN_RCVD:
+	case NES_CM_STATE_CLOSING:
+		rem_ref_cm_node(cm_node->cm_core, cm_node);
+		break;
+	case NES_CM_STATE_LAST_ACK:
+	case NES_CM_STATE_FIN_WAIT1:
+	case NES_CM_STATE_MPAREJ_RCVD:
+		send_reset(cm_node, NULL);
+		break;
+	default:
+		create_event(cm_node, NES_CM_EVENT_ABORTED);
+	}
+}
+
+static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node)
+{
+	struct nes_timer_entry *recv_entry = cm_node->recv_entry;
+	struct iw_cm_id *cm_id = cm_node->cm_id;
+	struct nes_qp *nesqp;
+	unsigned long qplockflags;
+
+	if (!recv_entry)
+		return;
+	nesqp = (struct nes_qp *)recv_entry->skb;
+	if (nesqp) {
+		spin_lock_irqsave(&nesqp->lock, qplockflags);
+		if (nesqp->cm_id) {
+			nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
+				"refcount = %d: HIT A "
+				"NES_TIMER_TYPE_CLOSE with something "
+				"to do!!!\n", nesqp->hwqp.qp_id, cm_id,
+				atomic_read(&nesqp->refcount));
+			nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+			nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+			nesqp->ibqp_state = IB_QPS_ERR;
+			spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+			nes_cm_disconn(nesqp);
+		} else {
+			spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+			nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
+				"refcount = %d: HIT A "
+				"NES_TIMER_TYPE_CLOSE with nothing "
+				"to do!!!\n", nesqp->hwqp.qp_id, cm_id,
+				atomic_read(&nesqp->refcount));
+		}
+	} else if (rem_node) {
+		/* TIME_WAIT state */
+		rem_ref_cm_node(cm_node->cm_core, cm_node);
+	}
+	if (cm_node->cm_id)
+		cm_id->rem_ref(cm_id);
+	kfree(recv_entry);
+	cm_node->recv_entry = NULL;
+}
 
 /**
  * nes_cm_timer_tick
  */
 static void nes_cm_timer_tick(unsigned long pass)
 {
-	unsigned long flags, qplockflags;
+	unsigned long flags;
 	unsigned long nexttimeout = jiffies + NES_LONG_TIME;
-	struct iw_cm_id *cm_id;
 	struct nes_cm_node *cm_node;
 	struct nes_timer_entry *send_entry, *recv_entry;
-	struct list_head *list_core, *list_core_temp;
-	struct list_head *list_node, *list_node_temp;
+	struct list_head *list_core_temp;
+	struct list_head *list_node;
 	struct nes_cm_core *cm_core = g_cm_core;
-	struct nes_qp *nesqp;
 	u32 settimer = 0;
 	int ret = NETDEV_TX_OK;
-	enum nes_cm_node_state last_state;
 
 	struct list_head timer_list;
 	INIT_LIST_HEAD(&timer_list);
@@ -461,7 +548,7 @@ static void nes_cm_timer_tick(unsigned long pass)
 	list_for_each_safe(list_node, list_core_temp,
 				&cm_core->connected_nodes) {
 		cm_node = container_of(list_node, struct nes_cm_node, list);
-		if (!list_empty(&cm_node->recv_list) || (cm_node->send_entry)) {
+		if ((cm_node->recv_entry) || (cm_node->send_entry)) {
 			add_ref_cm_node(cm_node);
 			list_add(&cm_node->timer_entry, &timer_list);
 		}
@@ -471,54 +558,18 @@ static void nes_cm_timer_tick(unsigned long pass)
 	list_for_each_safe(list_node, list_core_temp, &timer_list) {
 		cm_node = container_of(list_node, struct nes_cm_node,
 					timer_entry);
-		spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-		list_for_each_safe(list_core, list_node_temp,
-			&cm_node->recv_list) {
-			recv_entry = container_of(list_core,
-				struct nes_timer_entry, list);
-			if (!recv_entry)
-				break;
+		recv_entry = cm_node->recv_entry;
+
+		if (recv_entry) {
 			if (time_after(recv_entry->timetosend, jiffies)) {
 				if (nexttimeout > recv_entry->timetosend ||
-					!settimer) {
+						!settimer) {
 					nexttimeout = recv_entry->timetosend;
 					settimer = 1;
 				}
-				continue;
-			}
-			list_del(&recv_entry->list);
-			cm_id = cm_node->cm_id;
-			spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-			nesqp = (struct nes_qp *)recv_entry->skb;
-			spin_lock_irqsave(&nesqp->lock, qplockflags);
-			if (nesqp->cm_id) {
-				nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
-					"refcount = %d: HIT A "
-					"NES_TIMER_TYPE_CLOSE with something "
-					"to do!!!\n", nesqp->hwqp.qp_id, cm_id,
-					atomic_read(&nesqp->refcount));
-				nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
-				nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
-				nesqp->ibqp_state = IB_QPS_ERR;
-				spin_unlock_irqrestore(&nesqp->lock,
-					qplockflags);
-				nes_cm_disconn(nesqp);
-			} else {
-				spin_unlock_irqrestore(&nesqp->lock,
-					qplockflags);
-				nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
-					"refcount = %d: HIT A "
-					"NES_TIMER_TYPE_CLOSE with nothing "
-					"to do!!!\n", nesqp->hwqp.qp_id, cm_id,
-					atomic_read(&nesqp->refcount));
-			}
-			if (cm_id)
-				cm_id->rem_ref(cm_id);
-
-			kfree(recv_entry);
-			spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+			} else
+				handle_recv_entry(cm_node, 1);
 		}
-		spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
 
 		spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
 		do {
@@ -533,12 +584,11 @@ static void nes_cm_timer_tick(unsigned long pass)
 						nexttimeout =
 							send_entry->timetosend;
 						settimer = 1;
-						break;
 					}
 				} else {
 					free_retrans_entry(cm_node);
-					break;
 				}
+				break;
 			}
 
 			if ((cm_node->state == NES_CM_STATE_TSA) ||
@@ -550,16 +600,12 @@ static void nes_cm_timer_tick(unsigned long pass)
 			if (!send_entry->retranscount ||
 				!send_entry->retrycount) {
 				cm_packets_dropped++;
-				last_state = cm_node->state;
-				cm_node->state = NES_CM_STATE_CLOSED;
 				free_retrans_entry(cm_node);
+
 				spin_unlock_irqrestore(
 					&cm_node->retrans_list_lock, flags);
-				if (last_state == NES_CM_STATE_SYN_RCVD)
-					rem_ref_cm_node(cm_core, cm_node);
-				else
-					create_event(cm_node,
-						NES_CM_EVENT_ABORTED);
+				nes_retrans_expired(cm_node);
+				cm_node->state = NES_CM_STATE_CLOSED;
 				spin_lock_irqsave(&cm_node->retrans_list_lock,
 					flags);
 				break;
@@ -714,7 +760,7 @@ static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)
 		skb = dev_alloc_skb(MAX_CM_BUFFER);
 	if (!skb) {
 		nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
-		return -1;
+		return -ENOMEM;
 	}
 
 	form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
@@ -871,7 +917,8 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
 static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
 	struct nes_cm_listener *listener, int free_hanging_nodes)
 {
-	int ret = 1;
+	int ret = -EINVAL;
+	int err = 0;
 	unsigned long flags;
 	struct list_head *list_pos = NULL;
 	struct list_head *list_temp = NULL;
@@ -900,10 +947,60 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
 
 	list_for_each_safe(list_pos, list_temp, &reset_list) {
 		cm_node = container_of(list_pos, struct nes_cm_node,
-					reset_entry);
-		cleanup_retrans_entry(cm_node);
-		send_reset(cm_node, NULL);
-		rem_ref_cm_node(cm_node->cm_core, cm_node);
+				reset_entry);
+		{
+			struct nes_cm_node *loopback = cm_node->loopbackpartner;
+			if (NES_CM_STATE_FIN_WAIT1 <= cm_node->state) {
+				rem_ref_cm_node(cm_node->cm_core, cm_node);
+			} else {
+				if (!loopback) {
+					cleanup_retrans_entry(cm_node);
+					err = send_reset(cm_node, NULL);
+					if (err) {
+						cm_node->state =
+							 NES_CM_STATE_CLOSED;
+						WARN_ON(1);
+					} else {
+						cm_node->state =
+							NES_CM_STATE_CLOSED;
+						rem_ref_cm_node(
+							cm_node->cm_core,
+							cm_node);
+					}
+				} else {
+					struct nes_cm_event event;
+
+					event.cm_node = loopback;
+					event.cm_info.rem_addr =
+							loopback->rem_addr;
+					event.cm_info.loc_addr =
+							loopback->loc_addr;
+					event.cm_info.rem_port =
+							loopback->rem_port;
+					event.cm_info.loc_port =
+							 loopback->loc_port;
+					event.cm_info.cm_id = loopback->cm_id;
+					cm_event_connect_error(&event);
+					loopback->state = NES_CM_STATE_CLOSED;
+
+					event.cm_node = cm_node;
+					event.cm_info.rem_addr =
+							 cm_node->rem_addr;
+					event.cm_info.loc_addr =
+							 cm_node->loc_addr;
+					event.cm_info.rem_port =
+							 cm_node->rem_port;
+					event.cm_info.loc_port =
+							 cm_node->loc_port;
+					event.cm_info.cm_id = cm_node->cm_id;
+					cm_event_reset(&event);
+
+					rem_ref_cm_node(cm_node->cm_core,
+							 cm_node);
+
+				}
+			}
+		}
 	}
 
 	spin_lock_irqsave(&cm_core->listen_list_lock, flags);
@@ -964,6 +1061,7 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
 	if (cm_node->accept_pend) {
 		BUG_ON(!cm_node->listener);
 		atomic_dec(&cm_node->listener->pend_accepts_cnt);
+		cm_node->accept_pend = 0;
 		BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
 	}
 
@@ -990,7 +1088,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip)
 	memset(&fl, 0, sizeof fl);
 	fl.nl_u.ip4_u.daddr = htonl(dst_ip);
 	if (ip_route_output_key(&init_net, &rt, &fl)) {
-		printk("%s: ip_route_output_key failed for 0x%08X\n",
+		printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n",
 				__func__, dst_ip);
 		return rc;
 	}
@@ -1053,8 +1151,6 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
 			cm_node->cm_id);
 
 	spin_lock_init(&cm_node->retrans_list_lock);
-	INIT_LIST_HEAD(&cm_node->recv_list);
-	spin_lock_init(&cm_node->recv_list_lock);
 
 	cm_node->loopbackpartner = NULL;
 	atomic_set(&cm_node->ref_count, 1);
@@ -1122,10 +1218,7 @@ static int add_ref_cm_node(struct nes_cm_node *cm_node)
 static int rem_ref_cm_node(struct nes_cm_core *cm_core,
 	struct nes_cm_node *cm_node)
 {
-	unsigned long flags, qplockflags;
-	struct nes_timer_entry *recv_entry;
-	struct iw_cm_id *cm_id;
-	struct list_head *list_core, *list_node_temp;
+	unsigned long flags;
 	struct nes_qp *nesqp;
 
 	if (!cm_node)
@@ -1146,38 +1239,9 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
 		atomic_dec(&cm_node->listener->pend_accepts_cnt);
 		BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
 	}
-	BUG_ON(cm_node->send_entry);
-	spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-	list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
-		recv_entry = container_of(list_core, struct nes_timer_entry,
-				list);
-		list_del(&recv_entry->list);
-		cm_id = cm_node->cm_id;
-		spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-		nesqp = (struct nes_qp *)recv_entry->skb;
-		spin_lock_irqsave(&nesqp->lock, qplockflags);
-		if (nesqp->cm_id) {
-			nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A "
-				"NES_TIMER_TYPE_CLOSE with something to do!\n",
-				nesqp->hwqp.qp_id, cm_id);
-			nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
-			nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
-			nesqp->ibqp_state = IB_QPS_ERR;
-			spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-			nes_cm_disconn(nesqp);
-		} else {
-			spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-			nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A "
-				"NES_TIMER_TYPE_CLOSE with nothing to do!\n",
-				nesqp->hwqp.qp_id, cm_id);
-		}
-		cm_id->rem_ref(cm_id);
-
-		kfree(recv_entry);
-		spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-	}
-	spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-
+	WARN_ON(cm_node->send_entry);
+	if (cm_node->recv_entry)
+		handle_recv_entry(cm_node, 0);
 	if (cm_node->listener) {
 		mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
 	} else {
@@ -1262,8 +1326,7 @@ static void drop_packet(struct sk_buff *skb)
 	dev_kfree_skb_any(skb);
 }
 
-static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
-	struct tcphdr *tcph)
+static void handle_fin_pkt(struct nes_cm_node *cm_node)
 {
 	nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
 		"refcnt=%d\n", cm_node, cm_node->state,
@@ -1275,23 +1338,30 @@ static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 	case NES_CM_STATE_SYN_SENT:
 	case NES_CM_STATE_ESTABLISHED:
 	case NES_CM_STATE_MPAREQ_SENT:
+	case NES_CM_STATE_MPAREJ_RCVD:
 		cm_node->state = NES_CM_STATE_LAST_ACK;
-		send_fin(cm_node, skb);
+		send_fin(cm_node, NULL);
 		break;
 	case NES_CM_STATE_FIN_WAIT1:
 		cm_node->state = NES_CM_STATE_CLOSING;
-		send_ack(cm_node, skb);
+		send_ack(cm_node, NULL);
+		/* Wait for ACK as this is simultanous close..
+		* After we receive ACK, do not send anything..
+		* Just rm the node.. Done.. */
 		break;
 	case NES_CM_STATE_FIN_WAIT2:
 		cm_node->state = NES_CM_STATE_TIME_WAIT;
-		send_ack(cm_node, skb);
+		send_ack(cm_node, NULL);
+		schedule_nes_timer(cm_node, NULL,  NES_TIMER_TYPE_CLOSE, 1, 0);
+		break;
+	case NES_CM_STATE_TIME_WAIT:
 		cm_node->state = NES_CM_STATE_CLOSED;
+		rem_ref_cm_node(cm_node->cm_core, cm_node);
 		break;
 	case NES_CM_STATE_TSA:
 	default:
 		nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n",
 			cm_node, cm_node->state);
-		drop_packet(skb);
 		break;
 	}
 }
@@ -1337,23 +1407,35 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 		cleanup_retrans_entry(cm_node);
 		drop_packet(skb);
 		break;
+	case NES_CM_STATE_TIME_WAIT:
+		cleanup_retrans_entry(cm_node);
+		cm_node->state = NES_CM_STATE_CLOSED;
+		rem_ref_cm_node(cm_node->cm_core, cm_node);
+		drop_packet(skb);
+		break;
+	case NES_CM_STATE_FIN_WAIT1:
+		cleanup_retrans_entry(cm_node);
+		nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
 	default:
 		drop_packet(skb);
 		break;
 	}
 }
 
-static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
-	enum nes_cm_event_type type)
+
+static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
 
-	int	ret;
+	int	ret = 0;
 	int datasize = skb->len;
 	u8 *dataloc = skb->data;
-	ret = parse_mpa(cm_node, dataloc, datasize);
-	if (ret < 0) {
+
+	enum nes_cm_event_type type = NES_CM_EVENT_UNKNOWN;
+	u32     res_type;
+	ret = parse_mpa(cm_node, dataloc, &res_type, datasize);
+	if (ret) {
 		nes_debug(NES_DBG_CM, "didn't like MPA Request\n");
-		if (type == NES_CM_EVENT_CONNECTED) {
+		if (cm_node->state == NES_CM_STATE_MPAREQ_SENT) {
 			nes_debug(NES_DBG_CM, "%s[%u] create abort for "
 				"cm_node=%p listener=%p state=%d\n", __func__,
 				__LINE__, cm_node, cm_node->listener,
@@ -1362,18 +1444,38 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
 		} else {
 			passive_open_err(cm_node, skb, 1);
 		}
-	} else {
-		cleanup_retrans_entry(cm_node);
-		dev_kfree_skb_any(skb);
-		if (type == NES_CM_EVENT_CONNECTED)
+		return;
+	}
+
+	switch (cm_node->state) {
+	case NES_CM_STATE_ESTABLISHED:
+		if (res_type == NES_MPA_REQUEST_REJECT) {
+			/*BIG problem as we are receiving the MPA.. So should
+			* not be REJECT.. This is Passive Open.. We can
+			* only receive it Reject for Active Open...*/
+			WARN_ON(1);
+		}
+		cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
+		type = NES_CM_EVENT_MPA_REQ;
+		atomic_set(&cm_node->passive_state,
+				NES_PASSIVE_STATE_INDICATED);
+		break;
+	case NES_CM_STATE_MPAREQ_SENT:
+		if (res_type == NES_MPA_REQUEST_REJECT) {
+			type = NES_CM_EVENT_MPA_REJECT;
+			cm_node->state = NES_CM_STATE_MPAREJ_RCVD;
+		} else {
+			type = NES_CM_EVENT_CONNECTED;
 			cm_node->state = NES_CM_STATE_TSA;
-		else
-			atomic_set(&cm_node->passive_state,
-					NES_PASSIVE_STATE_INDICATED);
-		create_event(cm_node, type);
+		}
 
+		break;
+	default:
+		WARN_ON(1);
+		break;
 	}
-	return ;
+	dev_kfree_skb_any(skb);
+	create_event(cm_node, type);
 }
 
 static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)
@@ -1461,8 +1563,6 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 		break;
 	case NES_CM_STATE_LISTENING:
 		/* Passive OPEN */
-		cm_node->accept_pend = 1;
-		atomic_inc(&cm_node->listener->pend_accepts_cnt);
 		if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
 				cm_node->listener->backlog) {
 			nes_debug(NES_DBG_CM, "drop syn due to backlog "
@@ -1480,6 +1580,9 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 		}
 		cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
 		BUG_ON(cm_node->send_entry);
+		cm_node->accept_pend = 1;
+		atomic_inc(&cm_node->listener->pend_accepts_cnt);
+
 		cm_node->state = NES_CM_STATE_SYN_RCVD;
 		send_syn(cm_node, 1, skb);
 		break;
@@ -1514,6 +1617,7 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 	inc_sequence = ntohl(tcph->seq);
 	switch (cm_node->state) {
 	case NES_CM_STATE_SYN_SENT:
+		cleanup_retrans_entry(cm_node);
 		/* active open */
 		if (check_syn(cm_node, tcph, skb))
 			return;
@@ -1563,10 +1667,7 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 	u32 rem_seq;
 	int ret;
 	int optionsize;
-	u32 temp_seq = cm_node->tcp_cntxt.loc_seq_num;
-
 	optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-	cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
 
 	if (check_seq(cm_node, tcph, skb))
 		return;
@@ -1576,7 +1677,7 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 	rem_seq = ntohl(tcph->seq);
 	rem_seq_ack =  ntohl(tcph->ack_seq);
 	datasize = skb->len;
-
+	cleanup_retrans_entry(cm_node);
 	switch (cm_node->state) {
 	case NES_CM_STATE_SYN_RCVD:
 		/* Passive OPEN */
@@ -1584,7 +1685,6 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 		if (ret)
 			break;
 		cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
-		cm_node->tcp_cntxt.loc_seq_num = temp_seq;
 		if (cm_node->tcp_cntxt.rem_ack_num !=
 		    cm_node->tcp_cntxt.loc_seq_num) {
 			nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n");
@@ -1593,31 +1693,30 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 			return;
 		}
 		cm_node->state = NES_CM_STATE_ESTABLISHED;
+		cleanup_retrans_entry(cm_node);
 		if (datasize) {
 			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
-			cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
-			handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_MPA_REQ);
-		 } else { /* rcvd ACK only */
+			handle_rcv_mpa(cm_node, skb);
+		} else { /* rcvd ACK only */
 			dev_kfree_skb_any(skb);
 			cleanup_retrans_entry(cm_node);
 		 }
 		break;
 	case NES_CM_STATE_ESTABLISHED:
 		/* Passive OPEN */
-		/* We expect mpa frame to be received only */
+		cleanup_retrans_entry(cm_node);
 		if (datasize) {
 			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
-			cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
-			handle_rcv_mpa(cm_node, skb,
-				NES_CM_EVENT_MPA_REQ);
+			handle_rcv_mpa(cm_node, skb);
 		} else
 			drop_packet(skb);
 		break;
 	case NES_CM_STATE_MPAREQ_SENT:
+		cleanup_retrans_entry(cm_node);
 		cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
 		if (datasize) {
 			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
-			handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_CONNECTED);
+			handle_rcv_mpa(cm_node, skb);
 		} else { /* Could be just an ack pkt.. */
 			cleanup_retrans_entry(cm_node);
 			dev_kfree_skb_any(skb);
@@ -1628,13 +1727,24 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 		cleanup_retrans_entry(cm_node);
 		send_reset(cm_node, skb);
 		break;
+	case NES_CM_STATE_LAST_ACK:
+		cleanup_retrans_entry(cm_node);
+		cm_node->state = NES_CM_STATE_CLOSED;
+		cm_node->cm_id->rem_ref(cm_node->cm_id);
+	case NES_CM_STATE_CLOSING:
+		cleanup_retrans_entry(cm_node);
+		rem_ref_cm_node(cm_node->cm_core, cm_node);
+		drop_packet(skb);
+		break;
 	case NES_CM_STATE_FIN_WAIT1:
+		cleanup_retrans_entry(cm_node);
+		drop_packet(skb);
+		cm_node->state = NES_CM_STATE_FIN_WAIT2;
+		break;
 	case NES_CM_STATE_SYN_SENT:
 	case NES_CM_STATE_FIN_WAIT2:
 	case NES_CM_STATE_TSA:
 	case NES_CM_STATE_MPAREQ_RCVD:
-	case NES_CM_STATE_LAST_ACK:
-	case NES_CM_STATE_CLOSING:
 	case NES_CM_STATE_UNKNOWN:
 	default:
 		drop_packet(skb);
@@ -1744,6 +1854,7 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
 {
 	enum nes_tcpip_pkt_type	pkt_type = NES_PKT_TYPE_UNKNOWN;
 	struct tcphdr *tcph = tcp_hdr(skb);
+	u32     fin_set = 0;
 	skb_pull(skb, ip_hdr(skb)->ihl << 2);
 
 	nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
@@ -1756,10 +1867,10 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
 		pkt_type = NES_PKT_TYPE_SYN;
 		if (tcph->ack)
 			pkt_type = NES_PKT_TYPE_SYNACK;
-	} else if (tcph->fin)
-		pkt_type = NES_PKT_TYPE_FIN;
-	else if (tcph->ack)
+	} else if (tcph->ack)
 		pkt_type = NES_PKT_TYPE_ACK;
+	if (tcph->fin)
+		fin_set = 1;
 
 	switch (pkt_type) {
 	case NES_PKT_TYPE_SYN:
@@ -1770,15 +1881,16 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
 		break;
 	case NES_PKT_TYPE_ACK:
 		handle_ack_pkt(cm_node, skb, tcph);
+		if (fin_set)
+			handle_fin_pkt(cm_node);
 		break;
 	case NES_PKT_TYPE_RST:
 		handle_rst_pkt(cm_node, skb, tcph);
 		break;
-	case NES_PKT_TYPE_FIN:
-		handle_fin_pkt(cm_node, skb, tcph);
-		break;
 	default:
 		drop_packet(skb);
+		if (fin_set)
+			handle_fin_pkt(cm_node);
 		break;
 	}
 }
@@ -1921,7 +2033,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
 				loopbackremotenode->tcp_cntxt.rcv_wscale;
 			loopbackremotenode->tcp_cntxt.snd_wscale =
 				cm_node->tcp_cntxt.rcv_wscale;
-
+			loopbackremotenode->state = NES_CM_STATE_MPAREQ_RCVD;
 			create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
 		}
 		return cm_node;
@@ -1976,7 +2088,11 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
 	struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
 {
 	int ret = 0;
+	int err = 0;
 	int passive_state;
+	struct nes_cm_event event;
+	struct iw_cm_id *cm_id = cm_node->cm_id;
+	struct nes_cm_node *loopback = cm_node->loopbackpartner;
 
 	nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n",
 		__func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);
@@ -1985,12 +2101,38 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
 		return ret;
 	cleanup_retrans_entry(cm_node);
 
-	passive_state = atomic_add_return(1, &cm_node->passive_state);
-	cm_node->state = NES_CM_STATE_CLOSED;
-	if (passive_state == NES_SEND_RESET_EVENT)
+	if (!loopback) {
+		passive_state = atomic_add_return(1, &cm_node->passive_state);
+		if (passive_state == NES_SEND_RESET_EVENT) {
+			cm_node->state = NES_CM_STATE_CLOSED;
+			rem_ref_cm_node(cm_core, cm_node);
+		} else {
+			ret = send_mpa_reject(cm_node);
+			if (ret) {
+				cm_node->state = NES_CM_STATE_CLOSED;
+				err = send_reset(cm_node, NULL);
+				if (err)
+					WARN_ON(1);
+			} else
+				cm_id->add_ref(cm_id);
+		}
+	} else {
+		cm_node->cm_id = NULL;
+		event.cm_node = loopback;
+		event.cm_info.rem_addr = loopback->rem_addr;
+		event.cm_info.loc_addr = loopback->loc_addr;
+		event.cm_info.rem_port = loopback->rem_port;
+		event.cm_info.loc_port = loopback->loc_port;
+		event.cm_info.cm_id = loopback->cm_id;
+		cm_event_mpa_reject(&event);
 		rem_ref_cm_node(cm_core, cm_node);
-	else
-		ret = send_reset(cm_node, NULL);
+		loopback->state = NES_CM_STATE_CLOSING;
+
+		cm_id = loopback->cm_id;
+		rem_ref_cm_node(cm_core, loopback);
+		cm_id->rem_ref(cm_id);
+	}
+
 	return ret;
 }
 
@@ -2027,6 +2169,7 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
 	case NES_CM_STATE_CLOSING:
 		ret = -1;
 		break;
+	case NES_CM_STATE_MPAREJ_RCVD:
 	case NES_CM_STATE_LISTENING:
 	case NES_CM_STATE_UNKNOWN:
 	case NES_CM_STATE_INITED:
@@ -2223,15 +2366,15 @@ static int mini_cm_set(struct nes_cm_core *cm_core, u32 type, u32 value)
 	int ret = 0;
 
 	switch (type) {
-		case NES_CM_SET_PKT_SIZE:
-			cm_core->mtu = value;
-			break;
-		case NES_CM_SET_FREE_PKT_Q_SIZE:
-			cm_core->free_tx_pkt_max = value;
-			break;
-		default:
-			/* unknown set option */
-			ret = -EINVAL;
+	case NES_CM_SET_PKT_SIZE:
+		cm_core->mtu = value;
+		break;
+	case NES_CM_SET_FREE_PKT_Q_SIZE:
+		cm_core->free_tx_pkt_max = value;
+		break;
+	default:
+		/* unknown set option */
+		ret = -EINVAL;
 	}
 
 	return ret;
@@ -2650,9 +2793,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 			NES_QPCONTEXT_ORDIRD_WRPDU);
 	} else {
 		nesqp->nesqp_context->ird_ord_sizes |=
-			cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
-			NES_QPCONTEXT_ORDIRD_WRPDU |
-			NES_QPCONTEXT_ORDIRD_ALSMM));
+			cpu_to_le32(NES_QPCONTEXT_ORDIRD_WRPDU);
 	}
 	nesqp->skip_lsmm = 1;
 
@@ -2774,23 +2915,35 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
 {
 	struct nes_cm_node *cm_node;
+	struct nes_cm_node *loopback;
+
 	struct nes_cm_core *cm_core;
 
 	atomic_inc(&cm_rejects);
 	cm_node = (struct nes_cm_node *) cm_id->provider_data;
+	loopback = cm_node->loopbackpartner;
 	cm_core = cm_node->cm_core;
+	cm_node->cm_id = cm_id;
 	cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;
 
+	if (cm_node->mpa_frame_size > MAX_CM_BUFFER)
+		return -EINVAL;
+
 	strcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP);
-	memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+	if (loopback) {
+		memcpy(&loopback->mpa_frame.priv_data, pdata, pdata_len);
+		loopback->mpa_frame.priv_data_len = pdata_len;
+		loopback->mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+				pdata_len;
+	} else {
+		memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+		cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);
+	}
 
-	cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);
 	cm_node->mpa_frame.rev = mpa_version;
 	cm_node->mpa_frame.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT;
 
-	cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);
-
-	return 0;
+	return cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);
 }
 
 
@@ -3299,13 +3452,56 @@ static void cm_event_mpa_req(struct nes_cm_event *event)
 	cm_event.remote_addr.sin_family = AF_INET;
 	cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
 	cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);
+	cm_event.private_data = cm_node->mpa_frame_buf;
+	cm_event.private_data_len  = (u8) cm_node->mpa_frame_size;
+
+	ret = cm_id->event_handler(cm_id, &cm_event);
+	if (ret)
+		printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",
+				__func__, __LINE__, ret);
+	return;
+}
+
+
+static void cm_event_mpa_reject(struct nes_cm_event *event)
+{
+	struct iw_cm_id   *cm_id;
+	struct iw_cm_event cm_event;
+	struct nes_cm_node *cm_node;
+	int ret;
+
+	cm_node = event->cm_node;
+	if (!cm_node)
+		return;
+	cm_id = cm_node->cm_id;
+
+	atomic_inc(&cm_connect_reqs);
+	nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",
+			cm_node, cm_id, jiffies);
+
+	cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+	cm_event.status = -ECONNREFUSED;
+	cm_event.provider_data = cm_id->provider_data;
+
+	cm_event.local_addr.sin_family = AF_INET;
+	cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);
+	cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr);
+
+	cm_event.remote_addr.sin_family = AF_INET;
+	cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
+	cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);
 
-		cm_event.private_data                = cm_node->mpa_frame_buf;
-		cm_event.private_data_len            = (u8) cm_node->mpa_frame_size;
+	cm_event.private_data = cm_node->mpa_frame_buf;
+	cm_event.private_data_len = (u8) cm_node->mpa_frame_size;
+
+	nes_debug(NES_DBG_CM, "call CM_EVENT_MPA_REJECTED, local_addr=%08x, "
+			"remove_addr=%08x\n",
+			cm_event.local_addr.sin_addr.s_addr,
+			cm_event.remote_addr.sin_addr.s_addr);
 
 	ret = cm_id->event_handler(cm_id, &cm_event);
 	if (ret)
-		printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+		printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",
 				__func__, __LINE__, ret);
 
 	return;
@@ -3370,6 +3566,14 @@ static void nes_cm_event_handler(struct work_struct *work)
 		cm_event_connected(event);
 		nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
 		break;
+	case NES_CM_EVENT_MPA_REJECT:
+		if ((!event->cm_node->cm_id) ||
+				(event->cm_node->state == NES_CM_STATE_TSA))
+			break;
+		cm_event_mpa_reject(event);
+		nes_debug(NES_DBG_CM, "CM Event: REJECT\n");
+		break;
+
 	case NES_CM_EVENT_ABORTED:
 		if ((!event->cm_node->cm_id) ||
 			(event->cm_node->state == NES_CM_STATE_TSA))
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
index 4ab2beb..d5f7782 100644
--- a/drivers/infiniband/hw/nes/nes_cm.h
+++ b/drivers/infiniband/hw/nes/nes_cm.h
@@ -39,6 +39,9 @@
 #define NES_MANAGE_APBVT_DEL 0
 #define NES_MANAGE_APBVT_ADD 1
 
+#define NES_MPA_REQUEST_ACCEPT  1
+#define NES_MPA_REQUEST_REJECT  2
+
 /* IETF MPA -- defines, enums, structs */
 #define IEFT_MPA_KEY_REQ  "MPA ID Req Frame"
 #define IEFT_MPA_KEY_REP  "MPA ID Rep Frame"
@@ -186,6 +189,7 @@ enum nes_cm_node_state {
 	NES_CM_STATE_ACCEPTING,
 	NES_CM_STATE_MPAREQ_SENT,
 	NES_CM_STATE_MPAREQ_RCVD,
+	NES_CM_STATE_MPAREJ_RCVD,
 	NES_CM_STATE_TSA,
 	NES_CM_STATE_FIN_WAIT1,
 	NES_CM_STATE_FIN_WAIT2,
@@ -278,13 +282,12 @@ struct nes_cm_node {
 	struct nes_timer_entry	*send_entry;
 
 	spinlock_t                retrans_list_lock;
-	struct list_head          recv_list;
-	spinlock_t                recv_list_lock;
+	struct nes_timer_entry  *recv_entry;
 
 	int                       send_write0;
 	union {
 		struct ietf_mpa_frame mpa_frame;
-		u8                    mpa_frame_buf[NES_CM_DEFAULT_MTU];
+		u8                    mpa_frame_buf[MAX_CM_BUFFER];
 	};
 	u16                       mpa_frame_size;
 	struct iw_cm_id           *cm_id;
@@ -326,6 +329,7 @@ enum  nes_cm_event_type {
 	NES_CM_EVENT_MPA_REQ,
 	NES_CM_EVENT_MPA_CONNECT,
 	NES_CM_EVENT_MPA_ACCEPT,
+	NES_CM_EVENT_MPA_REJECT,
 	NES_CM_EVENT_MPA_ESTABLISHED,
 	NES_CM_EVENT_CONNECTED,
 	NES_CM_EVENT_CLOSED,
-- 
1.5.3.3




More information about the general mailing list