|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
|
|
|
|
|
|
+ * Copyright (c) 2006 - 2009 Intel-NE, Inc. All rights reserved.
|
|
*
|
|
*
|
|
* This software is available to you under a choice of one of two
|
|
* This software is available to you under a choice of one of two
|
|
* licenses. You may choose to be licensed under the terms of the GNU
|
|
* licenses. You may choose to be licensed under the terms of the GNU
|
|
@@ -103,6 +103,7 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt);
|
|
static void nes_disconnect_worker(struct work_struct *work);
|
|
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_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_syn(struct nes_cm_node *, u32, struct sk_buff *);
|
|
static int send_reset(struct nes_cm_node *, 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);
|
|
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 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 passive_open_err(struct nes_cm_node *, struct sk_buff *, int);
|
|
static void cleanup_retrans_entry(struct nes_cm_node *);
|
|
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 void free_retrans_entry(struct nes_cm_node *cm_node);
|
|
static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
|
|
static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
|
|
struct sk_buff *skb, int optionsize, int passive);
|
|
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_connect_error(struct nes_cm_event *);
|
|
static void cm_event_reset(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_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);
|
|
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)
|
|
static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
|
|
{
|
|
{
|
|
- int ret;
|
|
|
|
if (!skb) {
|
|
if (!skb) {
|
|
nes_debug(NES_DBG_CM, "skb set to NULL\n");
|
|
nes_debug(NES_DBG_CM, "skb set to NULL\n");
|
|
return -1;
|
|
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,
|
|
form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
|
|
cm_node->mpa_frame_size, SET_ACK);
|
|
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
|
|
* recv_mpa - process a received TCP pkt, we are expecting an
|
|
* IETF MPA frame
|
|
* 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;
|
|
struct ietf_mpa_frame *mpa_frame;
|
|
|
|
|
|
|
|
+ *type = NES_MPA_REQUEST_ACCEPT;
|
|
|
|
+
|
|
/* assume req frame is in tcp data payload */
|
|
/* assume req frame is in tcp data payload */
|
|
if (len < sizeof(struct ietf_mpa_frame)) {
|
|
if (len < sizeof(struct ietf_mpa_frame)) {
|
|
nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);
|
|
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;
|
|
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) {
|
|
if (cm_node->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {
|
|
nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
|
|
nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
|
|
" complete (%x + %x != %x)\n",
|
|
" 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 */
|
|
/* copy entire MPA frame to our cm_node's frame */
|
|
memcpy(cm_node->mpa_frame_buf, buffer + sizeof(struct ietf_mpa_frame),
|
|
memcpy(cm_node->mpa_frame_buf, buffer + sizeof(struct ietf_mpa_frame),
|
|
cm_node->mpa_frame_size);
|
|
cm_node->mpa_frame_size);
|
|
|
|
|
|
|
|
+ if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)
|
|
|
|
+ *type = NES_MPA_REQUEST_REJECT;
|
|
return 0;
|
|
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);
|
|
new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
|
|
if (!new_send)
|
|
if (!new_send)
|
|
- return -1;
|
|
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
/* new_send->timetosend = currenttime */
|
|
/* new_send->timetosend = currenttime */
|
|
new_send->retrycount = NES_DEFAULT_RETRYS;
|
|
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) {
|
|
if (type == NES_TIMER_TYPE_CLOSE) {
|
|
new_send->timetosend += (HZ/10);
|
|
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) {
|
|
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;
|
|
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
|
|
* nes_cm_timer_tick
|
|
*/
|
|
*/
|
|
static void nes_cm_timer_tick(unsigned long pass)
|
|
static void nes_cm_timer_tick(unsigned long pass)
|
|
{
|
|
{
|
|
- unsigned long flags, qplockflags;
|
|
|
|
|
|
+ unsigned long flags;
|
|
unsigned long nexttimeout = jiffies + NES_LONG_TIME;
|
|
unsigned long nexttimeout = jiffies + NES_LONG_TIME;
|
|
- struct iw_cm_id *cm_id;
|
|
|
|
struct nes_cm_node *cm_node;
|
|
struct nes_cm_node *cm_node;
|
|
struct nes_timer_entry *send_entry, *recv_entry;
|
|
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_cm_core *cm_core = g_cm_core;
|
|
- struct nes_qp *nesqp;
|
|
|
|
u32 settimer = 0;
|
|
u32 settimer = 0;
|
|
int ret = NETDEV_TX_OK;
|
|
int ret = NETDEV_TX_OK;
|
|
- enum nes_cm_node_state last_state;
|
|
|
|
|
|
|
|
struct list_head timer_list;
|
|
struct list_head timer_list;
|
|
INIT_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,
|
|
list_for_each_safe(list_node, list_core_temp,
|
|
&cm_core->connected_nodes) {
|
|
&cm_core->connected_nodes) {
|
|
cm_node = container_of(list_node, struct nes_cm_node, list);
|
|
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);
|
|
add_ref_cm_node(cm_node);
|
|
list_add(&cm_node->timer_entry, &timer_list);
|
|
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) {
|
|
list_for_each_safe(list_node, list_core_temp, &timer_list) {
|
|
cm_node = container_of(list_node, struct nes_cm_node,
|
|
cm_node = container_of(list_node, struct nes_cm_node,
|
|
timer_entry);
|
|
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 (time_after(recv_entry->timetosend, jiffies)) {
|
|
if (nexttimeout > recv_entry->timetosend ||
|
|
if (nexttimeout > recv_entry->timetosend ||
|
|
- !settimer) {
|
|
|
|
|
|
+ !settimer) {
|
|
nexttimeout = recv_entry->timetosend;
|
|
nexttimeout = recv_entry->timetosend;
|
|
settimer = 1;
|
|
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);
|
|
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
|
|
do {
|
|
do {
|
|
@@ -533,12 +584,11 @@ static void nes_cm_timer_tick(unsigned long pass)
|
|
nexttimeout =
|
|
nexttimeout =
|
|
send_entry->timetosend;
|
|
send_entry->timetosend;
|
|
settimer = 1;
|
|
settimer = 1;
|
|
- break;
|
|
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
free_retrans_entry(cm_node);
|
|
free_retrans_entry(cm_node);
|
|
- break;
|
|
|
|
}
|
|
}
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
|
|
if ((cm_node->state == NES_CM_STATE_TSA) ||
|
|
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 ||
|
|
if (!send_entry->retranscount ||
|
|
!send_entry->retrycount) {
|
|
!send_entry->retrycount) {
|
|
cm_packets_dropped++;
|
|
cm_packets_dropped++;
|
|
- last_state = cm_node->state;
|
|
|
|
- cm_node->state = NES_CM_STATE_CLOSED;
|
|
|
|
free_retrans_entry(cm_node);
|
|
free_retrans_entry(cm_node);
|
|
|
|
+
|
|
spin_unlock_irqrestore(
|
|
spin_unlock_irqrestore(
|
|
&cm_node->retrans_list_lock, flags);
|
|
&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,
|
|
spin_lock_irqsave(&cm_node->retrans_list_lock,
|
|
flags);
|
|
flags);
|
|
break;
|
|
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);
|
|
skb = dev_alloc_skb(MAX_CM_BUFFER);
|
|
if (!skb) {
|
|
if (!skb) {
|
|
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
|
|
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);
|
|
form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
|
|
@@ -778,14 +824,10 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
struct list_head *hte;
|
|
struct list_head *hte;
|
|
struct nes_cm_node *cm_node;
|
|
struct nes_cm_node *cm_node;
|
|
- __be32 tmp_addr = cpu_to_be32(loc_addr);
|
|
|
|
|
|
|
|
/* get a handle on the hte */
|
|
/* get a handle on the hte */
|
|
hte = &cm_core->connected_nodes;
|
|
hte = &cm_core->connected_nodes;
|
|
|
|
|
|
- nes_debug(NES_DBG_CM, "Searching for an owner node: %pI4:%x from core %p->%p\n",
|
|
|
|
- &tmp_addr, loc_port, cm_core, hte);
|
|
|
|
-
|
|
|
|
/* walk list and find cm_node associated with this session ID */
|
|
/* walk list and find cm_node associated with this session ID */
|
|
spin_lock_irqsave(&cm_core->ht_lock, flags);
|
|
spin_lock_irqsave(&cm_core->ht_lock, flags);
|
|
list_for_each_entry(cm_node, hte, list) {
|
|
list_for_each_entry(cm_node, hte, list) {
|
|
@@ -875,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,
|
|
static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
|
|
struct nes_cm_listener *listener, int free_hanging_nodes)
|
|
struct nes_cm_listener *listener, int free_hanging_nodes)
|
|
{
|
|
{
|
|
- int ret = 1;
|
|
|
|
|
|
+ int ret = -EINVAL;
|
|
|
|
+ int err = 0;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
struct list_head *list_pos = NULL;
|
|
struct list_head *list_pos = NULL;
|
|
struct list_head *list_temp = NULL;
|
|
struct list_head *list_temp = NULL;
|
|
@@ -904,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) {
|
|
list_for_each_safe(list_pos, list_temp, &reset_list) {
|
|
cm_node = container_of(list_pos, struct nes_cm_node,
|
|
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);
|
|
spin_lock_irqsave(&cm_core->listen_list_lock, flags);
|
|
@@ -968,6 +1061,7 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
|
|
if (cm_node->accept_pend) {
|
|
if (cm_node->accept_pend) {
|
|
BUG_ON(!cm_node->listener);
|
|
BUG_ON(!cm_node->listener);
|
|
atomic_dec(&cm_node->listener->pend_accepts_cnt);
|
|
atomic_dec(&cm_node->listener->pend_accepts_cnt);
|
|
|
|
+ cm_node->accept_pend = 0;
|
|
BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
|
|
BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -994,7 +1088,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip)
|
|
memset(&fl, 0, sizeof fl);
|
|
memset(&fl, 0, sizeof fl);
|
|
fl.nl_u.ip4_u.daddr = htonl(dst_ip);
|
|
fl.nl_u.ip4_u.daddr = htonl(dst_ip);
|
|
if (ip_route_output_key(&init_net, &rt, &fl)) {
|
|
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);
|
|
__func__, dst_ip);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
@@ -1057,8 +1151,6 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
|
|
cm_node->cm_id);
|
|
cm_node->cm_id);
|
|
|
|
|
|
spin_lock_init(&cm_node->retrans_list_lock);
|
|
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;
|
|
cm_node->loopbackpartner = NULL;
|
|
atomic_set(&cm_node->ref_count, 1);
|
|
atomic_set(&cm_node->ref_count, 1);
|
|
@@ -1126,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,
|
|
static int rem_ref_cm_node(struct nes_cm_core *cm_core,
|
|
struct nes_cm_node *cm_node)
|
|
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;
|
|
struct nes_qp *nesqp;
|
|
|
|
|
|
if (!cm_node)
|
|
if (!cm_node)
|
|
@@ -1150,38 +1239,9 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
|
|
atomic_dec(&cm_node->listener->pend_accepts_cnt);
|
|
atomic_dec(&cm_node->listener->pend_accepts_cnt);
|
|
BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
|
|
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) {
|
|
if (cm_node->listener) {
|
|
mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
|
|
mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
|
|
} else {
|
|
} else {
|
|
@@ -1266,8 +1326,7 @@ static void drop_packet(struct sk_buff *skb)
|
|
dev_kfree_skb_any(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. "
|
|
nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
|
|
"refcnt=%d\n", cm_node, cm_node->state,
|
|
"refcnt=%d\n", cm_node, cm_node->state,
|
|
@@ -1279,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_SYN_SENT:
|
|
case NES_CM_STATE_ESTABLISHED:
|
|
case NES_CM_STATE_ESTABLISHED:
|
|
case NES_CM_STATE_MPAREQ_SENT:
|
|
case NES_CM_STATE_MPAREQ_SENT:
|
|
|
|
+ case NES_CM_STATE_MPAREJ_RCVD:
|
|
cm_node->state = NES_CM_STATE_LAST_ACK;
|
|
cm_node->state = NES_CM_STATE_LAST_ACK;
|
|
- send_fin(cm_node, skb);
|
|
|
|
|
|
+ send_fin(cm_node, NULL);
|
|
break;
|
|
break;
|
|
case NES_CM_STATE_FIN_WAIT1:
|
|
case NES_CM_STATE_FIN_WAIT1:
|
|
cm_node->state = NES_CM_STATE_CLOSING;
|
|
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;
|
|
break;
|
|
case NES_CM_STATE_FIN_WAIT2:
|
|
case NES_CM_STATE_FIN_WAIT2:
|
|
cm_node->state = NES_CM_STATE_TIME_WAIT;
|
|
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;
|
|
cm_node->state = NES_CM_STATE_CLOSED;
|
|
|
|
+ rem_ref_cm_node(cm_node->cm_core, cm_node);
|
|
break;
|
|
break;
|
|
case NES_CM_STATE_TSA:
|
|
case NES_CM_STATE_TSA:
|
|
default:
|
|
default:
|
|
nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n",
|
|
nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n",
|
|
cm_node, cm_node->state);
|
|
cm_node, cm_node->state);
|
|
- drop_packet(skb);
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1341,23 +1407,35 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
cleanup_retrans_entry(cm_node);
|
|
cleanup_retrans_entry(cm_node);
|
|
drop_packet(skb);
|
|
drop_packet(skb);
|
|
break;
|
|
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:
|
|
default:
|
|
drop_packet(skb);
|
|
drop_packet(skb);
|
|
break;
|
|
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;
|
|
int datasize = skb->len;
|
|
u8 *dataloc = skb->data;
|
|
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");
|
|
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 "
|
|
nes_debug(NES_DBG_CM, "%s[%u] create abort for "
|
|
"cm_node=%p listener=%p state=%d\n", __func__,
|
|
"cm_node=%p listener=%p state=%d\n", __func__,
|
|
__LINE__, cm_node, cm_node->listener,
|
|
__LINE__, cm_node, cm_node->listener,
|
|
@@ -1366,18 +1444,38 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
} else {
|
|
} else {
|
|
passive_open_err(cm_node, skb, 1);
|
|
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;
|
|
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)
|
|
static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)
|
|
@@ -1465,8 +1563,6 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
break;
|
|
break;
|
|
case NES_CM_STATE_LISTENING:
|
|
case NES_CM_STATE_LISTENING:
|
|
/* Passive OPEN */
|
|
/* Passive OPEN */
|
|
- cm_node->accept_pend = 1;
|
|
|
|
- atomic_inc(&cm_node->listener->pend_accepts_cnt);
|
|
|
|
if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
|
|
if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
|
|
cm_node->listener->backlog) {
|
|
cm_node->listener->backlog) {
|
|
nes_debug(NES_DBG_CM, "drop syn due to backlog "
|
|
nes_debug(NES_DBG_CM, "drop syn due to backlog "
|
|
@@ -1484,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;
|
|
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
|
|
BUG_ON(cm_node->send_entry);
|
|
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;
|
|
cm_node->state = NES_CM_STATE_SYN_RCVD;
|
|
send_syn(cm_node, 1, skb);
|
|
send_syn(cm_node, 1, skb);
|
|
break;
|
|
break;
|
|
@@ -1518,6 +1617,7 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
inc_sequence = ntohl(tcph->seq);
|
|
inc_sequence = ntohl(tcph->seq);
|
|
switch (cm_node->state) {
|
|
switch (cm_node->state) {
|
|
case NES_CM_STATE_SYN_SENT:
|
|
case NES_CM_STATE_SYN_SENT:
|
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
/* active open */
|
|
/* active open */
|
|
if (check_syn(cm_node, tcph, skb))
|
|
if (check_syn(cm_node, tcph, skb))
|
|
return;
|
|
return;
|
|
@@ -1567,10 +1667,7 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
u32 rem_seq;
|
|
u32 rem_seq;
|
|
int ret;
|
|
int ret;
|
|
int optionsize;
|
|
int optionsize;
|
|
- u32 temp_seq = cm_node->tcp_cntxt.loc_seq_num;
|
|
|
|
-
|
|
|
|
optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
|
|
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))
|
|
if (check_seq(cm_node, tcph, skb))
|
|
return;
|
|
return;
|
|
@@ -1580,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 = ntohl(tcph->seq);
|
|
rem_seq_ack = ntohl(tcph->ack_seq);
|
|
rem_seq_ack = ntohl(tcph->ack_seq);
|
|
datasize = skb->len;
|
|
datasize = skb->len;
|
|
-
|
|
|
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
switch (cm_node->state) {
|
|
switch (cm_node->state) {
|
|
case NES_CM_STATE_SYN_RCVD:
|
|
case NES_CM_STATE_SYN_RCVD:
|
|
/* Passive OPEN */
|
|
/* Passive OPEN */
|
|
@@ -1588,7 +1685,6 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
if (ret)
|
|
if (ret)
|
|
break;
|
|
break;
|
|
cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
|
|
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 !=
|
|
if (cm_node->tcp_cntxt.rem_ack_num !=
|
|
cm_node->tcp_cntxt.loc_seq_num) {
|
|
cm_node->tcp_cntxt.loc_seq_num) {
|
|
nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n");
|
|
nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n");
|
|
@@ -1597,31 +1693,30 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
cm_node->state = NES_CM_STATE_ESTABLISHED;
|
|
cm_node->state = NES_CM_STATE_ESTABLISHED;
|
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
if (datasize) {
|
|
if (datasize) {
|
|
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 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);
|
|
dev_kfree_skb_any(skb);
|
|
cleanup_retrans_entry(cm_node);
|
|
cleanup_retrans_entry(cm_node);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case NES_CM_STATE_ESTABLISHED:
|
|
case NES_CM_STATE_ESTABLISHED:
|
|
/* Passive OPEN */
|
|
/* Passive OPEN */
|
|
- /* We expect mpa frame to be received only */
|
|
|
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
if (datasize) {
|
|
if (datasize) {
|
|
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 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
|
|
} else
|
|
drop_packet(skb);
|
|
drop_packet(skb);
|
|
break;
|
|
break;
|
|
case NES_CM_STATE_MPAREQ_SENT:
|
|
case NES_CM_STATE_MPAREQ_SENT:
|
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
|
|
cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
|
|
if (datasize) {
|
|
if (datasize) {
|
|
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 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.. */
|
|
} else { /* Could be just an ack pkt.. */
|
|
cleanup_retrans_entry(cm_node);
|
|
cleanup_retrans_entry(cm_node);
|
|
dev_kfree_skb_any(skb);
|
|
dev_kfree_skb_any(skb);
|
|
@@ -1632,13 +1727,24 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
cleanup_retrans_entry(cm_node);
|
|
cleanup_retrans_entry(cm_node);
|
|
send_reset(cm_node, skb);
|
|
send_reset(cm_node, skb);
|
|
break;
|
|
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:
|
|
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_SYN_SENT:
|
|
case NES_CM_STATE_FIN_WAIT2:
|
|
case NES_CM_STATE_FIN_WAIT2:
|
|
case NES_CM_STATE_TSA:
|
|
case NES_CM_STATE_TSA:
|
|
case NES_CM_STATE_MPAREQ_RCVD:
|
|
case NES_CM_STATE_MPAREQ_RCVD:
|
|
- case NES_CM_STATE_LAST_ACK:
|
|
|
|
- case NES_CM_STATE_CLOSING:
|
|
|
|
case NES_CM_STATE_UNKNOWN:
|
|
case NES_CM_STATE_UNKNOWN:
|
|
default:
|
|
default:
|
|
drop_packet(skb);
|
|
drop_packet(skb);
|
|
@@ -1748,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;
|
|
enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;
|
|
struct tcphdr *tcph = tcp_hdr(skb);
|
|
struct tcphdr *tcph = tcp_hdr(skb);
|
|
|
|
+ u32 fin_set = 0;
|
|
skb_pull(skb, ip_hdr(skb)->ihl << 2);
|
|
skb_pull(skb, ip_hdr(skb)->ihl << 2);
|
|
|
|
|
|
nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
|
|
nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
|
|
@@ -1760,10 +1867,10 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
pkt_type = NES_PKT_TYPE_SYN;
|
|
pkt_type = NES_PKT_TYPE_SYN;
|
|
if (tcph->ack)
|
|
if (tcph->ack)
|
|
pkt_type = NES_PKT_TYPE_SYNACK;
|
|
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;
|
|
pkt_type = NES_PKT_TYPE_ACK;
|
|
|
|
+ if (tcph->fin)
|
|
|
|
+ fin_set = 1;
|
|
|
|
|
|
switch (pkt_type) {
|
|
switch (pkt_type) {
|
|
case NES_PKT_TYPE_SYN:
|
|
case NES_PKT_TYPE_SYN:
|
|
@@ -1774,15 +1881,16 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
break;
|
|
break;
|
|
case NES_PKT_TYPE_ACK:
|
|
case NES_PKT_TYPE_ACK:
|
|
handle_ack_pkt(cm_node, skb, tcph);
|
|
handle_ack_pkt(cm_node, skb, tcph);
|
|
|
|
+ if (fin_set)
|
|
|
|
+ handle_fin_pkt(cm_node);
|
|
break;
|
|
break;
|
|
case NES_PKT_TYPE_RST:
|
|
case NES_PKT_TYPE_RST:
|
|
handle_rst_pkt(cm_node, skb, tcph);
|
|
handle_rst_pkt(cm_node, skb, tcph);
|
|
break;
|
|
break;
|
|
- case NES_PKT_TYPE_FIN:
|
|
|
|
- handle_fin_pkt(cm_node, skb, tcph);
|
|
|
|
- break;
|
|
|
|
default:
|
|
default:
|
|
drop_packet(skb);
|
|
drop_packet(skb);
|
|
|
|
+ if (fin_set)
|
|
|
|
+ handle_fin_pkt(cm_node);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1925,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.rcv_wscale;
|
|
loopbackremotenode->tcp_cntxt.snd_wscale =
|
|
loopbackremotenode->tcp_cntxt.snd_wscale =
|
|
cm_node->tcp_cntxt.rcv_wscale;
|
|
cm_node->tcp_cntxt.rcv_wscale;
|
|
-
|
|
|
|
|
|
+ loopbackremotenode->state = NES_CM_STATE_MPAREQ_RCVD;
|
|
create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
|
|
create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
|
|
}
|
|
}
|
|
return cm_node;
|
|
return cm_node;
|
|
@@ -1980,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)
|
|
struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
|
|
{
|
|
{
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
+ int err = 0;
|
|
int passive_state;
|
|
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",
|
|
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);
|
|
__func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);
|
|
@@ -1989,12 +2101,38 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
|
|
return ret;
|
|
return ret;
|
|
cleanup_retrans_entry(cm_node);
|
|
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);
|
|
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;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2031,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:
|
|
case NES_CM_STATE_CLOSING:
|
|
ret = -1;
|
|
ret = -1;
|
|
break;
|
|
break;
|
|
|
|
+ case NES_CM_STATE_MPAREJ_RCVD:
|
|
case NES_CM_STATE_LISTENING:
|
|
case NES_CM_STATE_LISTENING:
|
|
case NES_CM_STATE_UNKNOWN:
|
|
case NES_CM_STATE_UNKNOWN:
|
|
case NES_CM_STATE_INITED:
|
|
case NES_CM_STATE_INITED:
|
|
@@ -2227,15 +2366,15 @@ static int mini_cm_set(struct nes_cm_core *cm_core, u32 type, u32 value)
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
switch (type) {
|
|
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;
|
|
return ret;
|
|
@@ -2625,9 +2764,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|
NES_QPCONTEXT_ORDIRD_WRPDU);
|
|
NES_QPCONTEXT_ORDIRD_WRPDU);
|
|
} else {
|
|
} else {
|
|
nesqp->nesqp_context->ird_ord_sizes |=
|
|
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;
|
|
nesqp->skip_lsmm = 1;
|
|
|
|
|
|
@@ -2749,23 +2886,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)
|
|
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 *cm_node;
|
|
|
|
+ struct nes_cm_node *loopback;
|
|
|
|
+
|
|
struct nes_cm_core *cm_core;
|
|
struct nes_cm_core *cm_core;
|
|
|
|
|
|
atomic_inc(&cm_rejects);
|
|
atomic_inc(&cm_rejects);
|
|
cm_node = (struct nes_cm_node *) cm_id->provider_data;
|
|
cm_node = (struct nes_cm_node *) cm_id->provider_data;
|
|
|
|
+ loopback = cm_node->loopbackpartner;
|
|
cm_core = cm_node->cm_core;
|
|
cm_core = cm_node->cm_core;
|
|
|
|
+ cm_node->cm_id = cm_id;
|
|
cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;
|
|
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);
|
|
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.rev = mpa_version;
|
|
cm_node->mpa_frame.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT;
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -3271,16 +3420,59 @@ static void cm_event_mpa_req(struct nes_cm_event *event)
|
|
cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);
|
|
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.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;
|
|
|
|
+
|
|
|
|
+ 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_family = AF_INET;
|
|
cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
|
|
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.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);
|
|
ret = cm_id->event_handler(cm_id, &cm_event);
|
|
if (ret)
|
|
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);
|
|
__func__, __LINE__, ret);
|
|
|
|
|
|
return;
|
|
return;
|
|
@@ -3345,6 +3537,14 @@ static void nes_cm_event_handler(struct work_struct *work)
|
|
cm_event_connected(event);
|
|
cm_event_connected(event);
|
|
nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
|
|
nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
|
|
break;
|
|
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:
|
|
case NES_CM_EVENT_ABORTED:
|
|
if ((!event->cm_node->cm_id) ||
|
|
if ((!event->cm_node->cm_id) ||
|
|
(event->cm_node->state == NES_CM_STATE_TSA))
|
|
(event->cm_node->state == NES_CM_STATE_TSA))
|