|
@@ -86,15 +86,14 @@ static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *,
|
|
|
struct nes_cm_node *);
|
|
|
static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *,
|
|
|
struct nes_cm_node *);
|
|
|
-static void mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
|
|
|
+static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
|
|
|
struct sk_buff *);
|
|
|
static int mini_cm_dealloc_core(struct nes_cm_core *);
|
|
|
static int mini_cm_get(struct nes_cm_core *);
|
|
|
static int mini_cm_set(struct nes_cm_core *, u32, u32);
|
|
|
|
|
|
-static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
|
|
|
+static void form_cm_frame(struct sk_buff *, struct nes_cm_node *,
|
|
|
void *, u32, void *, u32, u8);
|
|
|
-static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node);
|
|
|
static int add_ref_cm_node(struct nes_cm_node *);
|
|
|
static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
|
|
|
|
|
@@ -251,7 +250,7 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
|
|
|
* form_cm_frame - get a free packet and build empty frame Use
|
|
|
* node info to build.
|
|
|
*/
|
|
|
-static struct sk_buff *form_cm_frame(struct sk_buff *skb,
|
|
|
+static void form_cm_frame(struct sk_buff *skb,
|
|
|
struct nes_cm_node *cm_node, void *options, u32 optionsize,
|
|
|
void *data, u32 datasize, u8 flags)
|
|
|
{
|
|
@@ -339,7 +338,6 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb,
|
|
|
skb_shinfo(skb)->nr_frags = 0;
|
|
|
cm_packets_created++;
|
|
|
|
|
|
- return skb;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -356,7 +354,6 @@ static void print_core(struct nes_cm_core *core)
|
|
|
|
|
|
nes_debug(NES_DBG_CM, "State : %u \n", core->state);
|
|
|
|
|
|
- nes_debug(NES_DBG_CM, "Tx Free cnt : %u \n", skb_queue_len(&core->tx_free_list));
|
|
|
nes_debug(NES_DBG_CM, "Listen Nodes : %u \n", atomic_read(&core->listen_node_cnt));
|
|
|
nes_debug(NES_DBG_CM, "Active Nodes : %u \n", atomic_read(&core->node_cnt));
|
|
|
|
|
@@ -381,8 +378,6 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
int ret = 0;
|
|
|
u32 was_timer_set;
|
|
|
|
|
|
- if (!cm_node)
|
|
|
- return -EINVAL;
|
|
|
new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
|
|
|
if (!new_send)
|
|
|
return -1;
|
|
@@ -459,13 +454,23 @@ static void nes_cm_timer_tick(unsigned long pass)
|
|
|
int ret = NETDEV_TX_OK;
|
|
|
enum nes_cm_node_state last_state;
|
|
|
|
|
|
+ struct list_head timer_list;
|
|
|
+ INIT_LIST_HEAD(&timer_list);
|
|
|
spin_lock_irqsave(&cm_core->ht_lock, flags);
|
|
|
|
|
|
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);
|
|
|
- add_ref_cm_node(cm_node);
|
|
|
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
|
|
|
+ if (!list_empty(&cm_node->recv_list) || (cm_node->send_entry)) {
|
|
|
+ add_ref_cm_node(cm_node);
|
|
|
+ list_add(&cm_node->timer_entry, &timer_list);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
|
|
|
+
|
|
|
+ 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) {
|
|
@@ -519,7 +524,7 @@ static void nes_cm_timer_tick(unsigned long pass)
|
|
|
do {
|
|
|
send_entry = cm_node->send_entry;
|
|
|
if (!send_entry)
|
|
|
- continue;
|
|
|
+ break;
|
|
|
if (time_after(send_entry->timetosend, jiffies)) {
|
|
|
if (cm_node->state != NES_CM_STATE_TSA) {
|
|
|
if ((nexttimeout >
|
|
@@ -528,18 +533,18 @@ static void nes_cm_timer_tick(unsigned long pass)
|
|
|
nexttimeout =
|
|
|
send_entry->timetosend;
|
|
|
settimer = 1;
|
|
|
- continue;
|
|
|
+ break;
|
|
|
}
|
|
|
} else {
|
|
|
free_retrans_entry(cm_node);
|
|
|
- continue;
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if ((cm_node->state == NES_CM_STATE_TSA) ||
|
|
|
(cm_node->state == NES_CM_STATE_CLOSED)) {
|
|
|
free_retrans_entry(cm_node);
|
|
|
- continue;
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
if (!send_entry->retranscount ||
|
|
@@ -557,7 +562,7 @@ static void nes_cm_timer_tick(unsigned long pass)
|
|
|
NES_CM_EVENT_ABORTED);
|
|
|
spin_lock_irqsave(&cm_node->retrans_list_lock,
|
|
|
flags);
|
|
|
- continue;
|
|
|
+ break;
|
|
|
}
|
|
|
atomic_inc(&send_entry->skb->users);
|
|
|
cm_packets_retrans++;
|
|
@@ -583,7 +588,7 @@ static void nes_cm_timer_tick(unsigned long pass)
|
|
|
send_entry->retrycount--;
|
|
|
nexttimeout = jiffies + NES_SHORT_TIME;
|
|
|
settimer = 1;
|
|
|
- continue;
|
|
|
+ break;
|
|
|
} else {
|
|
|
cm_packets_sent++;
|
|
|
}
|
|
@@ -615,14 +620,12 @@ static void nes_cm_timer_tick(unsigned long pass)
|
|
|
|
|
|
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
|
|
|
rem_ref_cm_node(cm_node->cm_core, cm_node);
|
|
|
- spin_lock_irqsave(&cm_core->ht_lock, flags);
|
|
|
if (ret != NETDEV_TX_OK) {
|
|
|
nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n",
|
|
|
cm_node);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
|
|
|
|
|
|
if (settimer) {
|
|
|
if (!timer_pending(&cm_core->tcp_timer)) {
|
|
@@ -683,7 +686,7 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack,
|
|
|
optionssize += 1;
|
|
|
|
|
|
if (!skb)
|
|
|
- skb = get_free_pkt(cm_node);
|
|
|
+ skb = dev_alloc_skb(MAX_CM_BUFFER);
|
|
|
if (!skb) {
|
|
|
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
|
|
|
return -1;
|
|
@@ -708,7 +711,7 @@ static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)
|
|
|
int flags = SET_RST | SET_ACK;
|
|
|
|
|
|
if (!skb)
|
|
|
- skb = get_free_pkt(cm_node);
|
|
|
+ skb = dev_alloc_skb(MAX_CM_BUFFER);
|
|
|
if (!skb) {
|
|
|
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
|
|
|
return -1;
|
|
@@ -729,7 +732,7 @@ static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb)
|
|
|
int ret;
|
|
|
|
|
|
if (!skb)
|
|
|
- skb = get_free_pkt(cm_node);
|
|
|
+ skb = dev_alloc_skb(MAX_CM_BUFFER);
|
|
|
|
|
|
if (!skb) {
|
|
|
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
|
|
@@ -752,7 +755,7 @@ static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)
|
|
|
|
|
|
/* if we didn't get a frame get one */
|
|
|
if (!skb)
|
|
|
- skb = get_free_pkt(cm_node);
|
|
|
+ skb = dev_alloc_skb(MAX_CM_BUFFER);
|
|
|
|
|
|
if (!skb) {
|
|
|
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
|
|
@@ -766,46 +769,6 @@ static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)
|
|
|
}
|
|
|
|
|
|
|
|
|
-/**
|
|
|
- * get_free_pkt
|
|
|
- */
|
|
|
-static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node)
|
|
|
-{
|
|
|
- struct sk_buff *skb, *new_skb;
|
|
|
-
|
|
|
- /* check to see if we need to repopulate the free tx pkt queue */
|
|
|
- if (skb_queue_len(&cm_node->cm_core->tx_free_list) < NES_CM_FREE_PKT_LO_WATERMARK) {
|
|
|
- while (skb_queue_len(&cm_node->cm_core->tx_free_list) <
|
|
|
- cm_node->cm_core->free_tx_pkt_max) {
|
|
|
- /* replace the frame we took, we won't get it back */
|
|
|
- new_skb = dev_alloc_skb(cm_node->cm_core->mtu);
|
|
|
- BUG_ON(!new_skb);
|
|
|
- /* add a replacement frame to the free tx list head */
|
|
|
- skb_queue_head(&cm_node->cm_core->tx_free_list, new_skb);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- skb = skb_dequeue(&cm_node->cm_core->tx_free_list);
|
|
|
-
|
|
|
- return skb;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * make_hashkey - generate hash key from node tuple
|
|
|
- */
|
|
|
-static inline int make_hashkey(u16 loc_port, nes_addr_t loc_addr, u16 rem_port,
|
|
|
- nes_addr_t rem_addr)
|
|
|
-{
|
|
|
- u32 hashkey = 0;
|
|
|
-
|
|
|
- hashkey = loc_addr + rem_addr + loc_port + rem_port;
|
|
|
- hashkey = (hashkey % NES_CM_HASHTABLE_SIZE);
|
|
|
-
|
|
|
- return hashkey;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
* find_node - find a cm node that matches the reference cm node
|
|
|
*/
|
|
@@ -813,13 +776,9 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
|
|
|
u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
- u32 hashkey;
|
|
|
struct list_head *hte;
|
|
|
struct nes_cm_node *cm_node;
|
|
|
|
|
|
- /* make a hash index key for this packet */
|
|
|
- hashkey = make_hashkey(loc_port, loc_addr, rem_port, rem_addr);
|
|
|
-
|
|
|
/* get a handle on the hte */
|
|
|
hte = &cm_core->connected_nodes;
|
|
|
|
|
@@ -887,7 +846,6 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
|
|
|
static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
- u32 hashkey;
|
|
|
struct list_head *hte;
|
|
|
|
|
|
if (!cm_node || !cm_core)
|
|
@@ -896,11 +854,6 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
|
|
|
nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n",
|
|
|
cm_node);
|
|
|
|
|
|
- /* first, make an index into our hash table */
|
|
|
- hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr,
|
|
|
- cm_node->rem_port, cm_node->rem_addr);
|
|
|
- cm_node->hashkey = hashkey;
|
|
|
-
|
|
|
spin_lock_irqsave(&cm_core->ht_lock, flags);
|
|
|
|
|
|
/* get a handle on the hash table element (list head for this slot) */
|
|
@@ -925,28 +878,36 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
|
|
|
struct list_head *list_pos = NULL;
|
|
|
struct list_head *list_temp = NULL;
|
|
|
struct nes_cm_node *cm_node = NULL;
|
|
|
+ struct list_head reset_list;
|
|
|
|
|
|
nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "
|
|
|
"refcnt=%d\n", listener, free_hanging_nodes,
|
|
|
atomic_read(&listener->ref_count));
|
|
|
/* free non-accelerated child nodes for this listener */
|
|
|
+ INIT_LIST_HEAD(&reset_list);
|
|
|
if (free_hanging_nodes) {
|
|
|
spin_lock_irqsave(&cm_core->ht_lock, flags);
|
|
|
list_for_each_safe(list_pos, list_temp,
|
|
|
- &g_cm_core->connected_nodes) {
|
|
|
+ &g_cm_core->connected_nodes) {
|
|
|
cm_node = container_of(list_pos, struct nes_cm_node,
|
|
|
list);
|
|
|
if ((cm_node->listener == listener) &&
|
|
|
- (!cm_node->accelerated)) {
|
|
|
- cleanup_retrans_entry(cm_node);
|
|
|
- spin_unlock_irqrestore(&cm_core->ht_lock,
|
|
|
- flags);
|
|
|
- send_reset(cm_node, NULL);
|
|
|
- spin_lock_irqsave(&cm_core->ht_lock, flags);
|
|
|
+ (!cm_node->accelerated)) {
|
|
|
+ add_ref_cm_node(cm_node);
|
|
|
+ list_add(&cm_node->reset_entry, &reset_list);
|
|
|
}
|
|
|
}
|
|
|
spin_unlock_irqrestore(&cm_core->ht_lock, flags);
|
|
|
}
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+
|
|
|
spin_lock_irqsave(&cm_core->listen_list_lock, flags);
|
|
|
if (!atomic_dec_return(&listener->ref_count)) {
|
|
|
list_del(&listener->list);
|
|
@@ -1126,7 +1087,10 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
|
|
|
|
|
|
cm_node->loopbackpartner = NULL;
|
|
|
/* get the mac addr for the remote node */
|
|
|
- arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
|
|
|
+ if (ipv4_is_loopback(htonl(cm_node->rem_addr)))
|
|
|
+ arpindex = nes_arp_table(nesdev, ntohl(nesvnic->local_ipaddr), NULL, NES_ARP_RESOLVE);
|
|
|
+ else
|
|
|
+ arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
|
|
|
if (arpindex < 0) {
|
|
|
arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr);
|
|
|
if (arpindex < 0) {
|
|
@@ -1306,7 +1270,6 @@ static void drop_packet(struct sk_buff *skb)
|
|
|
static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
struct tcphdr *tcph)
|
|
|
{
|
|
|
- atomic_inc(&cm_resets_recvd);
|
|
|
nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
|
|
|
"refcnt=%d\n", cm_node, cm_node->state,
|
|
|
atomic_read(&cm_node->ref_count));
|
|
@@ -1344,6 +1307,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
{
|
|
|
|
|
|
int reset = 0; /* whether to send reset in case of err.. */
|
|
|
+ int passive_state;
|
|
|
atomic_inc(&cm_resets_recvd);
|
|
|
nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."
|
|
|
" refcnt=%d\n", cm_node, cm_node->state,
|
|
@@ -1357,7 +1321,14 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
cm_node->listener, cm_node->state);
|
|
|
active_open_err(cm_node, skb, reset);
|
|
|
break;
|
|
|
- /* For PASSIVE open states, remove the cm_node event */
|
|
|
+ case NES_CM_STATE_MPAREQ_RCVD:
|
|
|
+ passive_state = atomic_add_return(1, &cm_node->passive_state);
|
|
|
+ if (passive_state == NES_SEND_RESET_EVENT)
|
|
|
+ create_event(cm_node, NES_CM_EVENT_RESET);
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
|
+ cm_node->state = NES_CM_STATE_CLOSED;
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ break;
|
|
|
case NES_CM_STATE_ESTABLISHED:
|
|
|
case NES_CM_STATE_SYN_RCVD:
|
|
|
case NES_CM_STATE_LISTENING:
|
|
@@ -1365,7 +1336,14 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
passive_open_err(cm_node, skb, reset);
|
|
|
break;
|
|
|
case NES_CM_STATE_TSA:
|
|
|
+ active_open_err(cm_node, skb, reset);
|
|
|
+ break;
|
|
|
+ case NES_CM_STATE_CLOSED:
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
|
+ drop_packet(skb);
|
|
|
+ break;
|
|
|
default:
|
|
|
+ drop_packet(skb);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -1394,6 +1372,9 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
dev_kfree_skb_any(skb);
|
|
|
if (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);
|
|
|
|
|
|
}
|
|
@@ -1474,7 +1455,7 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
int optionsize;
|
|
|
|
|
|
optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
|
|
|
- skb_pull(skb, tcph->doff << 2);
|
|
|
+ skb_trim(skb, 0);
|
|
|
inc_sequence = ntohl(tcph->seq);
|
|
|
|
|
|
switch (cm_node->state) {
|
|
@@ -1507,6 +1488,10 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
cm_node->state = NES_CM_STATE_SYN_RCVD;
|
|
|
send_syn(cm_node, 1, skb);
|
|
|
break;
|
|
|
+ case NES_CM_STATE_CLOSED:
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
|
+ send_reset(cm_node, skb);
|
|
|
+ break;
|
|
|
case NES_CM_STATE_TSA:
|
|
|
case NES_CM_STATE_ESTABLISHED:
|
|
|
case NES_CM_STATE_FIN_WAIT1:
|
|
@@ -1515,7 +1500,6 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
case NES_CM_STATE_LAST_ACK:
|
|
|
case NES_CM_STATE_CLOSING:
|
|
|
case NES_CM_STATE_UNKNOWN:
|
|
|
- case NES_CM_STATE_CLOSED:
|
|
|
default:
|
|
|
drop_packet(skb);
|
|
|
break;
|
|
@@ -1531,7 +1515,7 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
int optionsize;
|
|
|
|
|
|
optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
|
|
|
- skb_pull(skb, tcph->doff << 2);
|
|
|
+ skb_trim(skb, 0);
|
|
|
inc_sequence = ntohl(tcph->seq);
|
|
|
switch (cm_node->state) {
|
|
|
case NES_CM_STATE_SYN_SENT:
|
|
@@ -1555,6 +1539,12 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
/* passive open, so should not be here */
|
|
|
passive_open_err(cm_node, skb, 1);
|
|
|
break;
|
|
|
+ case NES_CM_STATE_LISTENING:
|
|
|
+ case NES_CM_STATE_CLOSED:
|
|
|
+ cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
|
+ send_reset(cm_node, skb);
|
|
|
+ break;
|
|
|
case NES_CM_STATE_ESTABLISHED:
|
|
|
case NES_CM_STATE_FIN_WAIT1:
|
|
|
case NES_CM_STATE_FIN_WAIT2:
|
|
@@ -1562,7 +1552,6 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
case NES_CM_STATE_TSA:
|
|
|
case NES_CM_STATE_CLOSING:
|
|
|
case NES_CM_STATE_UNKNOWN:
|
|
|
- case NES_CM_STATE_CLOSED:
|
|
|
case NES_CM_STATE_MPAREQ_SENT:
|
|
|
default:
|
|
|
drop_packet(skb);
|
|
@@ -1577,6 +1566,13 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
u32 inc_sequence;
|
|
|
u32 rem_seq_ack;
|
|
|
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;
|
|
|
|
|
@@ -1589,7 +1585,18 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
switch (cm_node->state) {
|
|
|
case NES_CM_STATE_SYN_RCVD:
|
|
|
/* Passive OPEN */
|
|
|
+ ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 1);
|
|
|
+ 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");
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
|
+ send_reset(cm_node, skb);
|
|
|
+ return;
|
|
|
+ }
|
|
|
cm_node->state = NES_CM_STATE_ESTABLISHED;
|
|
|
if (datasize) {
|
|
|
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
|
|
@@ -1621,11 +1628,15 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
|
|
|
dev_kfree_skb_any(skb);
|
|
|
}
|
|
|
break;
|
|
|
+ case NES_CM_STATE_LISTENING:
|
|
|
+ case NES_CM_STATE_CLOSED:
|
|
|
+ cleanup_retrans_entry(cm_node);
|
|
|
+ send_reset(cm_node, skb);
|
|
|
+ break;
|
|
|
case NES_CM_STATE_FIN_WAIT1:
|
|
|
case NES_CM_STATE_SYN_SENT:
|
|
|
case NES_CM_STATE_FIN_WAIT2:
|
|
|
case NES_CM_STATE_TSA:
|
|
|
- case NES_CM_STATE_CLOSED:
|
|
|
case NES_CM_STATE_MPAREQ_RCVD:
|
|
|
case NES_CM_STATE_LAST_ACK:
|
|
|
case NES_CM_STATE_CLOSING:
|
|
@@ -1648,9 +1659,9 @@ static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
|
|
|
nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",
|
|
|
__func__, cm_node);
|
|
|
if (passive)
|
|
|
- passive_open_err(cm_node, skb, 0);
|
|
|
+ passive_open_err(cm_node, skb, 1);
|
|
|
else
|
|
|
- active_open_err(cm_node, skb, 0);
|
|
|
+ active_open_err(cm_node, skb, 1);
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
@@ -1970,6 +1981,7 @@ 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 passive_state;
|
|
|
|
|
|
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);
|
|
@@ -1977,9 +1989,13 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
|
|
|
if (cm_node->tcp_cntxt.client)
|
|
|
return ret;
|
|
|
cleanup_retrans_entry(cm_node);
|
|
|
- cm_node->state = NES_CM_STATE_CLOSED;
|
|
|
|
|
|
- ret = send_reset(cm_node, NULL);
|
|
|
+ passive_state = atomic_add_return(1, &cm_node->passive_state);
|
|
|
+ cm_node->state = NES_CM_STATE_CLOSED;
|
|
|
+ if (passive_state == NES_SEND_RESET_EVENT)
|
|
|
+ rem_ref_cm_node(cm_core, cm_node);
|
|
|
+ else
|
|
|
+ ret = send_reset(cm_node, NULL);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -2037,7 +2053,7 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
|
|
|
* recv_pkt - recv an ETHERNET packet, and process it through CM
|
|
|
* node state machine
|
|
|
*/
|
|
|
-static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
|
|
|
+static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
|
|
|
struct nes_vnic *nesvnic, struct sk_buff *skb)
|
|
|
{
|
|
|
struct nes_cm_node *cm_node = NULL;
|
|
@@ -2045,23 +2061,16 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
|
|
|
struct iphdr *iph;
|
|
|
struct tcphdr *tcph;
|
|
|
struct nes_cm_info nfo;
|
|
|
+ int skb_handled = 1;
|
|
|
|
|
|
if (!skb)
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
|
|
|
- dev_kfree_skb_any(skb);
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
iph = (struct iphdr *)skb->data;
|
|
|
tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));
|
|
|
- skb_reset_network_header(skb);
|
|
|
- skb_set_transport_header(skb, sizeof(*tcph));
|
|
|
- if (!tcph) {
|
|
|
- dev_kfree_skb_any(skb);
|
|
|
- return;
|
|
|
- }
|
|
|
- skb->len = ntohs(iph->tot_len);
|
|
|
|
|
|
nfo.loc_addr = ntohl(iph->daddr);
|
|
|
nfo.loc_port = ntohs(tcph->dest);
|
|
@@ -2082,23 +2091,21 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
|
|
|
/* Only type of packet accepted are for */
|
|
|
/* the PASSIVE open (syn only) */
|
|
|
if ((!tcph->syn) || (tcph->ack)) {
|
|
|
- cm_packets_dropped++;
|
|
|
+ skb_handled = 0;
|
|
|
break;
|
|
|
}
|
|
|
listener = find_listener(cm_core, nfo.loc_addr,
|
|
|
nfo.loc_port,
|
|
|
NES_CM_LISTENER_ACTIVE_STATE);
|
|
|
- if (listener) {
|
|
|
- nfo.cm_id = listener->cm_id;
|
|
|
- nfo.conn_type = listener->conn_type;
|
|
|
- } else {
|
|
|
- nes_debug(NES_DBG_CM, "Unable to find listener "
|
|
|
- "for the pkt\n");
|
|
|
- cm_packets_dropped++;
|
|
|
- dev_kfree_skb_any(skb);
|
|
|
+ if (!listener) {
|
|
|
+ nfo.cm_id = NULL;
|
|
|
+ nfo.conn_type = 0;
|
|
|
+ nes_debug(NES_DBG_CM, "Unable to find listener for the pkt\n");
|
|
|
+ skb_handled = 0;
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
+ nfo.cm_id = listener->cm_id;
|
|
|
+ nfo.conn_type = listener->conn_type;
|
|
|
cm_node = make_cm_node(cm_core, nesvnic, &nfo,
|
|
|
listener);
|
|
|
if (!cm_node) {
|
|
@@ -2124,9 +2131,13 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
|
|
|
dev_kfree_skb_any(skb);
|
|
|
break;
|
|
|
}
|
|
|
+ skb_reset_network_header(skb);
|
|
|
+ skb_set_transport_header(skb, sizeof(*tcph));
|
|
|
+ skb->len = ntohs(iph->tot_len);
|
|
|
process_packet(cm_node, skb, cm_core);
|
|
|
rem_ref_cm_node(cm_core, cm_node);
|
|
|
} while (0);
|
|
|
+ return skb_handled;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -2135,10 +2146,7 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
|
|
|
*/
|
|
|
static struct nes_cm_core *nes_cm_alloc_core(void)
|
|
|
{
|
|
|
- int i;
|
|
|
-
|
|
|
struct nes_cm_core *cm_core;
|
|
|
- struct sk_buff *skb = NULL;
|
|
|
|
|
|
/* setup the CM core */
|
|
|
/* alloc top level core control structure */
|
|
@@ -2156,19 +2164,6 @@ static struct nes_cm_core *nes_cm_alloc_core(void)
|
|
|
|
|
|
atomic_set(&cm_core->events_posted, 0);
|
|
|
|
|
|
- /* init the packet lists */
|
|
|
- skb_queue_head_init(&cm_core->tx_free_list);
|
|
|
-
|
|
|
- for (i = 0; i < NES_CM_DEFAULT_FRAME_CNT; i++) {
|
|
|
- skb = dev_alloc_skb(cm_core->mtu);
|
|
|
- if (!skb) {
|
|
|
- kfree(cm_core);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
- /* add 'raw' skb to free frame list */
|
|
|
- skb_queue_head(&cm_core->tx_free_list, skb);
|
|
|
- }
|
|
|
-
|
|
|
cm_core->api = &nes_cm_api;
|
|
|
|
|
|
spin_lock_init(&cm_core->ht_lock);
|
|
@@ -2397,7 +2392,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
|
|
|
atomic_inc(&cm_disconnects);
|
|
|
cm_event.event = IW_CM_EVENT_DISCONNECT;
|
|
|
if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
|
|
|
- issued_disconnect_reset = 1;
|
|
|
cm_event.status = IW_CM_EVENT_STATUS_RESET;
|
|
|
nes_debug(NES_DBG_CM, "Generating a CM "
|
|
|
"Disconnect Event (status reset) for "
|
|
@@ -2547,6 +2541,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|
|
struct nes_v4_quad nes_quad;
|
|
|
u32 crc_value;
|
|
|
int ret;
|
|
|
+ int passive_state;
|
|
|
|
|
|
ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
|
|
|
if (!ibqp)
|
|
@@ -2714,8 +2709,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|
|
conn_param->private_data_len +
|
|
|
sizeof(struct ietf_mpa_frame));
|
|
|
|
|
|
- attr.qp_state = IB_QPS_RTS;
|
|
|
- nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
|
|
|
|
|
|
/* notify OF layer that accept event was successfull */
|
|
|
cm_id->add_ref(cm_id);
|
|
@@ -2728,6 +2721,8 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|
|
cm_event.private_data = NULL;
|
|
|
cm_event.private_data_len = 0;
|
|
|
ret = cm_id->event_handler(cm_id, &cm_event);
|
|
|
+ attr.qp_state = IB_QPS_RTS;
|
|
|
+ nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
|
|
|
if (cm_node->loopbackpartner) {
|
|
|
cm_node->loopbackpartner->mpa_frame_size =
|
|
|
nesqp->private_data_len;
|
|
@@ -2740,6 +2735,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|
|
printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
|
|
|
"ret=%d\n", __func__, __LINE__, ret);
|
|
|
|
|
|
+ passive_state = atomic_add_return(1, &cm_node->passive_state);
|
|
|
+ if (passive_state == NES_SEND_RESET_EVENT)
|
|
|
+ create_event(cm_node, NES_CM_EVENT_RESET);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2943,15 +2941,16 @@ int nes_destroy_listen(struct iw_cm_id *cm_id)
|
|
|
*/
|
|
|
int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)
|
|
|
{
|
|
|
+ int rc = 0;
|
|
|
cm_packets_received++;
|
|
|
if ((g_cm_core) && (g_cm_core->api)) {
|
|
|
- g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
|
|
|
+ rc = g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
|
|
|
} else {
|
|
|
nes_debug(NES_DBG_CM, "Unable to process packet for CM,"
|
|
|
" cm is not setup properly.\n");
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -3222,6 +3221,18 @@ static void cm_event_reset(struct nes_cm_event *event)
|
|
|
cm_event.private_data_len = 0;
|
|
|
|
|
|
ret = cm_id->event_handler(cm_id, &cm_event);
|
|
|
+ cm_id->add_ref(cm_id);
|
|
|
+ atomic_inc(&cm_closes);
|
|
|
+ cm_event.event = IW_CM_EVENT_CLOSE;
|
|
|
+ cm_event.status = IW_CM_EVENT_STATUS_OK;
|
|
|
+ cm_event.provider_data = cm_id->provider_data;
|
|
|
+ cm_event.local_addr = cm_id->local_addr;
|
|
|
+ cm_event.remote_addr = cm_id->remote_addr;
|
|
|
+ cm_event.private_data = NULL;
|
|
|
+ cm_event.private_data_len = 0;
|
|
|
+ nes_debug(NES_DBG_CM, "NODE %p Generating CLOSE\n", event->cm_node);
|
|
|
+ ret = cm_id->event_handler(cm_id, &cm_event);
|
|
|
+
|
|
|
nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
|
|
|
|
|
|
|