xref: /openbmc/linux/drivers/infiniband/hw/irdma/cm.c (revision e50e86dbcabda570fc8a1435fe2fca97e9ab7312)
1146b9756SMustafa Ismail // SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
2146b9756SMustafa Ismail /* Copyright (c) 2015 - 2021 Intel Corporation */
3146b9756SMustafa Ismail #include "main.h"
4146b9756SMustafa Ismail #include "trace.h"
5146b9756SMustafa Ismail 
6146b9756SMustafa Ismail static void irdma_cm_post_event(struct irdma_cm_event *event);
7146b9756SMustafa Ismail static void irdma_disconnect_worker(struct work_struct *work);
8146b9756SMustafa Ismail 
9146b9756SMustafa Ismail /**
10146b9756SMustafa Ismail  * irdma_free_sqbuf - put back puda buffer if refcount is 0
11146b9756SMustafa Ismail  * @vsi: The VSI structure of the device
12146b9756SMustafa Ismail  * @bufp: puda buffer to free
13146b9756SMustafa Ismail  */
irdma_free_sqbuf(struct irdma_sc_vsi * vsi,void * bufp)14146b9756SMustafa Ismail void irdma_free_sqbuf(struct irdma_sc_vsi *vsi, void *bufp)
15146b9756SMustafa Ismail {
16146b9756SMustafa Ismail 	struct irdma_puda_buf *buf = bufp;
17146b9756SMustafa Ismail 	struct irdma_puda_rsrc *ilq = vsi->ilq;
18146b9756SMustafa Ismail 
19146b9756SMustafa Ismail 	if (refcount_dec_and_test(&buf->refcount))
20146b9756SMustafa Ismail 		irdma_puda_ret_bufpool(ilq, buf);
21146b9756SMustafa Ismail }
22146b9756SMustafa Ismail 
23146b9756SMustafa Ismail /**
24146b9756SMustafa Ismail  * irdma_record_ird_ord - Record IRD/ORD passed in
25146b9756SMustafa Ismail  * @cm_node: connection's node
26146b9756SMustafa Ismail  * @conn_ird: connection IRD
27146b9756SMustafa Ismail  * @conn_ord: connection ORD
28146b9756SMustafa Ismail  */
irdma_record_ird_ord(struct irdma_cm_node * cm_node,u32 conn_ird,u32 conn_ord)29146b9756SMustafa Ismail static void irdma_record_ird_ord(struct irdma_cm_node *cm_node, u32 conn_ird,
30146b9756SMustafa Ismail 				 u32 conn_ord)
31146b9756SMustafa Ismail {
32146b9756SMustafa Ismail 	if (conn_ird > cm_node->dev->hw_attrs.max_hw_ird)
33146b9756SMustafa Ismail 		conn_ird = cm_node->dev->hw_attrs.max_hw_ird;
34146b9756SMustafa Ismail 
35146b9756SMustafa Ismail 	if (conn_ord > cm_node->dev->hw_attrs.max_hw_ord)
36146b9756SMustafa Ismail 		conn_ord = cm_node->dev->hw_attrs.max_hw_ord;
37146b9756SMustafa Ismail 	else if (!conn_ord && cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO)
38146b9756SMustafa Ismail 		conn_ord = 1;
39146b9756SMustafa Ismail 	cm_node->ird_size = conn_ird;
40146b9756SMustafa Ismail 	cm_node->ord_size = conn_ord;
41146b9756SMustafa Ismail }
42146b9756SMustafa Ismail 
43146b9756SMustafa Ismail /**
44146b9756SMustafa Ismail  * irdma_copy_ip_ntohl - copy IP address from  network to host
45146b9756SMustafa Ismail  * @dst: IP address in host order
46146b9756SMustafa Ismail  * @src: IP address in network order (big endian)
47146b9756SMustafa Ismail  */
irdma_copy_ip_ntohl(u32 * dst,__be32 * src)48146b9756SMustafa Ismail void irdma_copy_ip_ntohl(u32 *dst, __be32 *src)
49146b9756SMustafa Ismail {
50146b9756SMustafa Ismail 	*dst++ = ntohl(*src++);
51146b9756SMustafa Ismail 	*dst++ = ntohl(*src++);
52146b9756SMustafa Ismail 	*dst++ = ntohl(*src++);
53146b9756SMustafa Ismail 	*dst = ntohl(*src);
54146b9756SMustafa Ismail }
55146b9756SMustafa Ismail 
56146b9756SMustafa Ismail /**
57146b9756SMustafa Ismail  * irdma_copy_ip_htonl - copy IP address from host to network order
58146b9756SMustafa Ismail  * @dst: IP address in network order (big endian)
59146b9756SMustafa Ismail  * @src: IP address in host order
60146b9756SMustafa Ismail  */
irdma_copy_ip_htonl(__be32 * dst,u32 * src)61146b9756SMustafa Ismail void irdma_copy_ip_htonl(__be32 *dst, u32 *src)
62146b9756SMustafa Ismail {
63146b9756SMustafa Ismail 	*dst++ = htonl(*src++);
64146b9756SMustafa Ismail 	*dst++ = htonl(*src++);
65146b9756SMustafa Ismail 	*dst++ = htonl(*src++);
66146b9756SMustafa Ismail 	*dst = htonl(*src);
67146b9756SMustafa Ismail }
68146b9756SMustafa Ismail 
69146b9756SMustafa Ismail /**
70146b9756SMustafa Ismail  * irdma_get_addr_info
71146b9756SMustafa Ismail  * @cm_node: contains ip/tcp info
72146b9756SMustafa Ismail  * @cm_info: to get a copy of the cm_node ip/tcp info
73146b9756SMustafa Ismail  */
irdma_get_addr_info(struct irdma_cm_node * cm_node,struct irdma_cm_info * cm_info)74146b9756SMustafa Ismail static void irdma_get_addr_info(struct irdma_cm_node *cm_node,
75146b9756SMustafa Ismail 				struct irdma_cm_info *cm_info)
76146b9756SMustafa Ismail {
77146b9756SMustafa Ismail 	memset(cm_info, 0, sizeof(*cm_info));
78146b9756SMustafa Ismail 	cm_info->ipv4 = cm_node->ipv4;
79146b9756SMustafa Ismail 	cm_info->vlan_id = cm_node->vlan_id;
80146b9756SMustafa Ismail 	memcpy(cm_info->loc_addr, cm_node->loc_addr, sizeof(cm_info->loc_addr));
81146b9756SMustafa Ismail 	memcpy(cm_info->rem_addr, cm_node->rem_addr, sizeof(cm_info->rem_addr));
82146b9756SMustafa Ismail 	cm_info->loc_port = cm_node->loc_port;
83146b9756SMustafa Ismail 	cm_info->rem_port = cm_node->rem_port;
84146b9756SMustafa Ismail }
85146b9756SMustafa Ismail 
86146b9756SMustafa Ismail /**
87146b9756SMustafa Ismail  * irdma_fill_sockaddr4 - fill in addr info for IPv4 connection
88146b9756SMustafa Ismail  * @cm_node: connection's node
89146b9756SMustafa Ismail  * @event: upper layer's cm event
90146b9756SMustafa Ismail  */
irdma_fill_sockaddr4(struct irdma_cm_node * cm_node,struct iw_cm_event * event)91146b9756SMustafa Ismail static inline void irdma_fill_sockaddr4(struct irdma_cm_node *cm_node,
92146b9756SMustafa Ismail 					struct iw_cm_event *event)
93146b9756SMustafa Ismail {
94146b9756SMustafa Ismail 	struct sockaddr_in *laddr = (struct sockaddr_in *)&event->local_addr;
95146b9756SMustafa Ismail 	struct sockaddr_in *raddr = (struct sockaddr_in *)&event->remote_addr;
96146b9756SMustafa Ismail 
97146b9756SMustafa Ismail 	laddr->sin_family = AF_INET;
98146b9756SMustafa Ismail 	raddr->sin_family = AF_INET;
99146b9756SMustafa Ismail 
100146b9756SMustafa Ismail 	laddr->sin_port = htons(cm_node->loc_port);
101146b9756SMustafa Ismail 	raddr->sin_port = htons(cm_node->rem_port);
102146b9756SMustafa Ismail 
103146b9756SMustafa Ismail 	laddr->sin_addr.s_addr = htonl(cm_node->loc_addr[0]);
104146b9756SMustafa Ismail 	raddr->sin_addr.s_addr = htonl(cm_node->rem_addr[0]);
105146b9756SMustafa Ismail }
106146b9756SMustafa Ismail 
107146b9756SMustafa Ismail /**
108146b9756SMustafa Ismail  * irdma_fill_sockaddr6 - fill in addr info for IPv6 connection
109146b9756SMustafa Ismail  * @cm_node: connection's node
110146b9756SMustafa Ismail  * @event: upper layer's cm event
111146b9756SMustafa Ismail  */
irdma_fill_sockaddr6(struct irdma_cm_node * cm_node,struct iw_cm_event * event)112146b9756SMustafa Ismail static inline void irdma_fill_sockaddr6(struct irdma_cm_node *cm_node,
113146b9756SMustafa Ismail 					struct iw_cm_event *event)
114146b9756SMustafa Ismail {
115146b9756SMustafa Ismail 	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&event->local_addr;
116146b9756SMustafa Ismail 	struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *)&event->remote_addr;
117146b9756SMustafa Ismail 
118146b9756SMustafa Ismail 	laddr6->sin6_family = AF_INET6;
119146b9756SMustafa Ismail 	raddr6->sin6_family = AF_INET6;
120146b9756SMustafa Ismail 
121146b9756SMustafa Ismail 	laddr6->sin6_port = htons(cm_node->loc_port);
122146b9756SMustafa Ismail 	raddr6->sin6_port = htons(cm_node->rem_port);
123146b9756SMustafa Ismail 
124146b9756SMustafa Ismail 	irdma_copy_ip_htonl(laddr6->sin6_addr.in6_u.u6_addr32,
125146b9756SMustafa Ismail 			    cm_node->loc_addr);
126146b9756SMustafa Ismail 	irdma_copy_ip_htonl(raddr6->sin6_addr.in6_u.u6_addr32,
127146b9756SMustafa Ismail 			    cm_node->rem_addr);
128146b9756SMustafa Ismail }
129146b9756SMustafa Ismail 
130146b9756SMustafa Ismail /**
131146b9756SMustafa Ismail  * irdma_get_cmevent_info - for cm event upcall
132146b9756SMustafa Ismail  * @cm_node: connection's node
133146b9756SMustafa Ismail  * @cm_id: upper layers cm struct for the event
134146b9756SMustafa Ismail  * @event: upper layer's cm event
135146b9756SMustafa Ismail  */
irdma_get_cmevent_info(struct irdma_cm_node * cm_node,struct iw_cm_id * cm_id,struct iw_cm_event * event)136146b9756SMustafa Ismail static inline void irdma_get_cmevent_info(struct irdma_cm_node *cm_node,
137146b9756SMustafa Ismail 					  struct iw_cm_id *cm_id,
138146b9756SMustafa Ismail 					  struct iw_cm_event *event)
139146b9756SMustafa Ismail {
140146b9756SMustafa Ismail 	memcpy(&event->local_addr, &cm_id->m_local_addr,
141146b9756SMustafa Ismail 	       sizeof(event->local_addr));
142146b9756SMustafa Ismail 	memcpy(&event->remote_addr, &cm_id->m_remote_addr,
143146b9756SMustafa Ismail 	       sizeof(event->remote_addr));
144146b9756SMustafa Ismail 	if (cm_node) {
145146b9756SMustafa Ismail 		event->private_data = cm_node->pdata_buf;
146146b9756SMustafa Ismail 		event->private_data_len = (u8)cm_node->pdata.size;
147146b9756SMustafa Ismail 		event->ird = cm_node->ird_size;
148146b9756SMustafa Ismail 		event->ord = cm_node->ord_size;
149146b9756SMustafa Ismail 	}
150146b9756SMustafa Ismail }
151146b9756SMustafa Ismail 
152146b9756SMustafa Ismail /**
153146b9756SMustafa Ismail  * irdma_send_cm_event - upcall cm's event handler
154146b9756SMustafa Ismail  * @cm_node: connection's node
155146b9756SMustafa Ismail  * @cm_id: upper layer's cm info struct
156146b9756SMustafa Ismail  * @type: Event type to indicate
157146b9756SMustafa Ismail  * @status: status for the event type
158146b9756SMustafa Ismail  */
irdma_send_cm_event(struct irdma_cm_node * cm_node,struct iw_cm_id * cm_id,enum iw_cm_event_type type,int status)159146b9756SMustafa Ismail static int irdma_send_cm_event(struct irdma_cm_node *cm_node,
160146b9756SMustafa Ismail 			       struct iw_cm_id *cm_id,
161146b9756SMustafa Ismail 			       enum iw_cm_event_type type, int status)
162146b9756SMustafa Ismail {
163146b9756SMustafa Ismail 	struct iw_cm_event event = {};
164146b9756SMustafa Ismail 
165146b9756SMustafa Ismail 	event.event = type;
166146b9756SMustafa Ismail 	event.status = status;
167146b9756SMustafa Ismail 	trace_irdma_send_cm_event(cm_node, cm_id, type, status,
168146b9756SMustafa Ismail 				  __builtin_return_address(0));
169146b9756SMustafa Ismail 
170146b9756SMustafa Ismail 	ibdev_dbg(&cm_node->iwdev->ibdev,
171146b9756SMustafa Ismail 		  "CM: cm_node %p cm_id=%p state=%d accel=%d event_type=%d status=%d\n",
172146b9756SMustafa Ismail 		  cm_node, cm_id, cm_node->accelerated, cm_node->state, type,
173146b9756SMustafa Ismail 		  status);
174146b9756SMustafa Ismail 
175146b9756SMustafa Ismail 	switch (type) {
176146b9756SMustafa Ismail 	case IW_CM_EVENT_CONNECT_REQUEST:
177146b9756SMustafa Ismail 		if (cm_node->ipv4)
178146b9756SMustafa Ismail 			irdma_fill_sockaddr4(cm_node, &event);
179146b9756SMustafa Ismail 		else
180146b9756SMustafa Ismail 			irdma_fill_sockaddr6(cm_node, &event);
181146b9756SMustafa Ismail 		event.provider_data = cm_node;
182146b9756SMustafa Ismail 		event.private_data = cm_node->pdata_buf;
183146b9756SMustafa Ismail 		event.private_data_len = (u8)cm_node->pdata.size;
184146b9756SMustafa Ismail 		event.ird = cm_node->ird_size;
185146b9756SMustafa Ismail 		break;
186146b9756SMustafa Ismail 	case IW_CM_EVENT_CONNECT_REPLY:
187146b9756SMustafa Ismail 		irdma_get_cmevent_info(cm_node, cm_id, &event);
188146b9756SMustafa Ismail 		break;
189146b9756SMustafa Ismail 	case IW_CM_EVENT_ESTABLISHED:
190146b9756SMustafa Ismail 		event.ird = cm_node->ird_size;
191146b9756SMustafa Ismail 		event.ord = cm_node->ord_size;
192146b9756SMustafa Ismail 		break;
193146b9756SMustafa Ismail 	case IW_CM_EVENT_DISCONNECT:
194146b9756SMustafa Ismail 	case IW_CM_EVENT_CLOSE:
195146b9756SMustafa Ismail 		/* Wait if we are in RTS but havent issued the iwcm event upcall */
196146b9756SMustafa Ismail 		if (!cm_node->accelerated)
197146b9756SMustafa Ismail 			wait_for_completion(&cm_node->establish_comp);
198146b9756SMustafa Ismail 		break;
199146b9756SMustafa Ismail 	default:
200146b9756SMustafa Ismail 		return -EINVAL;
201146b9756SMustafa Ismail 	}
202146b9756SMustafa Ismail 
203146b9756SMustafa Ismail 	return cm_id->event_handler(cm_id, &event);
204146b9756SMustafa Ismail }
205146b9756SMustafa Ismail 
206146b9756SMustafa Ismail /**
207146b9756SMustafa Ismail  * irdma_timer_list_prep - add connection nodes to a list to perform timer tasks
208146b9756SMustafa Ismail  * @cm_core: cm's core
209146b9756SMustafa Ismail  * @timer_list: a timer list to which cm_node will be selected
210146b9756SMustafa Ismail  */
irdma_timer_list_prep(struct irdma_cm_core * cm_core,struct list_head * timer_list)211146b9756SMustafa Ismail static void irdma_timer_list_prep(struct irdma_cm_core *cm_core,
212146b9756SMustafa Ismail 				  struct list_head *timer_list)
213146b9756SMustafa Ismail {
214146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
215146b9756SMustafa Ismail 	int bkt;
216146b9756SMustafa Ismail 
217146b9756SMustafa Ismail 	hash_for_each_rcu(cm_core->cm_hash_tbl, bkt, cm_node, list) {
218146b9756SMustafa Ismail 		if ((cm_node->close_entry || cm_node->send_entry) &&
219146b9756SMustafa Ismail 		    refcount_inc_not_zero(&cm_node->refcnt))
220146b9756SMustafa Ismail 			list_add(&cm_node->timer_entry, timer_list);
221146b9756SMustafa Ismail 	}
222146b9756SMustafa Ismail }
223146b9756SMustafa Ismail 
224146b9756SMustafa Ismail /**
225146b9756SMustafa Ismail  * irdma_create_event - create cm event
226146b9756SMustafa Ismail  * @cm_node: connection's node
227146b9756SMustafa Ismail  * @type: Event type to generate
228146b9756SMustafa Ismail  */
irdma_create_event(struct irdma_cm_node * cm_node,enum irdma_cm_event_type type)229146b9756SMustafa Ismail static struct irdma_cm_event *irdma_create_event(struct irdma_cm_node *cm_node,
230146b9756SMustafa Ismail 						 enum irdma_cm_event_type type)
231146b9756SMustafa Ismail {
232146b9756SMustafa Ismail 	struct irdma_cm_event *event;
233146b9756SMustafa Ismail 
234146b9756SMustafa Ismail 	if (!cm_node->cm_id)
235146b9756SMustafa Ismail 		return NULL;
236146b9756SMustafa Ismail 
237146b9756SMustafa Ismail 	event = kzalloc(sizeof(*event), GFP_ATOMIC);
238146b9756SMustafa Ismail 
239146b9756SMustafa Ismail 	if (!event)
240146b9756SMustafa Ismail 		return NULL;
241146b9756SMustafa Ismail 
242146b9756SMustafa Ismail 	event->type = type;
243146b9756SMustafa Ismail 	event->cm_node = cm_node;
244146b9756SMustafa Ismail 	memcpy(event->cm_info.rem_addr, cm_node->rem_addr,
245146b9756SMustafa Ismail 	       sizeof(event->cm_info.rem_addr));
246146b9756SMustafa Ismail 	memcpy(event->cm_info.loc_addr, cm_node->loc_addr,
247146b9756SMustafa Ismail 	       sizeof(event->cm_info.loc_addr));
248146b9756SMustafa Ismail 	event->cm_info.rem_port = cm_node->rem_port;
249146b9756SMustafa Ismail 	event->cm_info.loc_port = cm_node->loc_port;
250146b9756SMustafa Ismail 	event->cm_info.cm_id = cm_node->cm_id;
251146b9756SMustafa Ismail 	ibdev_dbg(&cm_node->iwdev->ibdev,
252146b9756SMustafa Ismail 		  "CM: node=%p event=%p type=%u dst=%pI4 src=%pI4\n", cm_node,
253146b9756SMustafa Ismail 		  event, type, event->cm_info.loc_addr,
254146b9756SMustafa Ismail 		  event->cm_info.rem_addr);
255146b9756SMustafa Ismail 	trace_irdma_create_event(cm_node, type, __builtin_return_address(0));
256146b9756SMustafa Ismail 	irdma_cm_post_event(event);
257146b9756SMustafa Ismail 
258146b9756SMustafa Ismail 	return event;
259146b9756SMustafa Ismail }
260146b9756SMustafa Ismail 
261146b9756SMustafa Ismail /**
262146b9756SMustafa Ismail  * irdma_free_retrans_entry - free send entry
263146b9756SMustafa Ismail  * @cm_node: connection's node
264146b9756SMustafa Ismail  */
irdma_free_retrans_entry(struct irdma_cm_node * cm_node)265146b9756SMustafa Ismail static void irdma_free_retrans_entry(struct irdma_cm_node *cm_node)
266146b9756SMustafa Ismail {
267146b9756SMustafa Ismail 	struct irdma_device *iwdev = cm_node->iwdev;
268146b9756SMustafa Ismail 	struct irdma_timer_entry *send_entry;
269146b9756SMustafa Ismail 
270146b9756SMustafa Ismail 	send_entry = cm_node->send_entry;
271146b9756SMustafa Ismail 	if (!send_entry)
272146b9756SMustafa Ismail 		return;
273146b9756SMustafa Ismail 
274146b9756SMustafa Ismail 	cm_node->send_entry = NULL;
275146b9756SMustafa Ismail 	irdma_free_sqbuf(&iwdev->vsi, send_entry->sqbuf);
276146b9756SMustafa Ismail 	kfree(send_entry);
277146b9756SMustafa Ismail 	refcount_dec(&cm_node->refcnt);
278146b9756SMustafa Ismail }
279146b9756SMustafa Ismail 
280146b9756SMustafa Ismail /**
281146b9756SMustafa Ismail  * irdma_cleanup_retrans_entry - free send entry with lock
282146b9756SMustafa Ismail  * @cm_node: connection's node
283146b9756SMustafa Ismail  */
irdma_cleanup_retrans_entry(struct irdma_cm_node * cm_node)284146b9756SMustafa Ismail static void irdma_cleanup_retrans_entry(struct irdma_cm_node *cm_node)
285146b9756SMustafa Ismail {
286146b9756SMustafa Ismail 	unsigned long flags;
287146b9756SMustafa Ismail 
288146b9756SMustafa Ismail 	spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
289146b9756SMustafa Ismail 	irdma_free_retrans_entry(cm_node);
290146b9756SMustafa Ismail 	spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
291146b9756SMustafa Ismail }
292146b9756SMustafa Ismail 
293146b9756SMustafa Ismail /**
294146b9756SMustafa Ismail  * irdma_form_ah_cm_frame - get a free packet and build frame with address handle
295146b9756SMustafa Ismail  * @cm_node: connection's node ionfo to use in frame
296146b9756SMustafa Ismail  * @options: pointer to options info
297146b9756SMustafa Ismail  * @hdr: pointer mpa header
298146b9756SMustafa Ismail  * @pdata: pointer to private data
299146b9756SMustafa Ismail  * @flags:  indicates FIN or ACK
300146b9756SMustafa Ismail  */
irdma_form_ah_cm_frame(struct irdma_cm_node * cm_node,struct irdma_kmem_info * options,struct irdma_kmem_info * hdr,struct irdma_mpa_priv_info * pdata,u8 flags)301146b9756SMustafa Ismail static struct irdma_puda_buf *irdma_form_ah_cm_frame(struct irdma_cm_node *cm_node,
302146b9756SMustafa Ismail 						     struct irdma_kmem_info *options,
303146b9756SMustafa Ismail 						     struct irdma_kmem_info *hdr,
304146b9756SMustafa Ismail 						     struct irdma_mpa_priv_info *pdata,
305146b9756SMustafa Ismail 						     u8 flags)
306146b9756SMustafa Ismail {
307146b9756SMustafa Ismail 	struct irdma_puda_buf *sqbuf;
308146b9756SMustafa Ismail 	struct irdma_sc_vsi *vsi = &cm_node->iwdev->vsi;
309146b9756SMustafa Ismail 	u8 *buf;
310146b9756SMustafa Ismail 	struct tcphdr *tcph;
311146b9756SMustafa Ismail 	u16 pktsize;
312146b9756SMustafa Ismail 	u32 opts_len = 0;
313146b9756SMustafa Ismail 	u32 pd_len = 0;
314146b9756SMustafa Ismail 	u32 hdr_len = 0;
315146b9756SMustafa Ismail 
316146b9756SMustafa Ismail 	if (!cm_node->ah || !cm_node->ah->ah_info.ah_valid) {
317146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev, "CM: AH invalid\n");
318146b9756SMustafa Ismail 		return NULL;
319146b9756SMustafa Ismail 	}
320146b9756SMustafa Ismail 
321146b9756SMustafa Ismail 	sqbuf = irdma_puda_get_bufpool(vsi->ilq);
322146b9756SMustafa Ismail 	if (!sqbuf) {
323146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev, "CM: SQ buf NULL\n");
324146b9756SMustafa Ismail 		return NULL;
325146b9756SMustafa Ismail 	}
326146b9756SMustafa Ismail 
327146b9756SMustafa Ismail 	sqbuf->ah_id = cm_node->ah->ah_info.ah_idx;
328146b9756SMustafa Ismail 	buf = sqbuf->mem.va;
329146b9756SMustafa Ismail 	if (options)
330146b9756SMustafa Ismail 		opts_len = (u32)options->size;
331146b9756SMustafa Ismail 
332146b9756SMustafa Ismail 	if (hdr)
333146b9756SMustafa Ismail 		hdr_len = hdr->size;
334146b9756SMustafa Ismail 
335146b9756SMustafa Ismail 	if (pdata)
336146b9756SMustafa Ismail 		pd_len = pdata->size;
337146b9756SMustafa Ismail 
338146b9756SMustafa Ismail 	pktsize = sizeof(*tcph) + opts_len + hdr_len + pd_len;
339146b9756SMustafa Ismail 
340a2e20b29SChristophe JAILLET 	memset(buf, 0, sizeof(*tcph));
341146b9756SMustafa Ismail 
342146b9756SMustafa Ismail 	sqbuf->totallen = pktsize;
343146b9756SMustafa Ismail 	sqbuf->tcphlen = sizeof(*tcph) + opts_len;
344146b9756SMustafa Ismail 	sqbuf->scratch = cm_node;
345146b9756SMustafa Ismail 
346146b9756SMustafa Ismail 	tcph = (struct tcphdr *)buf;
347146b9756SMustafa Ismail 	buf += sizeof(*tcph);
348146b9756SMustafa Ismail 
349146b9756SMustafa Ismail 	tcph->source = htons(cm_node->loc_port);
350146b9756SMustafa Ismail 	tcph->dest = htons(cm_node->rem_port);
351146b9756SMustafa Ismail 	tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
352146b9756SMustafa Ismail 
353146b9756SMustafa Ismail 	if (flags & SET_ACK) {
354146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_ack_num = cm_node->tcp_cntxt.rcv_nxt;
355146b9756SMustafa Ismail 		tcph->ack_seq = htonl(cm_node->tcp_cntxt.loc_ack_num);
356146b9756SMustafa Ismail 		tcph->ack = 1;
357146b9756SMustafa Ismail 	} else {
358146b9756SMustafa Ismail 		tcph->ack_seq = 0;
359146b9756SMustafa Ismail 	}
360146b9756SMustafa Ismail 
361146b9756SMustafa Ismail 	if (flags & SET_SYN) {
362146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num++;
363146b9756SMustafa Ismail 		tcph->syn = 1;
364146b9756SMustafa Ismail 	} else {
365146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num += hdr_len + pd_len;
366146b9756SMustafa Ismail 	}
367146b9756SMustafa Ismail 
368146b9756SMustafa Ismail 	if (flags & SET_FIN) {
369146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num++;
370146b9756SMustafa Ismail 		tcph->fin = 1;
371146b9756SMustafa Ismail 	}
372146b9756SMustafa Ismail 
373146b9756SMustafa Ismail 	if (flags & SET_RST)
374146b9756SMustafa Ismail 		tcph->rst = 1;
375146b9756SMustafa Ismail 
376146b9756SMustafa Ismail 	tcph->doff = (u16)((sizeof(*tcph) + opts_len + 3) >> 2);
377146b9756SMustafa Ismail 	sqbuf->tcphlen = tcph->doff << 2;
378146b9756SMustafa Ismail 	tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
379146b9756SMustafa Ismail 	tcph->urg_ptr = 0;
380146b9756SMustafa Ismail 
381146b9756SMustafa Ismail 	if (opts_len) {
382146b9756SMustafa Ismail 		memcpy(buf, options->addr, opts_len);
383146b9756SMustafa Ismail 		buf += opts_len;
384146b9756SMustafa Ismail 	}
385146b9756SMustafa Ismail 
386146b9756SMustafa Ismail 	if (hdr_len) {
387146b9756SMustafa Ismail 		memcpy(buf, hdr->addr, hdr_len);
388146b9756SMustafa Ismail 		buf += hdr_len;
389146b9756SMustafa Ismail 	}
390146b9756SMustafa Ismail 
391146b9756SMustafa Ismail 	if (pdata && pdata->addr)
392146b9756SMustafa Ismail 		memcpy(buf, pdata->addr, pdata->size);
393146b9756SMustafa Ismail 
394146b9756SMustafa Ismail 	refcount_set(&sqbuf->refcount, 1);
395146b9756SMustafa Ismail 
396146b9756SMustafa Ismail 	print_hex_dump_debug("ILQ: TRANSMIT ILQ BUFFER", DUMP_PREFIX_OFFSET,
397146b9756SMustafa Ismail 			     16, 8, sqbuf->mem.va, sqbuf->totallen, false);
398146b9756SMustafa Ismail 
399146b9756SMustafa Ismail 	return sqbuf;
400146b9756SMustafa Ismail }
401146b9756SMustafa Ismail 
402146b9756SMustafa Ismail /**
403146b9756SMustafa Ismail  * irdma_form_uda_cm_frame - get a free packet and build frame full tcpip packet
404146b9756SMustafa Ismail  * @cm_node: connection's node ionfo to use in frame
405146b9756SMustafa Ismail  * @options: pointer to options info
406146b9756SMustafa Ismail  * @hdr: pointer mpa header
407146b9756SMustafa Ismail  * @pdata: pointer to private data
408146b9756SMustafa Ismail  * @flags:  indicates FIN or ACK
409146b9756SMustafa Ismail  */
irdma_form_uda_cm_frame(struct irdma_cm_node * cm_node,struct irdma_kmem_info * options,struct irdma_kmem_info * hdr,struct irdma_mpa_priv_info * pdata,u8 flags)410146b9756SMustafa Ismail static struct irdma_puda_buf *irdma_form_uda_cm_frame(struct irdma_cm_node *cm_node,
411146b9756SMustafa Ismail 						      struct irdma_kmem_info *options,
412146b9756SMustafa Ismail 						      struct irdma_kmem_info *hdr,
413146b9756SMustafa Ismail 						      struct irdma_mpa_priv_info *pdata,
414146b9756SMustafa Ismail 						      u8 flags)
415146b9756SMustafa Ismail {
416146b9756SMustafa Ismail 	struct irdma_puda_buf *sqbuf;
417146b9756SMustafa Ismail 	struct irdma_sc_vsi *vsi = &cm_node->iwdev->vsi;
418146b9756SMustafa Ismail 	u8 *buf;
419146b9756SMustafa Ismail 
420146b9756SMustafa Ismail 	struct tcphdr *tcph;
421146b9756SMustafa Ismail 	struct iphdr *iph;
422146b9756SMustafa Ismail 	struct ipv6hdr *ip6h;
423146b9756SMustafa Ismail 	struct ethhdr *ethh;
424146b9756SMustafa Ismail 	u16 pktsize;
425146b9756SMustafa Ismail 	u16 eth_hlen = ETH_HLEN;
426146b9756SMustafa Ismail 	u32 opts_len = 0;
427146b9756SMustafa Ismail 	u32 pd_len = 0;
428146b9756SMustafa Ismail 	u32 hdr_len = 0;
429146b9756SMustafa Ismail 
430146b9756SMustafa Ismail 	u16 vtag;
431146b9756SMustafa Ismail 
432146b9756SMustafa Ismail 	sqbuf = irdma_puda_get_bufpool(vsi->ilq);
433146b9756SMustafa Ismail 	if (!sqbuf)
434146b9756SMustafa Ismail 		return NULL;
435146b9756SMustafa Ismail 
436146b9756SMustafa Ismail 	buf = sqbuf->mem.va;
437146b9756SMustafa Ismail 
438146b9756SMustafa Ismail 	if (options)
439146b9756SMustafa Ismail 		opts_len = (u32)options->size;
440146b9756SMustafa Ismail 
441146b9756SMustafa Ismail 	if (hdr)
442146b9756SMustafa Ismail 		hdr_len = hdr->size;
443146b9756SMustafa Ismail 
444146b9756SMustafa Ismail 	if (pdata)
445146b9756SMustafa Ismail 		pd_len = pdata->size;
446146b9756SMustafa Ismail 
447146b9756SMustafa Ismail 	if (cm_node->vlan_id < VLAN_N_VID)
448146b9756SMustafa Ismail 		eth_hlen += 4;
449146b9756SMustafa Ismail 
450146b9756SMustafa Ismail 	if (cm_node->ipv4)
451146b9756SMustafa Ismail 		pktsize = sizeof(*iph) + sizeof(*tcph);
452146b9756SMustafa Ismail 	else
453146b9756SMustafa Ismail 		pktsize = sizeof(*ip6h) + sizeof(*tcph);
454146b9756SMustafa Ismail 	pktsize += opts_len + hdr_len + pd_len;
455146b9756SMustafa Ismail 
456146b9756SMustafa Ismail 	memset(buf, 0, eth_hlen + pktsize);
457146b9756SMustafa Ismail 
458146b9756SMustafa Ismail 	sqbuf->totallen = pktsize + eth_hlen;
459146b9756SMustafa Ismail 	sqbuf->maclen = eth_hlen;
460146b9756SMustafa Ismail 	sqbuf->tcphlen = sizeof(*tcph) + opts_len;
461146b9756SMustafa Ismail 	sqbuf->scratch = cm_node;
462146b9756SMustafa Ismail 
463146b9756SMustafa Ismail 	ethh = (struct ethhdr *)buf;
464146b9756SMustafa Ismail 	buf += eth_hlen;
465146b9756SMustafa Ismail 
466146b9756SMustafa Ismail 	if (cm_node->do_lpb)
467146b9756SMustafa Ismail 		sqbuf->do_lpb = true;
468146b9756SMustafa Ismail 
469146b9756SMustafa Ismail 	if (cm_node->ipv4) {
470146b9756SMustafa Ismail 		sqbuf->ipv4 = true;
471146b9756SMustafa Ismail 
472146b9756SMustafa Ismail 		iph = (struct iphdr *)buf;
473146b9756SMustafa Ismail 		buf += sizeof(*iph);
474146b9756SMustafa Ismail 		tcph = (struct tcphdr *)buf;
475146b9756SMustafa Ismail 		buf += sizeof(*tcph);
476146b9756SMustafa Ismail 
477146b9756SMustafa Ismail 		ether_addr_copy(ethh->h_dest, cm_node->rem_mac);
478146b9756SMustafa Ismail 		ether_addr_copy(ethh->h_source, cm_node->loc_mac);
479146b9756SMustafa Ismail 		if (cm_node->vlan_id < VLAN_N_VID) {
480146b9756SMustafa Ismail 			((struct vlan_ethhdr *)ethh)->h_vlan_proto =
481146b9756SMustafa Ismail 				htons(ETH_P_8021Q);
482146b9756SMustafa Ismail 			vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) |
483146b9756SMustafa Ismail 			       cm_node->vlan_id;
484146b9756SMustafa Ismail 			((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag);
485146b9756SMustafa Ismail 
486146b9756SMustafa Ismail 			((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto =
487146b9756SMustafa Ismail 				htons(ETH_P_IP);
488146b9756SMustafa Ismail 		} else {
489146b9756SMustafa Ismail 			ethh->h_proto = htons(ETH_P_IP);
490146b9756SMustafa Ismail 		}
491146b9756SMustafa Ismail 
492146b9756SMustafa Ismail 		iph->version = IPVERSION;
493146b9756SMustafa Ismail 		iph->ihl = 5; /* 5 * 4Byte words, IP headr len */
494146b9756SMustafa Ismail 		iph->tos = cm_node->tos;
495146b9756SMustafa Ismail 		iph->tot_len = htons(pktsize);
496146b9756SMustafa Ismail 		iph->id = htons(++cm_node->tcp_cntxt.loc_id);
497146b9756SMustafa Ismail 
498146b9756SMustafa Ismail 		iph->frag_off = htons(0x4000);
499146b9756SMustafa Ismail 		iph->ttl = 0x40;
500146b9756SMustafa Ismail 		iph->protocol = IPPROTO_TCP;
501146b9756SMustafa Ismail 		iph->saddr = htonl(cm_node->loc_addr[0]);
502146b9756SMustafa Ismail 		iph->daddr = htonl(cm_node->rem_addr[0]);
503146b9756SMustafa Ismail 	} else {
504146b9756SMustafa Ismail 		sqbuf->ipv4 = false;
505146b9756SMustafa Ismail 		ip6h = (struct ipv6hdr *)buf;
506146b9756SMustafa Ismail 		buf += sizeof(*ip6h);
507146b9756SMustafa Ismail 		tcph = (struct tcphdr *)buf;
508146b9756SMustafa Ismail 		buf += sizeof(*tcph);
509146b9756SMustafa Ismail 
510146b9756SMustafa Ismail 		ether_addr_copy(ethh->h_dest, cm_node->rem_mac);
511146b9756SMustafa Ismail 		ether_addr_copy(ethh->h_source, cm_node->loc_mac);
512146b9756SMustafa Ismail 		if (cm_node->vlan_id < VLAN_N_VID) {
513146b9756SMustafa Ismail 			((struct vlan_ethhdr *)ethh)->h_vlan_proto =
514146b9756SMustafa Ismail 				htons(ETH_P_8021Q);
515146b9756SMustafa Ismail 			vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) |
516146b9756SMustafa Ismail 			       cm_node->vlan_id;
517146b9756SMustafa Ismail 			((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag);
518146b9756SMustafa Ismail 			((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto =
519146b9756SMustafa Ismail 				htons(ETH_P_IPV6);
520146b9756SMustafa Ismail 		} else {
521146b9756SMustafa Ismail 			ethh->h_proto = htons(ETH_P_IPV6);
522146b9756SMustafa Ismail 		}
523146b9756SMustafa Ismail 		ip6h->version = 6;
524146b9756SMustafa Ismail 		ip6h->priority = cm_node->tos >> 4;
525146b9756SMustafa Ismail 		ip6h->flow_lbl[0] = cm_node->tos << 4;
526146b9756SMustafa Ismail 		ip6h->flow_lbl[1] = 0;
527146b9756SMustafa Ismail 		ip6h->flow_lbl[2] = 0;
528146b9756SMustafa Ismail 		ip6h->payload_len = htons(pktsize - sizeof(*ip6h));
529146b9756SMustafa Ismail 		ip6h->nexthdr = 6;
530146b9756SMustafa Ismail 		ip6h->hop_limit = 128;
531146b9756SMustafa Ismail 		irdma_copy_ip_htonl(ip6h->saddr.in6_u.u6_addr32,
532146b9756SMustafa Ismail 				    cm_node->loc_addr);
533146b9756SMustafa Ismail 		irdma_copy_ip_htonl(ip6h->daddr.in6_u.u6_addr32,
534146b9756SMustafa Ismail 				    cm_node->rem_addr);
535146b9756SMustafa Ismail 	}
536146b9756SMustafa Ismail 
537146b9756SMustafa Ismail 	tcph->source = htons(cm_node->loc_port);
538146b9756SMustafa Ismail 	tcph->dest = htons(cm_node->rem_port);
539146b9756SMustafa Ismail 	tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
540146b9756SMustafa Ismail 
541146b9756SMustafa Ismail 	if (flags & SET_ACK) {
542146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_ack_num = cm_node->tcp_cntxt.rcv_nxt;
543146b9756SMustafa Ismail 		tcph->ack_seq = htonl(cm_node->tcp_cntxt.loc_ack_num);
544146b9756SMustafa Ismail 		tcph->ack = 1;
545146b9756SMustafa Ismail 	} else {
546146b9756SMustafa Ismail 		tcph->ack_seq = 0;
547146b9756SMustafa Ismail 	}
548146b9756SMustafa Ismail 
549146b9756SMustafa Ismail 	if (flags & SET_SYN) {
550146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num++;
551146b9756SMustafa Ismail 		tcph->syn = 1;
552146b9756SMustafa Ismail 	} else {
553146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num += hdr_len + pd_len;
554146b9756SMustafa Ismail 	}
555146b9756SMustafa Ismail 
556146b9756SMustafa Ismail 	if (flags & SET_FIN) {
557146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num++;
558146b9756SMustafa Ismail 		tcph->fin = 1;
559146b9756SMustafa Ismail 	}
560146b9756SMustafa Ismail 
561146b9756SMustafa Ismail 	if (flags & SET_RST)
562146b9756SMustafa Ismail 		tcph->rst = 1;
563146b9756SMustafa Ismail 
564146b9756SMustafa Ismail 	tcph->doff = (u16)((sizeof(*tcph) + opts_len + 3) >> 2);
565146b9756SMustafa Ismail 	sqbuf->tcphlen = tcph->doff << 2;
566146b9756SMustafa Ismail 	tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
567146b9756SMustafa Ismail 	tcph->urg_ptr = 0;
568146b9756SMustafa Ismail 
569146b9756SMustafa Ismail 	if (opts_len) {
570146b9756SMustafa Ismail 		memcpy(buf, options->addr, opts_len);
571146b9756SMustafa Ismail 		buf += opts_len;
572146b9756SMustafa Ismail 	}
573146b9756SMustafa Ismail 
574146b9756SMustafa Ismail 	if (hdr_len) {
575146b9756SMustafa Ismail 		memcpy(buf, hdr->addr, hdr_len);
576146b9756SMustafa Ismail 		buf += hdr_len;
577146b9756SMustafa Ismail 	}
578146b9756SMustafa Ismail 
579146b9756SMustafa Ismail 	if (pdata && pdata->addr)
580146b9756SMustafa Ismail 		memcpy(buf, pdata->addr, pdata->size);
581146b9756SMustafa Ismail 
582146b9756SMustafa Ismail 	refcount_set(&sqbuf->refcount, 1);
583146b9756SMustafa Ismail 
584146b9756SMustafa Ismail 	print_hex_dump_debug("ILQ: TRANSMIT ILQ BUFFER", DUMP_PREFIX_OFFSET,
585146b9756SMustafa Ismail 			     16, 8, sqbuf->mem.va, sqbuf->totallen, false);
586146b9756SMustafa Ismail 	return sqbuf;
587146b9756SMustafa Ismail }
588146b9756SMustafa Ismail 
589146b9756SMustafa Ismail /**
590146b9756SMustafa Ismail  * irdma_send_reset - Send RST packet
591146b9756SMustafa Ismail  * @cm_node: connection's node
592146b9756SMustafa Ismail  */
irdma_send_reset(struct irdma_cm_node * cm_node)593146b9756SMustafa Ismail int irdma_send_reset(struct irdma_cm_node *cm_node)
594146b9756SMustafa Ismail {
595146b9756SMustafa Ismail 	struct irdma_puda_buf *sqbuf;
596146b9756SMustafa Ismail 	int flags = SET_RST | SET_ACK;
597146b9756SMustafa Ismail 
598146b9756SMustafa Ismail 	trace_irdma_send_reset(cm_node, 0, __builtin_return_address(0));
599146b9756SMustafa Ismail 	sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL, NULL, NULL,
600146b9756SMustafa Ismail 						flags);
601146b9756SMustafa Ismail 	if (!sqbuf)
602146b9756SMustafa Ismail 		return -ENOMEM;
603146b9756SMustafa Ismail 
604146b9756SMustafa Ismail 	ibdev_dbg(&cm_node->iwdev->ibdev,
605146b9756SMustafa Ismail 		  "CM: caller: %pS cm_node %p cm_id=%p accel=%d state=%d rem_port=0x%04x, loc_port=0x%04x rem_addr=%pI4 loc_addr=%pI4\n",
606146b9756SMustafa Ismail 		  __builtin_return_address(0), cm_node, cm_node->cm_id,
607146b9756SMustafa Ismail 		  cm_node->accelerated, cm_node->state, cm_node->rem_port,
608146b9756SMustafa Ismail 		  cm_node->loc_port, cm_node->rem_addr, cm_node->loc_addr);
609146b9756SMustafa Ismail 
610146b9756SMustafa Ismail 	return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 0,
611146b9756SMustafa Ismail 				       1);
612146b9756SMustafa Ismail }
613146b9756SMustafa Ismail 
614146b9756SMustafa Ismail /**
615146b9756SMustafa Ismail  * irdma_active_open_err - send event for active side cm error
616146b9756SMustafa Ismail  * @cm_node: connection's node
617146b9756SMustafa Ismail  * @reset: Flag to send reset or not
618146b9756SMustafa Ismail  */
irdma_active_open_err(struct irdma_cm_node * cm_node,bool reset)619146b9756SMustafa Ismail static void irdma_active_open_err(struct irdma_cm_node *cm_node, bool reset)
620146b9756SMustafa Ismail {
621146b9756SMustafa Ismail 	trace_irdma_active_open_err(cm_node, reset,
622146b9756SMustafa Ismail 				    __builtin_return_address(0));
623146b9756SMustafa Ismail 	irdma_cleanup_retrans_entry(cm_node);
624146b9756SMustafa Ismail 	cm_node->cm_core->stats_connect_errs++;
625146b9756SMustafa Ismail 	if (reset) {
626146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
627146b9756SMustafa Ismail 			  "CM: cm_node=%p state=%d\n", cm_node,
628146b9756SMustafa Ismail 			  cm_node->state);
629146b9756SMustafa Ismail 		refcount_inc(&cm_node->refcnt);
630146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
631146b9756SMustafa Ismail 	}
632146b9756SMustafa Ismail 
633146b9756SMustafa Ismail 	cm_node->state = IRDMA_CM_STATE_CLOSED;
634146b9756SMustafa Ismail 	irdma_create_event(cm_node, IRDMA_CM_EVENT_ABORTED);
635146b9756SMustafa Ismail }
636146b9756SMustafa Ismail 
637146b9756SMustafa Ismail /**
638146b9756SMustafa Ismail  * irdma_passive_open_err - handle passive side cm error
639146b9756SMustafa Ismail  * @cm_node: connection's node
640146b9756SMustafa Ismail  * @reset: send reset or just free cm_node
641146b9756SMustafa Ismail  */
irdma_passive_open_err(struct irdma_cm_node * cm_node,bool reset)642146b9756SMustafa Ismail static void irdma_passive_open_err(struct irdma_cm_node *cm_node, bool reset)
643146b9756SMustafa Ismail {
644146b9756SMustafa Ismail 	irdma_cleanup_retrans_entry(cm_node);
645146b9756SMustafa Ismail 	cm_node->cm_core->stats_passive_errs++;
646146b9756SMustafa Ismail 	cm_node->state = IRDMA_CM_STATE_CLOSED;
647146b9756SMustafa Ismail 	ibdev_dbg(&cm_node->iwdev->ibdev, "CM: cm_node=%p state =%d\n",
648146b9756SMustafa Ismail 		  cm_node, cm_node->state);
649146b9756SMustafa Ismail 	trace_irdma_passive_open_err(cm_node, reset,
650146b9756SMustafa Ismail 				     __builtin_return_address(0));
651146b9756SMustafa Ismail 	if (reset)
652146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
653146b9756SMustafa Ismail 	else
654146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
655146b9756SMustafa Ismail }
656146b9756SMustafa Ismail 
657146b9756SMustafa Ismail /**
658146b9756SMustafa Ismail  * irdma_event_connect_error - to create connect error event
659146b9756SMustafa Ismail  * @event: cm information for connect event
660146b9756SMustafa Ismail  */
irdma_event_connect_error(struct irdma_cm_event * event)661146b9756SMustafa Ismail static void irdma_event_connect_error(struct irdma_cm_event *event)
662146b9756SMustafa Ismail {
663146b9756SMustafa Ismail 	struct irdma_qp *iwqp;
664146b9756SMustafa Ismail 	struct iw_cm_id *cm_id;
665146b9756SMustafa Ismail 
666146b9756SMustafa Ismail 	cm_id = event->cm_node->cm_id;
667146b9756SMustafa Ismail 	if (!cm_id)
668146b9756SMustafa Ismail 		return;
669146b9756SMustafa Ismail 
670146b9756SMustafa Ismail 	iwqp = cm_id->provider_data;
671146b9756SMustafa Ismail 
672146b9756SMustafa Ismail 	if (!iwqp || !iwqp->iwdev)
673146b9756SMustafa Ismail 		return;
674146b9756SMustafa Ismail 
675146b9756SMustafa Ismail 	iwqp->cm_id = NULL;
676146b9756SMustafa Ismail 	cm_id->provider_data = NULL;
677146b9756SMustafa Ismail 	irdma_send_cm_event(event->cm_node, cm_id, IW_CM_EVENT_CONNECT_REPLY,
678146b9756SMustafa Ismail 			    -ECONNRESET);
679146b9756SMustafa Ismail 	irdma_rem_ref_cm_node(event->cm_node);
680146b9756SMustafa Ismail }
681146b9756SMustafa Ismail 
682146b9756SMustafa Ismail /**
683146b9756SMustafa Ismail  * irdma_process_options - process options from TCP header
684146b9756SMustafa Ismail  * @cm_node: connection's node
685146b9756SMustafa Ismail  * @optionsloc: point to start of options
686146b9756SMustafa Ismail  * @optionsize: size of all options
687146b9756SMustafa Ismail  * @syn_pkt: flag if syn packet
688146b9756SMustafa Ismail  */
irdma_process_options(struct irdma_cm_node * cm_node,u8 * optionsloc,u32 optionsize,u32 syn_pkt)689146b9756SMustafa Ismail static int irdma_process_options(struct irdma_cm_node *cm_node, u8 *optionsloc,
690146b9756SMustafa Ismail 				 u32 optionsize, u32 syn_pkt)
691146b9756SMustafa Ismail {
692146b9756SMustafa Ismail 	u32 tmp;
693146b9756SMustafa Ismail 	u32 offset = 0;
694146b9756SMustafa Ismail 	union all_known_options *all_options;
695146b9756SMustafa Ismail 	char got_mss_option = 0;
696146b9756SMustafa Ismail 
697146b9756SMustafa Ismail 	while (offset < optionsize) {
698146b9756SMustafa Ismail 		all_options = (union all_known_options *)(optionsloc + offset);
699146b9756SMustafa Ismail 		switch (all_options->base.optionnum) {
700146b9756SMustafa Ismail 		case OPTION_NUM_EOL:
701146b9756SMustafa Ismail 			offset = optionsize;
702146b9756SMustafa Ismail 			break;
703146b9756SMustafa Ismail 		case OPTION_NUM_NONE:
704146b9756SMustafa Ismail 			offset += 1;
705146b9756SMustafa Ismail 			continue;
706146b9756SMustafa Ismail 		case OPTION_NUM_MSS:
707146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
708146b9756SMustafa Ismail 				  "CM: MSS Length: %d Offset: %d Size: %d\n",
709146b9756SMustafa Ismail 				  all_options->mss.len, offset, optionsize);
710146b9756SMustafa Ismail 			got_mss_option = 1;
711146b9756SMustafa Ismail 			if (all_options->mss.len != 4)
712146b9756SMustafa Ismail 				return -EINVAL;
713146b9756SMustafa Ismail 			tmp = ntohs(all_options->mss.mss);
714146b9756SMustafa Ismail 			if ((cm_node->ipv4 &&
715146b9756SMustafa Ismail 			     (tmp + IRDMA_MTU_TO_MSS_IPV4) < IRDMA_MIN_MTU_IPV4) ||
716146b9756SMustafa Ismail 			    (!cm_node->ipv4 &&
717146b9756SMustafa Ismail 			     (tmp + IRDMA_MTU_TO_MSS_IPV6) < IRDMA_MIN_MTU_IPV6))
718146b9756SMustafa Ismail 				return -EINVAL;
719146b9756SMustafa Ismail 			if (tmp < cm_node->tcp_cntxt.mss)
720146b9756SMustafa Ismail 				cm_node->tcp_cntxt.mss = tmp;
721146b9756SMustafa Ismail 			break;
722146b9756SMustafa Ismail 		case OPTION_NUM_WINDOW_SCALE:
723146b9756SMustafa Ismail 			cm_node->tcp_cntxt.snd_wscale =
724146b9756SMustafa Ismail 				all_options->windowscale.shiftcount;
725146b9756SMustafa Ismail 			break;
726146b9756SMustafa Ismail 		default:
727146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
728146b9756SMustafa Ismail 				  "CM: Unsupported TCP Option: %x\n",
729146b9756SMustafa Ismail 				  all_options->base.optionnum);
730146b9756SMustafa Ismail 			break;
731146b9756SMustafa Ismail 		}
732146b9756SMustafa Ismail 		offset += all_options->base.len;
733146b9756SMustafa Ismail 	}
734146b9756SMustafa Ismail 	if (!got_mss_option && syn_pkt)
735146b9756SMustafa Ismail 		cm_node->tcp_cntxt.mss = IRDMA_CM_DEFAULT_MSS;
736146b9756SMustafa Ismail 
737146b9756SMustafa Ismail 	return 0;
738146b9756SMustafa Ismail }
739146b9756SMustafa Ismail 
740146b9756SMustafa Ismail /**
741146b9756SMustafa Ismail  * irdma_handle_tcp_options - setup TCP context info after parsing TCP options
742146b9756SMustafa Ismail  * @cm_node: connection's node
743146b9756SMustafa Ismail  * @tcph: pointer tcp header
744146b9756SMustafa Ismail  * @optionsize: size of options rcvd
745146b9756SMustafa Ismail  * @passive: active or passive flag
746146b9756SMustafa Ismail  */
irdma_handle_tcp_options(struct irdma_cm_node * cm_node,struct tcphdr * tcph,int optionsize,int passive)747146b9756SMustafa Ismail static int irdma_handle_tcp_options(struct irdma_cm_node *cm_node,
748146b9756SMustafa Ismail 				    struct tcphdr *tcph, int optionsize,
749146b9756SMustafa Ismail 				    int passive)
750146b9756SMustafa Ismail {
751146b9756SMustafa Ismail 	u8 *optionsloc = (u8 *)&tcph[1];
752146b9756SMustafa Ismail 	int ret;
753146b9756SMustafa Ismail 
754146b9756SMustafa Ismail 	if (optionsize) {
755146b9756SMustafa Ismail 		ret = irdma_process_options(cm_node, optionsloc, optionsize,
756146b9756SMustafa Ismail 					    (u32)tcph->syn);
757146b9756SMustafa Ismail 		if (ret) {
758146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
759146b9756SMustafa Ismail 				  "CM: Node %p, Sending Reset\n", cm_node);
760146b9756SMustafa Ismail 			if (passive)
761146b9756SMustafa Ismail 				irdma_passive_open_err(cm_node, true);
762146b9756SMustafa Ismail 			else
763146b9756SMustafa Ismail 				irdma_active_open_err(cm_node, true);
764146b9756SMustafa Ismail 			return ret;
765146b9756SMustafa Ismail 		}
766146b9756SMustafa Ismail 	}
767146b9756SMustafa Ismail 
768146b9756SMustafa Ismail 	cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window)
769146b9756SMustafa Ismail 				     << cm_node->tcp_cntxt.snd_wscale;
770146b9756SMustafa Ismail 
771146b9756SMustafa Ismail 	if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd)
772146b9756SMustafa Ismail 		cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;
773146b9756SMustafa Ismail 
774146b9756SMustafa Ismail 	return 0;
775146b9756SMustafa Ismail }
776146b9756SMustafa Ismail 
777146b9756SMustafa Ismail /**
778146b9756SMustafa Ismail  * irdma_build_mpa_v1 - build a MPA V1 frame
779146b9756SMustafa Ismail  * @cm_node: connection's node
780146b9756SMustafa Ismail  * @start_addr: address where to build frame
781146b9756SMustafa Ismail  * @mpa_key: to do read0 or write0
782146b9756SMustafa Ismail  */
irdma_build_mpa_v1(struct irdma_cm_node * cm_node,void * start_addr,u8 mpa_key)783146b9756SMustafa Ismail static void irdma_build_mpa_v1(struct irdma_cm_node *cm_node, void *start_addr,
784146b9756SMustafa Ismail 			       u8 mpa_key)
785146b9756SMustafa Ismail {
786146b9756SMustafa Ismail 	struct ietf_mpa_v1 *mpa_frame = start_addr;
787146b9756SMustafa Ismail 
788146b9756SMustafa Ismail 	switch (mpa_key) {
789146b9756SMustafa Ismail 	case MPA_KEY_REQUEST:
790146b9756SMustafa Ismail 		memcpy(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE);
791146b9756SMustafa Ismail 		break;
792146b9756SMustafa Ismail 	case MPA_KEY_REPLY:
793146b9756SMustafa Ismail 		memcpy(mpa_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
794146b9756SMustafa Ismail 		break;
795146b9756SMustafa Ismail 	default:
796146b9756SMustafa Ismail 		break;
797146b9756SMustafa Ismail 	}
798146b9756SMustafa Ismail 	mpa_frame->flags = IETF_MPA_FLAGS_CRC;
799146b9756SMustafa Ismail 	mpa_frame->rev = cm_node->mpa_frame_rev;
800146b9756SMustafa Ismail 	mpa_frame->priv_data_len = htons(cm_node->pdata.size);
801146b9756SMustafa Ismail }
802146b9756SMustafa Ismail 
803146b9756SMustafa Ismail /**
804146b9756SMustafa Ismail  * irdma_build_mpa_v2 - build a MPA V2 frame
805146b9756SMustafa Ismail  * @cm_node: connection's node
806146b9756SMustafa Ismail  * @start_addr: buffer start address
807146b9756SMustafa Ismail  * @mpa_key: to do read0 or write0
808146b9756SMustafa Ismail  */
irdma_build_mpa_v2(struct irdma_cm_node * cm_node,void * start_addr,u8 mpa_key)809146b9756SMustafa Ismail static void irdma_build_mpa_v2(struct irdma_cm_node *cm_node, void *start_addr,
810146b9756SMustafa Ismail 			       u8 mpa_key)
811146b9756SMustafa Ismail {
812146b9756SMustafa Ismail 	struct ietf_mpa_v2 *mpa_frame = start_addr;
813146b9756SMustafa Ismail 	struct ietf_rtr_msg *rtr_msg = &mpa_frame->rtr_msg;
814146b9756SMustafa Ismail 	u16 ctrl_ird, ctrl_ord;
815146b9756SMustafa Ismail 
816146b9756SMustafa Ismail 	/* initialize the upper 5 bytes of the frame */
817146b9756SMustafa Ismail 	irdma_build_mpa_v1(cm_node, start_addr, mpa_key);
818146b9756SMustafa Ismail 	mpa_frame->flags |= IETF_MPA_V2_FLAG;
819146b9756SMustafa Ismail 	if (cm_node->iwdev->iw_ooo) {
820146b9756SMustafa Ismail 		mpa_frame->flags |= IETF_MPA_FLAGS_MARKERS;
821146b9756SMustafa Ismail 		cm_node->rcv_mark_en = true;
822146b9756SMustafa Ismail 	}
823146b9756SMustafa Ismail 	mpa_frame->priv_data_len = cpu_to_be16(be16_to_cpu(mpa_frame->priv_data_len) +
824146b9756SMustafa Ismail 					       IETF_RTR_MSG_SIZE);
825146b9756SMustafa Ismail 
826146b9756SMustafa Ismail 	/* initialize RTR msg */
827146b9756SMustafa Ismail 	if (cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) {
828146b9756SMustafa Ismail 		ctrl_ird = IETF_NO_IRD_ORD;
829146b9756SMustafa Ismail 		ctrl_ord = IETF_NO_IRD_ORD;
830146b9756SMustafa Ismail 	} else {
831146b9756SMustafa Ismail 		ctrl_ird = (cm_node->ird_size > IETF_NO_IRD_ORD) ?
832146b9756SMustafa Ismail 				   IETF_NO_IRD_ORD :
833146b9756SMustafa Ismail 				   cm_node->ird_size;
834146b9756SMustafa Ismail 		ctrl_ord = (cm_node->ord_size > IETF_NO_IRD_ORD) ?
835146b9756SMustafa Ismail 				   IETF_NO_IRD_ORD :
836146b9756SMustafa Ismail 				   cm_node->ord_size;
837146b9756SMustafa Ismail 	}
838146b9756SMustafa Ismail 	ctrl_ird |= IETF_PEER_TO_PEER;
839146b9756SMustafa Ismail 
840146b9756SMustafa Ismail 	switch (mpa_key) {
841146b9756SMustafa Ismail 	case MPA_KEY_REQUEST:
842146b9756SMustafa Ismail 		ctrl_ord |= IETF_RDMA0_WRITE;
843146b9756SMustafa Ismail 		ctrl_ord |= IETF_RDMA0_READ;
844146b9756SMustafa Ismail 		break;
845146b9756SMustafa Ismail 	case MPA_KEY_REPLY:
846146b9756SMustafa Ismail 		switch (cm_node->send_rdma0_op) {
847146b9756SMustafa Ismail 		case SEND_RDMA_WRITE_ZERO:
848146b9756SMustafa Ismail 			ctrl_ord |= IETF_RDMA0_WRITE;
849146b9756SMustafa Ismail 			break;
850146b9756SMustafa Ismail 		case SEND_RDMA_READ_ZERO:
851146b9756SMustafa Ismail 			ctrl_ord |= IETF_RDMA0_READ;
852146b9756SMustafa Ismail 			break;
853146b9756SMustafa Ismail 		}
854146b9756SMustafa Ismail 		break;
855146b9756SMustafa Ismail 	default:
856146b9756SMustafa Ismail 		break;
857146b9756SMustafa Ismail 	}
858146b9756SMustafa Ismail 	rtr_msg->ctrl_ird = htons(ctrl_ird);
859146b9756SMustafa Ismail 	rtr_msg->ctrl_ord = htons(ctrl_ord);
860146b9756SMustafa Ismail }
861146b9756SMustafa Ismail 
862146b9756SMustafa Ismail /**
863146b9756SMustafa Ismail  * irdma_cm_build_mpa_frame - build mpa frame for mpa version 1 or version 2
864146b9756SMustafa Ismail  * @cm_node: connection's node
865146b9756SMustafa Ismail  * @mpa: mpa: data buffer
866146b9756SMustafa Ismail  * @mpa_key: to do read0 or write0
867146b9756SMustafa Ismail  */
irdma_cm_build_mpa_frame(struct irdma_cm_node * cm_node,struct irdma_kmem_info * mpa,u8 mpa_key)868146b9756SMustafa Ismail static int irdma_cm_build_mpa_frame(struct irdma_cm_node *cm_node,
869146b9756SMustafa Ismail 				    struct irdma_kmem_info *mpa, u8 mpa_key)
870146b9756SMustafa Ismail {
871146b9756SMustafa Ismail 	int hdr_len = 0;
872146b9756SMustafa Ismail 
873146b9756SMustafa Ismail 	switch (cm_node->mpa_frame_rev) {
874146b9756SMustafa Ismail 	case IETF_MPA_V1:
875146b9756SMustafa Ismail 		hdr_len = sizeof(struct ietf_mpa_v1);
876146b9756SMustafa Ismail 		irdma_build_mpa_v1(cm_node, mpa->addr, mpa_key);
877146b9756SMustafa Ismail 		break;
878146b9756SMustafa Ismail 	case IETF_MPA_V2:
879146b9756SMustafa Ismail 		hdr_len = sizeof(struct ietf_mpa_v2);
880146b9756SMustafa Ismail 		irdma_build_mpa_v2(cm_node, mpa->addr, mpa_key);
881146b9756SMustafa Ismail 		break;
882146b9756SMustafa Ismail 	default:
883146b9756SMustafa Ismail 		break;
884146b9756SMustafa Ismail 	}
885146b9756SMustafa Ismail 
886146b9756SMustafa Ismail 	return hdr_len;
887146b9756SMustafa Ismail }
888146b9756SMustafa Ismail 
889146b9756SMustafa Ismail /**
890146b9756SMustafa Ismail  * irdma_send_mpa_request - active node send mpa request to passive node
891146b9756SMustafa Ismail  * @cm_node: connection's node
892146b9756SMustafa Ismail  */
irdma_send_mpa_request(struct irdma_cm_node * cm_node)893146b9756SMustafa Ismail static int irdma_send_mpa_request(struct irdma_cm_node *cm_node)
894146b9756SMustafa Ismail {
895146b9756SMustafa Ismail 	struct irdma_puda_buf *sqbuf;
896146b9756SMustafa Ismail 
897146b9756SMustafa Ismail 	cm_node->mpa_hdr.addr = &cm_node->mpa_v2_frame;
898146b9756SMustafa Ismail 	cm_node->mpa_hdr.size = irdma_cm_build_mpa_frame(cm_node,
899146b9756SMustafa Ismail 							 &cm_node->mpa_hdr,
900146b9756SMustafa Ismail 							 MPA_KEY_REQUEST);
901146b9756SMustafa Ismail 	if (!cm_node->mpa_hdr.size) {
902146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
903146b9756SMustafa Ismail 			  "CM: mpa size = %d\n", cm_node->mpa_hdr.size);
904146b9756SMustafa Ismail 		return -EINVAL;
905146b9756SMustafa Ismail 	}
906146b9756SMustafa Ismail 
907146b9756SMustafa Ismail 	sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL,
908146b9756SMustafa Ismail 						&cm_node->mpa_hdr,
909146b9756SMustafa Ismail 						&cm_node->pdata, SET_ACK);
910146b9756SMustafa Ismail 	if (!sqbuf)
911146b9756SMustafa Ismail 		return -ENOMEM;
912146b9756SMustafa Ismail 
913146b9756SMustafa Ismail 	return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 1,
914146b9756SMustafa Ismail 				       0);
915146b9756SMustafa Ismail }
916146b9756SMustafa Ismail 
917146b9756SMustafa Ismail /**
918146b9756SMustafa Ismail  * irdma_send_mpa_reject -
919146b9756SMustafa Ismail  * @cm_node: connection's node
920146b9756SMustafa Ismail  * @pdata: reject data for connection
921146b9756SMustafa Ismail  * @plen: length of reject data
922146b9756SMustafa Ismail  */
irdma_send_mpa_reject(struct irdma_cm_node * cm_node,const void * pdata,u8 plen)923146b9756SMustafa Ismail static int irdma_send_mpa_reject(struct irdma_cm_node *cm_node,
924146b9756SMustafa Ismail 				 const void *pdata, u8 plen)
925146b9756SMustafa Ismail {
926146b9756SMustafa Ismail 	struct irdma_puda_buf *sqbuf;
927146b9756SMustafa Ismail 	struct irdma_mpa_priv_info priv_info;
928146b9756SMustafa Ismail 
929146b9756SMustafa Ismail 	cm_node->mpa_hdr.addr = &cm_node->mpa_v2_frame;
930146b9756SMustafa Ismail 	cm_node->mpa_hdr.size = irdma_cm_build_mpa_frame(cm_node,
931146b9756SMustafa Ismail 							 &cm_node->mpa_hdr,
932146b9756SMustafa Ismail 							 MPA_KEY_REPLY);
933146b9756SMustafa Ismail 
934146b9756SMustafa Ismail 	cm_node->mpa_frame.flags |= IETF_MPA_FLAGS_REJECT;
935146b9756SMustafa Ismail 	priv_info.addr = pdata;
936146b9756SMustafa Ismail 	priv_info.size = plen;
937146b9756SMustafa Ismail 
938146b9756SMustafa Ismail 	sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL,
939146b9756SMustafa Ismail 						&cm_node->mpa_hdr, &priv_info,
940146b9756SMustafa Ismail 						SET_ACK | SET_FIN);
941146b9756SMustafa Ismail 	if (!sqbuf)
942146b9756SMustafa Ismail 		return -ENOMEM;
943146b9756SMustafa Ismail 
944146b9756SMustafa Ismail 	cm_node->state = IRDMA_CM_STATE_FIN_WAIT1;
945146b9756SMustafa Ismail 
946146b9756SMustafa Ismail 	return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 1,
947146b9756SMustafa Ismail 				       0);
948146b9756SMustafa Ismail }
949146b9756SMustafa Ismail 
950146b9756SMustafa Ismail /**
951146b9756SMustafa Ismail  * irdma_negotiate_mpa_v2_ird_ord - negotiate MPAv2 IRD/ORD
952146b9756SMustafa Ismail  * @cm_node: connection's node
953146b9756SMustafa Ismail  * @buf: Data pointer
954146b9756SMustafa Ismail  */
irdma_negotiate_mpa_v2_ird_ord(struct irdma_cm_node * cm_node,u8 * buf)955146b9756SMustafa Ismail static int irdma_negotiate_mpa_v2_ird_ord(struct irdma_cm_node *cm_node,
956146b9756SMustafa Ismail 					  u8 *buf)
957146b9756SMustafa Ismail {
958146b9756SMustafa Ismail 	struct ietf_mpa_v2 *mpa_v2_frame;
959146b9756SMustafa Ismail 	struct ietf_rtr_msg *rtr_msg;
960146b9756SMustafa Ismail 	u16 ird_size;
961146b9756SMustafa Ismail 	u16 ord_size;
962146b9756SMustafa Ismail 	u16 ctrl_ord;
963146b9756SMustafa Ismail 	u16 ctrl_ird;
964146b9756SMustafa Ismail 
965146b9756SMustafa Ismail 	mpa_v2_frame = (struct ietf_mpa_v2 *)buf;
966146b9756SMustafa Ismail 	rtr_msg = &mpa_v2_frame->rtr_msg;
967146b9756SMustafa Ismail 
968146b9756SMustafa Ismail 	/* parse rtr message */
969146b9756SMustafa Ismail 	ctrl_ord = ntohs(rtr_msg->ctrl_ord);
970146b9756SMustafa Ismail 	ctrl_ird = ntohs(rtr_msg->ctrl_ird);
971146b9756SMustafa Ismail 	ird_size = ctrl_ird & IETF_NO_IRD_ORD;
972146b9756SMustafa Ismail 	ord_size = ctrl_ord & IETF_NO_IRD_ORD;
973146b9756SMustafa Ismail 
974146b9756SMustafa Ismail 	if (!(ctrl_ird & IETF_PEER_TO_PEER))
975146b9756SMustafa Ismail 		return -EOPNOTSUPP;
976146b9756SMustafa Ismail 
977146b9756SMustafa Ismail 	if (ird_size == IETF_NO_IRD_ORD || ord_size == IETF_NO_IRD_ORD) {
978146b9756SMustafa Ismail 		cm_node->mpav2_ird_ord = IETF_NO_IRD_ORD;
979146b9756SMustafa Ismail 		goto negotiate_done;
980146b9756SMustafa Ismail 	}
981146b9756SMustafa Ismail 
982146b9756SMustafa Ismail 	if (cm_node->state != IRDMA_CM_STATE_MPAREQ_SENT) {
983146b9756SMustafa Ismail 		/* responder */
984146b9756SMustafa Ismail 		if (!ord_size && (ctrl_ord & IETF_RDMA0_READ))
985146b9756SMustafa Ismail 			cm_node->ird_size = 1;
986146b9756SMustafa Ismail 		if (cm_node->ord_size > ird_size)
987146b9756SMustafa Ismail 			cm_node->ord_size = ird_size;
988146b9756SMustafa Ismail 	} else {
989146b9756SMustafa Ismail 		/* initiator */
990146b9756SMustafa Ismail 		if (!ird_size && (ctrl_ord & IETF_RDMA0_READ))
991146b9756SMustafa Ismail 			/* Remote peer doesn't support RDMA0_READ */
992146b9756SMustafa Ismail 			return -EOPNOTSUPP;
993146b9756SMustafa Ismail 
994146b9756SMustafa Ismail 		if (cm_node->ord_size > ird_size)
995146b9756SMustafa Ismail 			cm_node->ord_size = ird_size;
996146b9756SMustafa Ismail 
997146b9756SMustafa Ismail 		if (cm_node->ird_size < ord_size)
998146b9756SMustafa Ismail 		/* no resources available */
999146b9756SMustafa Ismail 			return -EINVAL;
1000146b9756SMustafa Ismail 	}
1001146b9756SMustafa Ismail 
1002146b9756SMustafa Ismail negotiate_done:
1003146b9756SMustafa Ismail 	if (ctrl_ord & IETF_RDMA0_READ)
1004146b9756SMustafa Ismail 		cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
1005146b9756SMustafa Ismail 	else if (ctrl_ord & IETF_RDMA0_WRITE)
1006146b9756SMustafa Ismail 		cm_node->send_rdma0_op = SEND_RDMA_WRITE_ZERO;
1007146b9756SMustafa Ismail 	else
1008146b9756SMustafa Ismail 		/* Not supported RDMA0 operation */
1009146b9756SMustafa Ismail 		return -EOPNOTSUPP;
1010146b9756SMustafa Ismail 
1011146b9756SMustafa Ismail 	ibdev_dbg(&cm_node->iwdev->ibdev,
1012146b9756SMustafa Ismail 		  "CM: MPAV2 Negotiated ORD: %d, IRD: %d\n",
1013146b9756SMustafa Ismail 		  cm_node->ord_size, cm_node->ird_size);
1014146b9756SMustafa Ismail 	trace_irdma_negotiate_mpa_v2(cm_node);
1015146b9756SMustafa Ismail 	return 0;
1016146b9756SMustafa Ismail }
1017146b9756SMustafa Ismail 
1018146b9756SMustafa Ismail /**
1019146b9756SMustafa Ismail  * irdma_parse_mpa - process an IETF MPA frame
1020146b9756SMustafa Ismail  * @cm_node: connection's node
1021146b9756SMustafa Ismail  * @buf: Data pointer
1022146b9756SMustafa Ismail  * @type: to return accept or reject
1023146b9756SMustafa Ismail  * @len: Len of mpa buffer
1024146b9756SMustafa Ismail  */
irdma_parse_mpa(struct irdma_cm_node * cm_node,u8 * buf,u32 * type,u32 len)1025146b9756SMustafa Ismail static int irdma_parse_mpa(struct irdma_cm_node *cm_node, u8 *buf, u32 *type,
1026146b9756SMustafa Ismail 			   u32 len)
1027146b9756SMustafa Ismail {
1028146b9756SMustafa Ismail 	struct ietf_mpa_v1 *mpa_frame;
1029146b9756SMustafa Ismail 	int mpa_hdr_len, priv_data_len, ret;
1030146b9756SMustafa Ismail 
1031146b9756SMustafa Ismail 	*type = IRDMA_MPA_REQUEST_ACCEPT;
1032146b9756SMustafa Ismail 
1033146b9756SMustafa Ismail 	if (len < sizeof(struct ietf_mpa_v1)) {
1034146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
1035146b9756SMustafa Ismail 			  "CM: ietf buffer small (%x)\n", len);
1036146b9756SMustafa Ismail 		return -EINVAL;
1037146b9756SMustafa Ismail 	}
1038146b9756SMustafa Ismail 
1039146b9756SMustafa Ismail 	mpa_frame = (struct ietf_mpa_v1 *)buf;
1040146b9756SMustafa Ismail 	mpa_hdr_len = sizeof(struct ietf_mpa_v1);
1041146b9756SMustafa Ismail 	priv_data_len = ntohs(mpa_frame->priv_data_len);
1042146b9756SMustafa Ismail 
1043146b9756SMustafa Ismail 	if (priv_data_len > IETF_MAX_PRIV_DATA_LEN) {
1044146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
1045146b9756SMustafa Ismail 			  "CM: private_data too big %d\n", priv_data_len);
1046146b9756SMustafa Ismail 		return -EOVERFLOW;
1047146b9756SMustafa Ismail 	}
1048146b9756SMustafa Ismail 
1049146b9756SMustafa Ismail 	if (mpa_frame->rev != IETF_MPA_V1 && mpa_frame->rev != IETF_MPA_V2) {
1050146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
1051146b9756SMustafa Ismail 			  "CM: unsupported mpa rev = %d\n", mpa_frame->rev);
1052146b9756SMustafa Ismail 		return -EINVAL;
1053146b9756SMustafa Ismail 	}
1054146b9756SMustafa Ismail 
1055146b9756SMustafa Ismail 	if (mpa_frame->rev > cm_node->mpa_frame_rev) {
1056146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev, "CM: rev %d\n",
1057146b9756SMustafa Ismail 			  mpa_frame->rev);
1058146b9756SMustafa Ismail 		return -EINVAL;
1059146b9756SMustafa Ismail 	}
1060146b9756SMustafa Ismail 
1061146b9756SMustafa Ismail 	cm_node->mpa_frame_rev = mpa_frame->rev;
1062146b9756SMustafa Ismail 	if (cm_node->state != IRDMA_CM_STATE_MPAREQ_SENT) {
1063146b9756SMustafa Ismail 		if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REQ,
1064146b9756SMustafa Ismail 			   IETF_MPA_KEY_SIZE)) {
1065146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
1066146b9756SMustafa Ismail 				  "CM: Unexpected MPA Key received\n");
1067146b9756SMustafa Ismail 			return -EINVAL;
1068146b9756SMustafa Ismail 		}
1069146b9756SMustafa Ismail 	} else {
1070146b9756SMustafa Ismail 		if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REP,
1071146b9756SMustafa Ismail 			   IETF_MPA_KEY_SIZE)) {
1072146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
1073146b9756SMustafa Ismail 				  "CM: Unexpected MPA Key received\n");
1074146b9756SMustafa Ismail 			return -EINVAL;
1075146b9756SMustafa Ismail 		}
1076146b9756SMustafa Ismail 	}
1077146b9756SMustafa Ismail 
1078146b9756SMustafa Ismail 	if (priv_data_len + mpa_hdr_len > len) {
1079146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
1080146b9756SMustafa Ismail 			  "CM: ietf buffer len(%x + %x != %x)\n",
1081146b9756SMustafa Ismail 			  priv_data_len, mpa_hdr_len, len);
1082146b9756SMustafa Ismail 		return -EOVERFLOW;
1083146b9756SMustafa Ismail 	}
1084146b9756SMustafa Ismail 
1085146b9756SMustafa Ismail 	if (len > IRDMA_MAX_CM_BUF) {
1086146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
1087146b9756SMustafa Ismail 			  "CM: ietf buffer large len = %d\n", len);
1088146b9756SMustafa Ismail 		return -EOVERFLOW;
1089146b9756SMustafa Ismail 	}
1090146b9756SMustafa Ismail 
1091146b9756SMustafa Ismail 	switch (mpa_frame->rev) {
1092146b9756SMustafa Ismail 	case IETF_MPA_V2:
1093146b9756SMustafa Ismail 		mpa_hdr_len += IETF_RTR_MSG_SIZE;
1094146b9756SMustafa Ismail 		ret = irdma_negotiate_mpa_v2_ird_ord(cm_node, buf);
1095146b9756SMustafa Ismail 		if (ret)
1096146b9756SMustafa Ismail 			return ret;
1097146b9756SMustafa Ismail 		break;
1098146b9756SMustafa Ismail 	case IETF_MPA_V1:
1099146b9756SMustafa Ismail 	default:
1100146b9756SMustafa Ismail 		break;
1101146b9756SMustafa Ismail 	}
1102146b9756SMustafa Ismail 
1103146b9756SMustafa Ismail 	memcpy(cm_node->pdata_buf, buf + mpa_hdr_len, priv_data_len);
1104146b9756SMustafa Ismail 	cm_node->pdata.size = priv_data_len;
1105146b9756SMustafa Ismail 
1106146b9756SMustafa Ismail 	if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)
1107146b9756SMustafa Ismail 		*type = IRDMA_MPA_REQUEST_REJECT;
1108146b9756SMustafa Ismail 
1109146b9756SMustafa Ismail 	if (mpa_frame->flags & IETF_MPA_FLAGS_MARKERS)
1110146b9756SMustafa Ismail 		cm_node->snd_mark_en = true;
1111146b9756SMustafa Ismail 
1112146b9756SMustafa Ismail 	return 0;
1113146b9756SMustafa Ismail }
1114146b9756SMustafa Ismail 
1115146b9756SMustafa Ismail /**
1116146b9756SMustafa Ismail  * irdma_schedule_cm_timer
1117146b9756SMustafa Ismail  * @cm_node: connection's node
1118146b9756SMustafa Ismail  * @sqbuf: buffer to send
1119146b9756SMustafa Ismail  * @type: if it is send or close
1120146b9756SMustafa Ismail  * @send_retrans: if rexmits to be done
1121146b9756SMustafa Ismail  * @close_when_complete: is cm_node to be removed
1122146b9756SMustafa Ismail  *
1123146b9756SMustafa Ismail  * note - cm_node needs to be protected before calling this. Encase in:
1124146b9756SMustafa Ismail  *		irdma_rem_ref_cm_node(cm_core, cm_node);
1125146b9756SMustafa Ismail  *		irdma_schedule_cm_timer(...)
1126146b9756SMustafa Ismail  *		refcount_inc(&cm_node->refcnt);
1127146b9756SMustafa Ismail  */
irdma_schedule_cm_timer(struct irdma_cm_node * cm_node,struct irdma_puda_buf * sqbuf,enum irdma_timer_type type,int send_retrans,int close_when_complete)1128146b9756SMustafa Ismail int irdma_schedule_cm_timer(struct irdma_cm_node *cm_node,
1129146b9756SMustafa Ismail 			    struct irdma_puda_buf *sqbuf,
1130146b9756SMustafa Ismail 			    enum irdma_timer_type type, int send_retrans,
1131146b9756SMustafa Ismail 			    int close_when_complete)
1132146b9756SMustafa Ismail {
1133146b9756SMustafa Ismail 	struct irdma_sc_vsi *vsi = &cm_node->iwdev->vsi;
1134146b9756SMustafa Ismail 	struct irdma_cm_core *cm_core = cm_node->cm_core;
1135146b9756SMustafa Ismail 	struct irdma_timer_entry *new_send;
1136146b9756SMustafa Ismail 	u32 was_timer_set;
1137146b9756SMustafa Ismail 	unsigned long flags;
1138146b9756SMustafa Ismail 
1139146b9756SMustafa Ismail 	new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
1140146b9756SMustafa Ismail 	if (!new_send) {
1141146b9756SMustafa Ismail 		if (type != IRDMA_TIMER_TYPE_CLOSE)
1142146b9756SMustafa Ismail 			irdma_free_sqbuf(vsi, sqbuf);
1143146b9756SMustafa Ismail 		return -ENOMEM;
1144146b9756SMustafa Ismail 	}
1145146b9756SMustafa Ismail 
1146146b9756SMustafa Ismail 	new_send->retrycount = IRDMA_DEFAULT_RETRYS;
1147146b9756SMustafa Ismail 	new_send->retranscount = IRDMA_DEFAULT_RETRANS;
1148146b9756SMustafa Ismail 	new_send->sqbuf = sqbuf;
1149146b9756SMustafa Ismail 	new_send->timetosend = jiffies;
1150146b9756SMustafa Ismail 	new_send->type = type;
1151146b9756SMustafa Ismail 	new_send->send_retrans = send_retrans;
1152146b9756SMustafa Ismail 	new_send->close_when_complete = close_when_complete;
1153146b9756SMustafa Ismail 
1154146b9756SMustafa Ismail 	if (type == IRDMA_TIMER_TYPE_CLOSE) {
1155146b9756SMustafa Ismail 		new_send->timetosend += (HZ / 10);
1156146b9756SMustafa Ismail 		if (cm_node->close_entry) {
1157146b9756SMustafa Ismail 			kfree(new_send);
1158146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
1159146b9756SMustafa Ismail 				  "CM: already close entry\n");
1160146b9756SMustafa Ismail 			return -EINVAL;
1161146b9756SMustafa Ismail 		}
1162146b9756SMustafa Ismail 
1163146b9756SMustafa Ismail 		cm_node->close_entry = new_send;
1164146b9756SMustafa Ismail 	} else { /* type == IRDMA_TIMER_TYPE_SEND */
1165146b9756SMustafa Ismail 		spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
1166146b9756SMustafa Ismail 		cm_node->send_entry = new_send;
1167146b9756SMustafa Ismail 		refcount_inc(&cm_node->refcnt);
1168146b9756SMustafa Ismail 		spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
1169146b9756SMustafa Ismail 		new_send->timetosend = jiffies + IRDMA_RETRY_TIMEOUT;
1170146b9756SMustafa Ismail 
1171146b9756SMustafa Ismail 		refcount_inc(&sqbuf->refcount);
1172146b9756SMustafa Ismail 		irdma_puda_send_buf(vsi->ilq, sqbuf);
1173146b9756SMustafa Ismail 		if (!send_retrans) {
1174146b9756SMustafa Ismail 			irdma_cleanup_retrans_entry(cm_node);
1175146b9756SMustafa Ismail 			if (close_when_complete)
1176146b9756SMustafa Ismail 				irdma_rem_ref_cm_node(cm_node);
1177146b9756SMustafa Ismail 			return 0;
1178146b9756SMustafa Ismail 		}
1179146b9756SMustafa Ismail 	}
1180146b9756SMustafa Ismail 
1181146b9756SMustafa Ismail 	spin_lock_irqsave(&cm_core->ht_lock, flags);
1182146b9756SMustafa Ismail 	was_timer_set = timer_pending(&cm_core->tcp_timer);
1183146b9756SMustafa Ismail 
1184146b9756SMustafa Ismail 	if (!was_timer_set) {
1185146b9756SMustafa Ismail 		cm_core->tcp_timer.expires = new_send->timetosend;
1186146b9756SMustafa Ismail 		add_timer(&cm_core->tcp_timer);
1187146b9756SMustafa Ismail 	}
1188146b9756SMustafa Ismail 	spin_unlock_irqrestore(&cm_core->ht_lock, flags);
1189146b9756SMustafa Ismail 
1190146b9756SMustafa Ismail 	return 0;
1191146b9756SMustafa Ismail }
1192146b9756SMustafa Ismail 
1193146b9756SMustafa Ismail /**
1194146b9756SMustafa Ismail  * irdma_retrans_expired - Could not rexmit the packet
1195146b9756SMustafa Ismail  * @cm_node: connection's node
1196146b9756SMustafa Ismail  */
irdma_retrans_expired(struct irdma_cm_node * cm_node)1197146b9756SMustafa Ismail static void irdma_retrans_expired(struct irdma_cm_node *cm_node)
1198146b9756SMustafa Ismail {
1199146b9756SMustafa Ismail 	enum irdma_cm_node_state state = cm_node->state;
1200146b9756SMustafa Ismail 
1201146b9756SMustafa Ismail 	cm_node->state = IRDMA_CM_STATE_CLOSED;
1202146b9756SMustafa Ismail 	switch (state) {
1203146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_RCVD:
1204146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSING:
1205146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
1206146b9756SMustafa Ismail 		break;
1207146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT1:
1208146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LAST_ACK:
1209146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
1210146b9756SMustafa Ismail 		break;
1211146b9756SMustafa Ismail 	default:
1212146b9756SMustafa Ismail 		refcount_inc(&cm_node->refcnt);
1213146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
1214146b9756SMustafa Ismail 		irdma_create_event(cm_node, IRDMA_CM_EVENT_ABORTED);
1215146b9756SMustafa Ismail 		break;
1216146b9756SMustafa Ismail 	}
1217146b9756SMustafa Ismail }
1218146b9756SMustafa Ismail 
1219146b9756SMustafa Ismail /**
1220146b9756SMustafa Ismail  * irdma_handle_close_entry - for handling retry/timeouts
1221146b9756SMustafa Ismail  * @cm_node: connection's node
1222146b9756SMustafa Ismail  * @rem_node: flag for remove cm_node
1223146b9756SMustafa Ismail  */
irdma_handle_close_entry(struct irdma_cm_node * cm_node,u32 rem_node)1224146b9756SMustafa Ismail static void irdma_handle_close_entry(struct irdma_cm_node *cm_node,
1225146b9756SMustafa Ismail 				     u32 rem_node)
1226146b9756SMustafa Ismail {
1227146b9756SMustafa Ismail 	struct irdma_timer_entry *close_entry = cm_node->close_entry;
1228146b9756SMustafa Ismail 	struct irdma_qp *iwqp;
1229146b9756SMustafa Ismail 	unsigned long flags;
1230146b9756SMustafa Ismail 
1231146b9756SMustafa Ismail 	if (!close_entry)
1232146b9756SMustafa Ismail 		return;
1233146b9756SMustafa Ismail 	iwqp = (struct irdma_qp *)close_entry->sqbuf;
1234146b9756SMustafa Ismail 	if (iwqp) {
1235146b9756SMustafa Ismail 		spin_lock_irqsave(&iwqp->lock, flags);
1236146b9756SMustafa Ismail 		if (iwqp->cm_id) {
1237146b9756SMustafa Ismail 			iwqp->hw_tcp_state = IRDMA_TCP_STATE_CLOSED;
1238146b9756SMustafa Ismail 			iwqp->hw_iwarp_state = IRDMA_QP_STATE_ERROR;
1239146b9756SMustafa Ismail 			iwqp->last_aeq = IRDMA_AE_RESET_SENT;
1240146b9756SMustafa Ismail 			iwqp->ibqp_state = IB_QPS_ERR;
1241146b9756SMustafa Ismail 			spin_unlock_irqrestore(&iwqp->lock, flags);
1242146b9756SMustafa Ismail 			irdma_cm_disconn(iwqp);
1243146b9756SMustafa Ismail 		} else {
1244146b9756SMustafa Ismail 			spin_unlock_irqrestore(&iwqp->lock, flags);
1245146b9756SMustafa Ismail 		}
1246146b9756SMustafa Ismail 	} else if (rem_node) {
1247146b9756SMustafa Ismail 		/* TIME_WAIT state */
1248146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
1249146b9756SMustafa Ismail 	}
1250146b9756SMustafa Ismail 
1251146b9756SMustafa Ismail 	kfree(close_entry);
1252146b9756SMustafa Ismail 	cm_node->close_entry = NULL;
1253146b9756SMustafa Ismail }
1254146b9756SMustafa Ismail 
1255146b9756SMustafa Ismail /**
1256146b9756SMustafa Ismail  * irdma_cm_timer_tick - system's timer expired callback
1257146b9756SMustafa Ismail  * @t: Pointer to timer_list
1258146b9756SMustafa Ismail  */
irdma_cm_timer_tick(struct timer_list * t)1259146b9756SMustafa Ismail static void irdma_cm_timer_tick(struct timer_list *t)
1260146b9756SMustafa Ismail {
1261146b9756SMustafa Ismail 	unsigned long nexttimeout = jiffies + IRDMA_LONG_TIME;
1262146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
1263146b9756SMustafa Ismail 	struct irdma_timer_entry *send_entry, *close_entry;
1264146b9756SMustafa Ismail 	struct list_head *list_core_temp;
1265146b9756SMustafa Ismail 	struct list_head *list_node;
1266146b9756SMustafa Ismail 	struct irdma_cm_core *cm_core = from_timer(cm_core, t, tcp_timer);
1267146b9756SMustafa Ismail 	struct irdma_sc_vsi *vsi;
1268146b9756SMustafa Ismail 	u32 settimer = 0;
1269146b9756SMustafa Ismail 	unsigned long timetosend;
1270146b9756SMustafa Ismail 	unsigned long flags;
1271146b9756SMustafa Ismail 	struct list_head timer_list;
1272146b9756SMustafa Ismail 
1273146b9756SMustafa Ismail 	INIT_LIST_HEAD(&timer_list);
1274146b9756SMustafa Ismail 
1275146b9756SMustafa Ismail 	rcu_read_lock();
1276146b9756SMustafa Ismail 	irdma_timer_list_prep(cm_core, &timer_list);
1277146b9756SMustafa Ismail 	rcu_read_unlock();
1278146b9756SMustafa Ismail 
1279146b9756SMustafa Ismail 	list_for_each_safe (list_node, list_core_temp, &timer_list) {
1280146b9756SMustafa Ismail 		cm_node = container_of(list_node, struct irdma_cm_node,
1281146b9756SMustafa Ismail 				       timer_entry);
1282146b9756SMustafa Ismail 		close_entry = cm_node->close_entry;
1283146b9756SMustafa Ismail 
1284146b9756SMustafa Ismail 		if (close_entry) {
1285146b9756SMustafa Ismail 			if (time_after(close_entry->timetosend, jiffies)) {
1286146b9756SMustafa Ismail 				if (nexttimeout > close_entry->timetosend ||
1287146b9756SMustafa Ismail 				    !settimer) {
1288146b9756SMustafa Ismail 					nexttimeout = close_entry->timetosend;
1289146b9756SMustafa Ismail 					settimer = 1;
1290146b9756SMustafa Ismail 				}
1291146b9756SMustafa Ismail 			} else {
1292146b9756SMustafa Ismail 				irdma_handle_close_entry(cm_node, 1);
1293146b9756SMustafa Ismail 			}
1294146b9756SMustafa Ismail 		}
1295146b9756SMustafa Ismail 
1296146b9756SMustafa Ismail 		spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
1297146b9756SMustafa Ismail 
1298146b9756SMustafa Ismail 		send_entry = cm_node->send_entry;
1299146b9756SMustafa Ismail 		if (!send_entry)
1300146b9756SMustafa Ismail 			goto done;
1301146b9756SMustafa Ismail 		if (time_after(send_entry->timetosend, jiffies)) {
1302146b9756SMustafa Ismail 			if (cm_node->state != IRDMA_CM_STATE_OFFLOADED) {
1303146b9756SMustafa Ismail 				if (nexttimeout > send_entry->timetosend ||
1304146b9756SMustafa Ismail 				    !settimer) {
1305146b9756SMustafa Ismail 					nexttimeout = send_entry->timetosend;
1306146b9756SMustafa Ismail 					settimer = 1;
1307146b9756SMustafa Ismail 				}
1308146b9756SMustafa Ismail 			} else {
1309146b9756SMustafa Ismail 				irdma_free_retrans_entry(cm_node);
1310146b9756SMustafa Ismail 			}
1311146b9756SMustafa Ismail 			goto done;
1312146b9756SMustafa Ismail 		}
1313146b9756SMustafa Ismail 
1314146b9756SMustafa Ismail 		if (cm_node->state == IRDMA_CM_STATE_OFFLOADED ||
1315146b9756SMustafa Ismail 		    cm_node->state == IRDMA_CM_STATE_CLOSED) {
1316146b9756SMustafa Ismail 			irdma_free_retrans_entry(cm_node);
1317146b9756SMustafa Ismail 			goto done;
1318146b9756SMustafa Ismail 		}
1319146b9756SMustafa Ismail 
1320146b9756SMustafa Ismail 		if (!send_entry->retranscount || !send_entry->retrycount) {
1321146b9756SMustafa Ismail 			irdma_free_retrans_entry(cm_node);
1322146b9756SMustafa Ismail 
1323146b9756SMustafa Ismail 			spin_unlock_irqrestore(&cm_node->retrans_list_lock,
1324146b9756SMustafa Ismail 					       flags);
1325146b9756SMustafa Ismail 			irdma_retrans_expired(cm_node);
1326146b9756SMustafa Ismail 			cm_node->state = IRDMA_CM_STATE_CLOSED;
1327146b9756SMustafa Ismail 			spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
1328146b9756SMustafa Ismail 			goto done;
1329146b9756SMustafa Ismail 		}
1330146b9756SMustafa Ismail 		spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
1331146b9756SMustafa Ismail 
1332146b9756SMustafa Ismail 		vsi = &cm_node->iwdev->vsi;
1333146b9756SMustafa Ismail 		if (!cm_node->ack_rcvd) {
1334146b9756SMustafa Ismail 			refcount_inc(&send_entry->sqbuf->refcount);
1335146b9756SMustafa Ismail 			irdma_puda_send_buf(vsi->ilq, send_entry->sqbuf);
1336146b9756SMustafa Ismail 			cm_node->cm_core->stats_pkt_retrans++;
1337146b9756SMustafa Ismail 		}
1338146b9756SMustafa Ismail 
1339146b9756SMustafa Ismail 		spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
1340146b9756SMustafa Ismail 		if (send_entry->send_retrans) {
1341146b9756SMustafa Ismail 			send_entry->retranscount--;
1342146b9756SMustafa Ismail 			timetosend = (IRDMA_RETRY_TIMEOUT <<
1343146b9756SMustafa Ismail 				      (IRDMA_DEFAULT_RETRANS -
1344146b9756SMustafa Ismail 				       send_entry->retranscount));
1345146b9756SMustafa Ismail 
1346146b9756SMustafa Ismail 			send_entry->timetosend = jiffies +
1347146b9756SMustafa Ismail 			    min(timetosend, IRDMA_MAX_TIMEOUT);
1348146b9756SMustafa Ismail 			if (nexttimeout > send_entry->timetosend || !settimer) {
1349146b9756SMustafa Ismail 				nexttimeout = send_entry->timetosend;
1350146b9756SMustafa Ismail 				settimer = 1;
1351146b9756SMustafa Ismail 			}
1352146b9756SMustafa Ismail 		} else {
1353146b9756SMustafa Ismail 			int close_when_complete;
1354146b9756SMustafa Ismail 
1355146b9756SMustafa Ismail 			close_when_complete = send_entry->close_when_complete;
1356146b9756SMustafa Ismail 			irdma_free_retrans_entry(cm_node);
1357146b9756SMustafa Ismail 			if (close_when_complete)
1358146b9756SMustafa Ismail 				irdma_rem_ref_cm_node(cm_node);
1359146b9756SMustafa Ismail 		}
1360146b9756SMustafa Ismail done:
1361146b9756SMustafa Ismail 		spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
1362146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
1363146b9756SMustafa Ismail 	}
1364146b9756SMustafa Ismail 
1365146b9756SMustafa Ismail 	if (settimer) {
1366146b9756SMustafa Ismail 		spin_lock_irqsave(&cm_core->ht_lock, flags);
1367146b9756SMustafa Ismail 		if (!timer_pending(&cm_core->tcp_timer)) {
1368146b9756SMustafa Ismail 			cm_core->tcp_timer.expires = nexttimeout;
1369146b9756SMustafa Ismail 			add_timer(&cm_core->tcp_timer);
1370146b9756SMustafa Ismail 		}
1371146b9756SMustafa Ismail 		spin_unlock_irqrestore(&cm_core->ht_lock, flags);
1372146b9756SMustafa Ismail 	}
1373146b9756SMustafa Ismail }
1374146b9756SMustafa Ismail 
1375146b9756SMustafa Ismail /**
1376146b9756SMustafa Ismail  * irdma_send_syn - send SYN packet
1377146b9756SMustafa Ismail  * @cm_node: connection's node
1378146b9756SMustafa Ismail  * @sendack: flag to set ACK bit or not
1379146b9756SMustafa Ismail  */
irdma_send_syn(struct irdma_cm_node * cm_node,u32 sendack)1380146b9756SMustafa Ismail int irdma_send_syn(struct irdma_cm_node *cm_node, u32 sendack)
1381146b9756SMustafa Ismail {
1382146b9756SMustafa Ismail 	struct irdma_puda_buf *sqbuf;
1383146b9756SMustafa Ismail 	int flags = SET_SYN;
1384146b9756SMustafa Ismail 	char optionsbuf[sizeof(struct option_mss) +
1385146b9756SMustafa Ismail 			sizeof(struct option_windowscale) +
1386146b9756SMustafa Ismail 			sizeof(struct option_base) + TCP_OPTIONS_PADDING];
1387146b9756SMustafa Ismail 	struct irdma_kmem_info opts;
1388146b9756SMustafa Ismail 	int optionssize = 0;
1389146b9756SMustafa Ismail 	/* Sending MSS option */
1390146b9756SMustafa Ismail 	union all_known_options *options;
1391146b9756SMustafa Ismail 
1392146b9756SMustafa Ismail 	opts.addr = optionsbuf;
1393146b9756SMustafa Ismail 	if (!cm_node)
1394146b9756SMustafa Ismail 		return -EINVAL;
1395146b9756SMustafa Ismail 
1396146b9756SMustafa Ismail 	options = (union all_known_options *)&optionsbuf[optionssize];
1397146b9756SMustafa Ismail 	options->mss.optionnum = OPTION_NUM_MSS;
1398146b9756SMustafa Ismail 	options->mss.len = sizeof(struct option_mss);
1399146b9756SMustafa Ismail 	options->mss.mss = htons(cm_node->tcp_cntxt.mss);
1400146b9756SMustafa Ismail 	optionssize += sizeof(struct option_mss);
1401146b9756SMustafa Ismail 
1402146b9756SMustafa Ismail 	options = (union all_known_options *)&optionsbuf[optionssize];
1403146b9756SMustafa Ismail 	options->windowscale.optionnum = OPTION_NUM_WINDOW_SCALE;
1404146b9756SMustafa Ismail 	options->windowscale.len = sizeof(struct option_windowscale);
1405146b9756SMustafa Ismail 	options->windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;
1406146b9756SMustafa Ismail 	optionssize += sizeof(struct option_windowscale);
1407146b9756SMustafa Ismail 	options = (union all_known_options *)&optionsbuf[optionssize];
1408146b9756SMustafa Ismail 	options->eol = OPTION_NUM_EOL;
1409146b9756SMustafa Ismail 	optionssize += 1;
1410146b9756SMustafa Ismail 
1411146b9756SMustafa Ismail 	if (sendack)
1412146b9756SMustafa Ismail 		flags |= SET_ACK;
1413146b9756SMustafa Ismail 
1414146b9756SMustafa Ismail 	opts.size = optionssize;
1415146b9756SMustafa Ismail 
1416146b9756SMustafa Ismail 	sqbuf = cm_node->cm_core->form_cm_frame(cm_node, &opts, NULL, NULL,
1417146b9756SMustafa Ismail 						flags);
1418146b9756SMustafa Ismail 	if (!sqbuf)
1419146b9756SMustafa Ismail 		return -ENOMEM;
1420146b9756SMustafa Ismail 
1421146b9756SMustafa Ismail 	return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 1,
1422146b9756SMustafa Ismail 				       0);
1423146b9756SMustafa Ismail }
1424146b9756SMustafa Ismail 
1425146b9756SMustafa Ismail /**
1426146b9756SMustafa Ismail  * irdma_send_ack - Send ACK packet
1427146b9756SMustafa Ismail  * @cm_node: connection's node
1428146b9756SMustafa Ismail  */
irdma_send_ack(struct irdma_cm_node * cm_node)1429146b9756SMustafa Ismail void irdma_send_ack(struct irdma_cm_node *cm_node)
1430146b9756SMustafa Ismail {
1431146b9756SMustafa Ismail 	struct irdma_puda_buf *sqbuf;
1432146b9756SMustafa Ismail 	struct irdma_sc_vsi *vsi = &cm_node->iwdev->vsi;
1433146b9756SMustafa Ismail 
1434146b9756SMustafa Ismail 	sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL, NULL, NULL,
1435146b9756SMustafa Ismail 						SET_ACK);
1436146b9756SMustafa Ismail 	if (sqbuf)
1437146b9756SMustafa Ismail 		irdma_puda_send_buf(vsi->ilq, sqbuf);
1438146b9756SMustafa Ismail }
1439146b9756SMustafa Ismail 
1440146b9756SMustafa Ismail /**
1441146b9756SMustafa Ismail  * irdma_send_fin - Send FIN pkt
1442146b9756SMustafa Ismail  * @cm_node: connection's node
1443146b9756SMustafa Ismail  */
irdma_send_fin(struct irdma_cm_node * cm_node)1444146b9756SMustafa Ismail static int irdma_send_fin(struct irdma_cm_node *cm_node)
1445146b9756SMustafa Ismail {
1446146b9756SMustafa Ismail 	struct irdma_puda_buf *sqbuf;
1447146b9756SMustafa Ismail 
1448146b9756SMustafa Ismail 	sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL, NULL, NULL,
1449146b9756SMustafa Ismail 						SET_ACK | SET_FIN);
1450146b9756SMustafa Ismail 	if (!sqbuf)
1451146b9756SMustafa Ismail 		return -ENOMEM;
1452146b9756SMustafa Ismail 
1453146b9756SMustafa Ismail 	return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 1,
1454146b9756SMustafa Ismail 				       0);
1455146b9756SMustafa Ismail }
1456146b9756SMustafa Ismail 
1457146b9756SMustafa Ismail /**
1458146b9756SMustafa Ismail  * irdma_find_listener - find a cm node listening on this addr-port pair
1459146b9756SMustafa Ismail  * @cm_core: cm's core
1460146b9756SMustafa Ismail  * @dst_addr: listener ip addr
1461e4522c09STatyana Nikolova  * @ipv4: flag indicating IPv4 when true
1462146b9756SMustafa Ismail  * @dst_port: listener tcp port num
1463146b9756SMustafa Ismail  * @vlan_id: virtual LAN ID
1464146b9756SMustafa Ismail  * @listener_state: state to match with listen node's
1465146b9756SMustafa Ismail  */
1466146b9756SMustafa Ismail static struct irdma_cm_listener *
irdma_find_listener(struct irdma_cm_core * cm_core,u32 * dst_addr,bool ipv4,u16 dst_port,u16 vlan_id,enum irdma_cm_listener_state listener_state)1467e4522c09STatyana Nikolova irdma_find_listener(struct irdma_cm_core *cm_core, u32 *dst_addr, bool ipv4,
1468e4522c09STatyana Nikolova 		    u16 dst_port, u16 vlan_id,
1469e4522c09STatyana Nikolova 		    enum irdma_cm_listener_state listener_state)
1470146b9756SMustafa Ismail {
1471146b9756SMustafa Ismail 	struct irdma_cm_listener *listen_node;
1472146b9756SMustafa Ismail 	static const u32 ip_zero[4] = { 0, 0, 0, 0 };
1473146b9756SMustafa Ismail 	u32 listen_addr[4];
1474146b9756SMustafa Ismail 	u16 listen_port;
1475146b9756SMustafa Ismail 	unsigned long flags;
1476146b9756SMustafa Ismail 
1477146b9756SMustafa Ismail 	/* walk list and find cm_node associated with this session ID */
1478146b9756SMustafa Ismail 	spin_lock_irqsave(&cm_core->listen_list_lock, flags);
1479146b9756SMustafa Ismail 	list_for_each_entry (listen_node, &cm_core->listen_list, list) {
1480146b9756SMustafa Ismail 		memcpy(listen_addr, listen_node->loc_addr, sizeof(listen_addr));
1481146b9756SMustafa Ismail 		listen_port = listen_node->loc_port;
1482e4522c09STatyana Nikolova 		if (listen_node->ipv4 != ipv4 || listen_port != dst_port ||
148382ab2b52SMustafa Ismail 		    !(listener_state & listen_node->listener_state))
148482ab2b52SMustafa Ismail 			continue;
1485146b9756SMustafa Ismail 		/* compare node pair, return node handle if a match */
148682ab2b52SMustafa Ismail 		if (!memcmp(listen_addr, ip_zero, sizeof(listen_addr)) ||
148782ab2b52SMustafa Ismail 		    (!memcmp(listen_addr, dst_addr, sizeof(listen_addr)) &&
148882ab2b52SMustafa Ismail 		     vlan_id == listen_node->vlan_id)) {
1489146b9756SMustafa Ismail 			refcount_inc(&listen_node->refcnt);
1490146b9756SMustafa Ismail 			spin_unlock_irqrestore(&cm_core->listen_list_lock,
1491146b9756SMustafa Ismail 					       flags);
1492146b9756SMustafa Ismail 			trace_irdma_find_listener(listen_node);
1493146b9756SMustafa Ismail 			return listen_node;
1494146b9756SMustafa Ismail 		}
1495146b9756SMustafa Ismail 	}
1496146b9756SMustafa Ismail 	spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
1497146b9756SMustafa Ismail 
1498146b9756SMustafa Ismail 	return NULL;
1499146b9756SMustafa Ismail }
1500146b9756SMustafa Ismail 
1501146b9756SMustafa Ismail /**
1502146b9756SMustafa Ismail  * irdma_del_multiple_qhash - Remove qhash and child listens
1503146b9756SMustafa Ismail  * @iwdev: iWarp device
1504146b9756SMustafa Ismail  * @cm_info: CM info for parent listen node
1505146b9756SMustafa Ismail  * @cm_parent_listen_node: The parent listen node
1506146b9756SMustafa Ismail  */
irdma_del_multiple_qhash(struct irdma_device * iwdev,struct irdma_cm_info * cm_info,struct irdma_cm_listener * cm_parent_listen_node)15072c4b14eaSShiraz Saleem static int irdma_del_multiple_qhash(struct irdma_device *iwdev,
1508146b9756SMustafa Ismail 				    struct irdma_cm_info *cm_info,
1509146b9756SMustafa Ismail 				    struct irdma_cm_listener *cm_parent_listen_node)
1510146b9756SMustafa Ismail {
1511146b9756SMustafa Ismail 	struct irdma_cm_listener *child_listen_node;
1512146b9756SMustafa Ismail 	struct list_head *pos, *tpos;
1513146b9756SMustafa Ismail 	unsigned long flags;
15142c4b14eaSShiraz Saleem 	int ret = -EINVAL;
1515146b9756SMustafa Ismail 
1516146b9756SMustafa Ismail 	spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
1517146b9756SMustafa Ismail 	list_for_each_safe (pos, tpos,
1518146b9756SMustafa Ismail 			    &cm_parent_listen_node->child_listen_list) {
1519146b9756SMustafa Ismail 		child_listen_node = list_entry(pos, struct irdma_cm_listener,
1520146b9756SMustafa Ismail 					       child_listen_list);
1521146b9756SMustafa Ismail 		if (child_listen_node->ipv4)
1522146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev,
1523146b9756SMustafa Ismail 				  "CM: removing child listen for IP=%pI4, port=%d, vlan=%d\n",
1524146b9756SMustafa Ismail 				  child_listen_node->loc_addr,
1525146b9756SMustafa Ismail 				  child_listen_node->loc_port,
1526146b9756SMustafa Ismail 				  child_listen_node->vlan_id);
1527146b9756SMustafa Ismail 		else
1528146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev,
1529146b9756SMustafa Ismail 				  "CM: removing child listen for IP=%pI6, port=%d, vlan=%d\n",
1530146b9756SMustafa Ismail 				  child_listen_node->loc_addr,
1531146b9756SMustafa Ismail 				  child_listen_node->loc_port,
1532146b9756SMustafa Ismail 				  child_listen_node->vlan_id);
1533146b9756SMustafa Ismail 		trace_irdma_del_multiple_qhash(child_listen_node);
1534146b9756SMustafa Ismail 		list_del(pos);
1535146b9756SMustafa Ismail 		memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
1536146b9756SMustafa Ismail 		       sizeof(cm_info->loc_addr));
1537146b9756SMustafa Ismail 		cm_info->vlan_id = child_listen_node->vlan_id;
1538146b9756SMustafa Ismail 		if (child_listen_node->qhash_set) {
1539146b9756SMustafa Ismail 			ret = irdma_manage_qhash(iwdev, cm_info,
1540146b9756SMustafa Ismail 						 IRDMA_QHASH_TYPE_TCP_SYN,
1541146b9756SMustafa Ismail 						 IRDMA_QHASH_MANAGE_TYPE_DELETE,
1542146b9756SMustafa Ismail 						 NULL, false);
1543146b9756SMustafa Ismail 			child_listen_node->qhash_set = false;
1544146b9756SMustafa Ismail 		} else {
1545146b9756SMustafa Ismail 			ret = 0;
1546146b9756SMustafa Ismail 		}
1547146b9756SMustafa Ismail 		ibdev_dbg(&iwdev->ibdev,
1548146b9756SMustafa Ismail 			  "CM: Child listen node freed = %p\n",
1549146b9756SMustafa Ismail 			  child_listen_node);
1550146b9756SMustafa Ismail 		kfree(child_listen_node);
1551146b9756SMustafa Ismail 		cm_parent_listen_node->cm_core->stats_listen_nodes_destroyed++;
1552146b9756SMustafa Ismail 	}
1553146b9756SMustafa Ismail 	spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
1554146b9756SMustafa Ismail 
1555146b9756SMustafa Ismail 	return ret;
1556146b9756SMustafa Ismail }
1557146b9756SMustafa Ismail 
irdma_iw_get_vlan_prio(u32 * loc_addr,u8 prio,bool ipv4)1558f877f22aSMustafa Ismail static u8 irdma_iw_get_vlan_prio(u32 *loc_addr, u8 prio, bool ipv4)
1559f877f22aSMustafa Ismail {
1560f877f22aSMustafa Ismail 	struct net_device *ndev = NULL;
1561f877f22aSMustafa Ismail 
1562f877f22aSMustafa Ismail 	rcu_read_lock();
1563f877f22aSMustafa Ismail 	if (ipv4) {
1564f877f22aSMustafa Ismail 		ndev = ip_dev_find(&init_net, htonl(loc_addr[0]));
1565b3d2b014SArnd Bergmann 	} else if (IS_ENABLED(CONFIG_IPV6)) {
1566f877f22aSMustafa Ismail 		struct net_device *ip_dev;
1567f877f22aSMustafa Ismail 		struct in6_addr laddr6;
1568f877f22aSMustafa Ismail 
1569f877f22aSMustafa Ismail 		irdma_copy_ip_htonl(laddr6.in6_u.u6_addr32, loc_addr);
1570f877f22aSMustafa Ismail 
1571f877f22aSMustafa Ismail 		for_each_netdev_rcu (&init_net, ip_dev) {
1572f877f22aSMustafa Ismail 			if (ipv6_chk_addr(&init_net, &laddr6, ip_dev, 1)) {
1573f877f22aSMustafa Ismail 				ndev = ip_dev;
1574f877f22aSMustafa Ismail 				break;
1575f877f22aSMustafa Ismail 			}
1576f877f22aSMustafa Ismail 		}
1577f877f22aSMustafa Ismail 	}
1578f877f22aSMustafa Ismail 
1579f877f22aSMustafa Ismail 	if (!ndev)
1580f877f22aSMustafa Ismail 		goto done;
1581f877f22aSMustafa Ismail 	if (is_vlan_dev(ndev))
1582f877f22aSMustafa Ismail 		prio = (vlan_dev_get_egress_qos_mask(ndev, prio) & VLAN_PRIO_MASK)
1583f877f22aSMustafa Ismail 			>> VLAN_PRIO_SHIFT;
1584f877f22aSMustafa Ismail 	if (ipv4)
1585f877f22aSMustafa Ismail 		dev_put(ndev);
1586f877f22aSMustafa Ismail 
1587f877f22aSMustafa Ismail done:
1588f877f22aSMustafa Ismail 	rcu_read_unlock();
1589f877f22aSMustafa Ismail 
1590f877f22aSMustafa Ismail 	return prio;
1591f877f22aSMustafa Ismail }
1592f877f22aSMustafa Ismail 
1593146b9756SMustafa Ismail /**
1594693e1cdeSMustafa Ismail  * irdma_get_vlan_mac_ipv6 - Gets the vlan and mac
1595146b9756SMustafa Ismail  * @addr: local IPv6 address
1596146b9756SMustafa Ismail  * @vlan_id: vlan id for the given IPv6 address
1597146b9756SMustafa Ismail  * @mac: mac address for the given IPv6 address
1598146b9756SMustafa Ismail  *
1599693e1cdeSMustafa Ismail  * Returns the vlan id and mac for an IPv6 address.
1600146b9756SMustafa Ismail  */
irdma_get_vlan_mac_ipv6(u32 * addr,u16 * vlan_id,u8 * mac)1601693e1cdeSMustafa Ismail void irdma_get_vlan_mac_ipv6(u32 *addr, u16 *vlan_id, u8 *mac)
1602146b9756SMustafa Ismail {
1603146b9756SMustafa Ismail 	struct net_device *ip_dev = NULL;
1604146b9756SMustafa Ismail 	struct in6_addr laddr6;
1605146b9756SMustafa Ismail 
1606146b9756SMustafa Ismail 	if (!IS_ENABLED(CONFIG_IPV6))
1607693e1cdeSMustafa Ismail 		return;
1608146b9756SMustafa Ismail 
1609146b9756SMustafa Ismail 	irdma_copy_ip_htonl(laddr6.in6_u.u6_addr32, addr);
1610146b9756SMustafa Ismail 	if (vlan_id)
1611146b9756SMustafa Ismail 		*vlan_id = 0xFFFF;	/* Match rdma_vlan_dev_vlan_id() */
1612146b9756SMustafa Ismail 	if (mac)
1613146b9756SMustafa Ismail 		eth_zero_addr(mac);
1614146b9756SMustafa Ismail 
1615146b9756SMustafa Ismail 	rcu_read_lock();
1616146b9756SMustafa Ismail 	for_each_netdev_rcu (&init_net, ip_dev) {
1617146b9756SMustafa Ismail 		if (ipv6_chk_addr(&init_net, &laddr6, ip_dev, 1)) {
1618146b9756SMustafa Ismail 			if (vlan_id)
1619146b9756SMustafa Ismail 				*vlan_id = rdma_vlan_dev_vlan_id(ip_dev);
1620146b9756SMustafa Ismail 			if (ip_dev->dev_addr && mac)
1621146b9756SMustafa Ismail 				ether_addr_copy(mac, ip_dev->dev_addr);
1622146b9756SMustafa Ismail 			break;
1623146b9756SMustafa Ismail 		}
1624146b9756SMustafa Ismail 	}
1625146b9756SMustafa Ismail 	rcu_read_unlock();
1626146b9756SMustafa Ismail }
1627146b9756SMustafa Ismail 
1628146b9756SMustafa Ismail /**
1629146b9756SMustafa Ismail  * irdma_get_vlan_ipv4 - Returns the vlan_id for IPv4 address
1630146b9756SMustafa Ismail  * @addr: local IPv4 address
1631146b9756SMustafa Ismail  */
irdma_get_vlan_ipv4(u32 * addr)1632146b9756SMustafa Ismail u16 irdma_get_vlan_ipv4(u32 *addr)
1633146b9756SMustafa Ismail {
1634146b9756SMustafa Ismail 	struct net_device *netdev;
1635146b9756SMustafa Ismail 	u16 vlan_id = 0xFFFF;
1636146b9756SMustafa Ismail 
1637146b9756SMustafa Ismail 	netdev = ip_dev_find(&init_net, htonl(addr[0]));
1638146b9756SMustafa Ismail 	if (netdev) {
1639146b9756SMustafa Ismail 		vlan_id = rdma_vlan_dev_vlan_id(netdev);
1640146b9756SMustafa Ismail 		dev_put(netdev);
1641146b9756SMustafa Ismail 	}
1642146b9756SMustafa Ismail 
1643146b9756SMustafa Ismail 	return vlan_id;
1644146b9756SMustafa Ismail }
1645146b9756SMustafa Ismail 
1646146b9756SMustafa Ismail /**
1647146b9756SMustafa Ismail  * irdma_add_mqh_6 - Adds multiple qhashes for IPv6
1648146b9756SMustafa Ismail  * @iwdev: iWarp device
1649146b9756SMustafa Ismail  * @cm_info: CM info for parent listen node
1650146b9756SMustafa Ismail  * @cm_parent_listen_node: The parent listen node
1651146b9756SMustafa Ismail  *
1652146b9756SMustafa Ismail  * Adds a qhash and a child listen node for every IPv6 address
1653146b9756SMustafa Ismail  * on the adapter and adds the associated qhash filter
1654146b9756SMustafa Ismail  */
irdma_add_mqh_6(struct irdma_device * iwdev,struct irdma_cm_info * cm_info,struct irdma_cm_listener * cm_parent_listen_node)16552c4b14eaSShiraz Saleem static int irdma_add_mqh_6(struct irdma_device *iwdev,
16562c4b14eaSShiraz Saleem 			   struct irdma_cm_info *cm_info,
1657146b9756SMustafa Ismail 			   struct irdma_cm_listener *cm_parent_listen_node)
1658146b9756SMustafa Ismail {
1659146b9756SMustafa Ismail 	struct net_device *ip_dev;
1660146b9756SMustafa Ismail 	struct inet6_dev *idev;
1661146b9756SMustafa Ismail 	struct inet6_ifaddr *ifp, *tmp;
1662146b9756SMustafa Ismail 	struct irdma_cm_listener *child_listen_node;
1663146b9756SMustafa Ismail 	unsigned long flags;
16642c4b14eaSShiraz Saleem 	int ret = 0;
1665146b9756SMustafa Ismail 
1666146b9756SMustafa Ismail 	rtnl_lock();
1667146b9756SMustafa Ismail 	for_each_netdev(&init_net, ip_dev) {
1668146b9756SMustafa Ismail 		if (!(ip_dev->flags & IFF_UP))
1669146b9756SMustafa Ismail 			continue;
1670146b9756SMustafa Ismail 
1671146b9756SMustafa Ismail 		if (((rdma_vlan_dev_vlan_id(ip_dev) >= VLAN_N_VID) ||
1672146b9756SMustafa Ismail 		     (rdma_vlan_dev_real_dev(ip_dev) != iwdev->netdev)) &&
1673146b9756SMustafa Ismail 		    ip_dev != iwdev->netdev)
1674146b9756SMustafa Ismail 			continue;
1675146b9756SMustafa Ismail 
1676146b9756SMustafa Ismail 		idev = __in6_dev_get(ip_dev);
1677146b9756SMustafa Ismail 		if (!idev) {
1678146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev, "CM: idev == NULL\n");
1679146b9756SMustafa Ismail 			break;
1680146b9756SMustafa Ismail 		}
1681146b9756SMustafa Ismail 		list_for_each_entry_safe (ifp, tmp, &idev->addr_list, if_list) {
1682146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev, "CM: IP=%pI6, vlan_id=%d, MAC=%pM\n",
1683146b9756SMustafa Ismail 				  &ifp->addr, rdma_vlan_dev_vlan_id(ip_dev),
1684146b9756SMustafa Ismail 				  ip_dev->dev_addr);
1685146b9756SMustafa Ismail 			child_listen_node = kzalloc(sizeof(*child_listen_node), GFP_KERNEL);
1686146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev, "CM: Allocating child listener %p\n",
1687146b9756SMustafa Ismail 				  child_listen_node);
1688146b9756SMustafa Ismail 			if (!child_listen_node) {
1689146b9756SMustafa Ismail 				ibdev_dbg(&iwdev->ibdev, "CM: listener memory allocation\n");
16902c4b14eaSShiraz Saleem 				ret = -ENOMEM;
1691146b9756SMustafa Ismail 				goto exit;
1692146b9756SMustafa Ismail 			}
1693146b9756SMustafa Ismail 
1694146b9756SMustafa Ismail 			cm_info->vlan_id = rdma_vlan_dev_vlan_id(ip_dev);
1695146b9756SMustafa Ismail 			cm_parent_listen_node->vlan_id = cm_info->vlan_id;
1696146b9756SMustafa Ismail 			memcpy(child_listen_node, cm_parent_listen_node,
1697146b9756SMustafa Ismail 			       sizeof(*child_listen_node));
1698146b9756SMustafa Ismail 			irdma_copy_ip_ntohl(child_listen_node->loc_addr,
1699146b9756SMustafa Ismail 					    ifp->addr.in6_u.u6_addr32);
1700146b9756SMustafa Ismail 			memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
1701146b9756SMustafa Ismail 			       sizeof(cm_info->loc_addr));
1702f877f22aSMustafa Ismail 			if (!iwdev->vsi.dscp_mode)
1703f877f22aSMustafa Ismail 				cm_info->user_pri =
1704f877f22aSMustafa Ismail 				irdma_iw_get_vlan_prio(child_listen_node->loc_addr,
1705f877f22aSMustafa Ismail 						       cm_info->user_pri,
1706f877f22aSMustafa Ismail 						       false);
1707f877f22aSMustafa Ismail 
1708146b9756SMustafa Ismail 			ret = irdma_manage_qhash(iwdev, cm_info,
1709146b9756SMustafa Ismail 						 IRDMA_QHASH_TYPE_TCP_SYN,
1710146b9756SMustafa Ismail 						 IRDMA_QHASH_MANAGE_TYPE_ADD,
1711146b9756SMustafa Ismail 						 NULL, true);
1712146b9756SMustafa Ismail 			if (ret) {
1713146b9756SMustafa Ismail 				kfree(child_listen_node);
1714146b9756SMustafa Ismail 				continue;
1715146b9756SMustafa Ismail 			}
1716146b9756SMustafa Ismail 
1717146b9756SMustafa Ismail 			trace_irdma_add_mqh_6(iwdev, child_listen_node,
1718146b9756SMustafa Ismail 					      ip_dev->dev_addr);
1719146b9756SMustafa Ismail 
1720146b9756SMustafa Ismail 			child_listen_node->qhash_set = true;
1721146b9756SMustafa Ismail 			spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
1722146b9756SMustafa Ismail 			list_add(&child_listen_node->child_listen_list,
1723146b9756SMustafa Ismail 				 &cm_parent_listen_node->child_listen_list);
1724146b9756SMustafa Ismail 			spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
1725146b9756SMustafa Ismail 			cm_parent_listen_node->cm_core->stats_listen_nodes_created++;
1726146b9756SMustafa Ismail 		}
1727146b9756SMustafa Ismail 	}
1728146b9756SMustafa Ismail exit:
1729146b9756SMustafa Ismail 	rtnl_unlock();
1730146b9756SMustafa Ismail 
1731146b9756SMustafa Ismail 	return ret;
1732146b9756SMustafa Ismail }
1733146b9756SMustafa Ismail 
1734146b9756SMustafa Ismail /**
1735146b9756SMustafa Ismail  * irdma_add_mqh_4 - Adds multiple qhashes for IPv4
1736146b9756SMustafa Ismail  * @iwdev: iWarp device
1737146b9756SMustafa Ismail  * @cm_info: CM info for parent listen node
1738146b9756SMustafa Ismail  * @cm_parent_listen_node: The parent listen node
1739146b9756SMustafa Ismail  *
1740146b9756SMustafa Ismail  * Adds a qhash and a child listen node for every IPv4 address
1741146b9756SMustafa Ismail  * on the adapter and adds the associated qhash filter
1742146b9756SMustafa Ismail  */
irdma_add_mqh_4(struct irdma_device * iwdev,struct irdma_cm_info * cm_info,struct irdma_cm_listener * cm_parent_listen_node)17432c4b14eaSShiraz Saleem static int irdma_add_mqh_4(struct irdma_device *iwdev,
17442c4b14eaSShiraz Saleem 			   struct irdma_cm_info *cm_info,
1745146b9756SMustafa Ismail 			   struct irdma_cm_listener *cm_parent_listen_node)
1746146b9756SMustafa Ismail {
1747146b9756SMustafa Ismail 	struct net_device *ip_dev;
1748146b9756SMustafa Ismail 	struct in_device *idev;
1749146b9756SMustafa Ismail 	struct irdma_cm_listener *child_listen_node;
1750146b9756SMustafa Ismail 	unsigned long flags;
1751146b9756SMustafa Ismail 	const struct in_ifaddr *ifa;
17522c4b14eaSShiraz Saleem 	int ret = 0;
1753146b9756SMustafa Ismail 
1754146b9756SMustafa Ismail 	rtnl_lock();
1755146b9756SMustafa Ismail 	for_each_netdev(&init_net, ip_dev) {
1756146b9756SMustafa Ismail 		if (!(ip_dev->flags & IFF_UP))
1757146b9756SMustafa Ismail 			continue;
1758146b9756SMustafa Ismail 
1759146b9756SMustafa Ismail 		if (((rdma_vlan_dev_vlan_id(ip_dev) >= VLAN_N_VID) ||
1760146b9756SMustafa Ismail 		     (rdma_vlan_dev_real_dev(ip_dev) != iwdev->netdev)) &&
1761146b9756SMustafa Ismail 		    ip_dev != iwdev->netdev)
1762146b9756SMustafa Ismail 			continue;
1763146b9756SMustafa Ismail 
1764146b9756SMustafa Ismail 		idev = in_dev_get(ip_dev);
17655d9745ceSNikita Zhandarovich 		if (!idev)
17665d9745ceSNikita Zhandarovich 			continue;
17675d9745ceSNikita Zhandarovich 
1768146b9756SMustafa Ismail 		in_dev_for_each_ifa_rtnl(ifa, idev) {
1769146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev,
1770146b9756SMustafa Ismail 				  "CM: Allocating child CM Listener forIP=%pI4, vlan_id=%d, MAC=%pM\n",
1771146b9756SMustafa Ismail 				  &ifa->ifa_address, rdma_vlan_dev_vlan_id(ip_dev),
1772146b9756SMustafa Ismail 				  ip_dev->dev_addr);
1773146b9756SMustafa Ismail 			child_listen_node = kzalloc(sizeof(*child_listen_node), GFP_KERNEL);
1774146b9756SMustafa Ismail 			cm_parent_listen_node->cm_core->stats_listen_nodes_created++;
1775146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev, "CM: Allocating child listener %p\n",
1776146b9756SMustafa Ismail 				  child_listen_node);
1777146b9756SMustafa Ismail 			if (!child_listen_node) {
1778146b9756SMustafa Ismail 				ibdev_dbg(&iwdev->ibdev, "CM: listener memory allocation\n");
1779146b9756SMustafa Ismail 				in_dev_put(idev);
17802c4b14eaSShiraz Saleem 				ret = -ENOMEM;
1781146b9756SMustafa Ismail 				goto exit;
1782146b9756SMustafa Ismail 			}
1783146b9756SMustafa Ismail 
1784146b9756SMustafa Ismail 			cm_info->vlan_id = rdma_vlan_dev_vlan_id(ip_dev);
1785146b9756SMustafa Ismail 			cm_parent_listen_node->vlan_id = cm_info->vlan_id;
1786146b9756SMustafa Ismail 			memcpy(child_listen_node, cm_parent_listen_node,
1787146b9756SMustafa Ismail 			       sizeof(*child_listen_node));
1788146b9756SMustafa Ismail 			child_listen_node->loc_addr[0] =
1789146b9756SMustafa Ismail 				ntohl(ifa->ifa_address);
1790146b9756SMustafa Ismail 			memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
1791146b9756SMustafa Ismail 			       sizeof(cm_info->loc_addr));
1792f877f22aSMustafa Ismail 			if (!iwdev->vsi.dscp_mode)
1793f877f22aSMustafa Ismail 				cm_info->user_pri =
1794f877f22aSMustafa Ismail 				irdma_iw_get_vlan_prio(child_listen_node->loc_addr,
1795f877f22aSMustafa Ismail 						       cm_info->user_pri,
1796f877f22aSMustafa Ismail 						       true);
1797146b9756SMustafa Ismail 			ret = irdma_manage_qhash(iwdev, cm_info,
1798146b9756SMustafa Ismail 						 IRDMA_QHASH_TYPE_TCP_SYN,
1799146b9756SMustafa Ismail 						 IRDMA_QHASH_MANAGE_TYPE_ADD,
1800146b9756SMustafa Ismail 						 NULL, true);
1801146b9756SMustafa Ismail 			if (ret) {
1802146b9756SMustafa Ismail 				kfree(child_listen_node);
1803146b9756SMustafa Ismail 				cm_parent_listen_node->cm_core
1804146b9756SMustafa Ismail 					->stats_listen_nodes_created--;
1805146b9756SMustafa Ismail 				continue;
1806146b9756SMustafa Ismail 			}
1807146b9756SMustafa Ismail 
1808146b9756SMustafa Ismail 			trace_irdma_add_mqh_4(iwdev, child_listen_node,
1809146b9756SMustafa Ismail 					      ip_dev->dev_addr);
1810146b9756SMustafa Ismail 
1811146b9756SMustafa Ismail 			child_listen_node->qhash_set = true;
1812146b9756SMustafa Ismail 			spin_lock_irqsave(&iwdev->cm_core.listen_list_lock,
1813146b9756SMustafa Ismail 					  flags);
1814146b9756SMustafa Ismail 			list_add(&child_listen_node->child_listen_list,
1815146b9756SMustafa Ismail 				 &cm_parent_listen_node->child_listen_list);
1816146b9756SMustafa Ismail 			spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
1817146b9756SMustafa Ismail 		}
1818146b9756SMustafa Ismail 		in_dev_put(idev);
1819146b9756SMustafa Ismail 	}
1820146b9756SMustafa Ismail exit:
1821146b9756SMustafa Ismail 	rtnl_unlock();
1822146b9756SMustafa Ismail 
1823146b9756SMustafa Ismail 	return ret;
1824146b9756SMustafa Ismail }
1825146b9756SMustafa Ismail 
1826146b9756SMustafa Ismail /**
1827146b9756SMustafa Ismail  * irdma_add_mqh - Adds multiple qhashes
1828146b9756SMustafa Ismail  * @iwdev: iWarp device
1829146b9756SMustafa Ismail  * @cm_info: CM info for parent listen node
1830146b9756SMustafa Ismail  * @cm_listen_node: The parent listen node
1831146b9756SMustafa Ismail  */
irdma_add_mqh(struct irdma_device * iwdev,struct irdma_cm_info * cm_info,struct irdma_cm_listener * cm_listen_node)18322c4b14eaSShiraz Saleem static int irdma_add_mqh(struct irdma_device *iwdev,
18332c4b14eaSShiraz Saleem 			 struct irdma_cm_info *cm_info,
1834146b9756SMustafa Ismail 			 struct irdma_cm_listener *cm_listen_node)
1835146b9756SMustafa Ismail {
1836146b9756SMustafa Ismail 	if (cm_info->ipv4)
1837146b9756SMustafa Ismail 		return irdma_add_mqh_4(iwdev, cm_info, cm_listen_node);
1838146b9756SMustafa Ismail 	else
1839146b9756SMustafa Ismail 		return irdma_add_mqh_6(iwdev, cm_info, cm_listen_node);
1840146b9756SMustafa Ismail }
1841146b9756SMustafa Ismail 
1842146b9756SMustafa Ismail /**
1843146b9756SMustafa Ismail  * irdma_reset_list_prep - add connection nodes slated for reset to list
1844146b9756SMustafa Ismail  * @cm_core: cm's core
1845146b9756SMustafa Ismail  * @listener: pointer to listener node
1846146b9756SMustafa Ismail  * @reset_list: a list to which cm_node will be selected
1847146b9756SMustafa Ismail  */
irdma_reset_list_prep(struct irdma_cm_core * cm_core,struct irdma_cm_listener * listener,struct list_head * reset_list)1848146b9756SMustafa Ismail static void irdma_reset_list_prep(struct irdma_cm_core *cm_core,
1849146b9756SMustafa Ismail 				  struct irdma_cm_listener *listener,
1850146b9756SMustafa Ismail 				  struct list_head *reset_list)
1851146b9756SMustafa Ismail {
1852146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
1853146b9756SMustafa Ismail 	int bkt;
1854146b9756SMustafa Ismail 
1855146b9756SMustafa Ismail 	hash_for_each_rcu(cm_core->cm_hash_tbl, bkt, cm_node, list) {
1856146b9756SMustafa Ismail 		if (cm_node->listener == listener &&
1857146b9756SMustafa Ismail 		    !cm_node->accelerated &&
1858146b9756SMustafa Ismail 		    refcount_inc_not_zero(&cm_node->refcnt))
1859146b9756SMustafa Ismail 			list_add(&cm_node->reset_entry, reset_list);
1860146b9756SMustafa Ismail 	}
1861146b9756SMustafa Ismail }
1862146b9756SMustafa Ismail 
1863146b9756SMustafa Ismail /**
1864146b9756SMustafa Ismail  * irdma_dec_refcnt_listen - delete listener and associated cm nodes
1865146b9756SMustafa Ismail  * @cm_core: cm's core
1866146b9756SMustafa Ismail  * @listener: pointer to listener node
1867146b9756SMustafa Ismail  * @free_hanging_nodes: to free associated cm_nodes
1868146b9756SMustafa Ismail  * @apbvt_del: flag to delete the apbvt
1869146b9756SMustafa Ismail  */
irdma_dec_refcnt_listen(struct irdma_cm_core * cm_core,struct irdma_cm_listener * listener,int free_hanging_nodes,bool apbvt_del)1870146b9756SMustafa Ismail static int irdma_dec_refcnt_listen(struct irdma_cm_core *cm_core,
1871146b9756SMustafa Ismail 				   struct irdma_cm_listener *listener,
1872146b9756SMustafa Ismail 				   int free_hanging_nodes, bool apbvt_del)
1873146b9756SMustafa Ismail {
1874146b9756SMustafa Ismail 	int err;
1875146b9756SMustafa Ismail 	struct list_head *list_pos;
1876146b9756SMustafa Ismail 	struct list_head *list_temp;
1877146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
1878146b9756SMustafa Ismail 	struct list_head reset_list;
1879146b9756SMustafa Ismail 	struct irdma_cm_info nfo;
1880146b9756SMustafa Ismail 	enum irdma_cm_node_state old_state;
1881146b9756SMustafa Ismail 	unsigned long flags;
1882146b9756SMustafa Ismail 
1883146b9756SMustafa Ismail 	trace_irdma_dec_refcnt_listen(listener, __builtin_return_address(0));
1884146b9756SMustafa Ismail 	/* free non-accelerated child nodes for this listener */
1885146b9756SMustafa Ismail 	INIT_LIST_HEAD(&reset_list);
1886146b9756SMustafa Ismail 	if (free_hanging_nodes) {
1887146b9756SMustafa Ismail 		rcu_read_lock();
1888146b9756SMustafa Ismail 		irdma_reset_list_prep(cm_core, listener, &reset_list);
1889146b9756SMustafa Ismail 		rcu_read_unlock();
1890146b9756SMustafa Ismail 	}
1891146b9756SMustafa Ismail 
1892146b9756SMustafa Ismail 	list_for_each_safe (list_pos, list_temp, &reset_list) {
1893146b9756SMustafa Ismail 		cm_node = container_of(list_pos, struct irdma_cm_node,
1894146b9756SMustafa Ismail 				       reset_entry);
1895146b9756SMustafa Ismail 		if (cm_node->state >= IRDMA_CM_STATE_FIN_WAIT1) {
1896146b9756SMustafa Ismail 			irdma_rem_ref_cm_node(cm_node);
1897146b9756SMustafa Ismail 			continue;
1898146b9756SMustafa Ismail 		}
1899146b9756SMustafa Ismail 
1900146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
1901146b9756SMustafa Ismail 		err = irdma_send_reset(cm_node);
1902146b9756SMustafa Ismail 		if (err) {
1903146b9756SMustafa Ismail 			cm_node->state = IRDMA_CM_STATE_CLOSED;
1904146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
1905146b9756SMustafa Ismail 				  "CM: send reset failed\n");
1906146b9756SMustafa Ismail 		} else {
1907146b9756SMustafa Ismail 			old_state = cm_node->state;
1908146b9756SMustafa Ismail 			cm_node->state = IRDMA_CM_STATE_LISTENER_DESTROYED;
1909146b9756SMustafa Ismail 			if (old_state != IRDMA_CM_STATE_MPAREQ_RCVD)
1910146b9756SMustafa Ismail 				irdma_rem_ref_cm_node(cm_node);
1911146b9756SMustafa Ismail 		}
1912146b9756SMustafa Ismail 	}
1913146b9756SMustafa Ismail 
1914146b9756SMustafa Ismail 	if (refcount_dec_and_test(&listener->refcnt)) {
1915146b9756SMustafa Ismail 		spin_lock_irqsave(&cm_core->listen_list_lock, flags);
1916146b9756SMustafa Ismail 		list_del(&listener->list);
1917146b9756SMustafa Ismail 		spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
1918146b9756SMustafa Ismail 
1919146b9756SMustafa Ismail 		if (apbvt_del)
1920146b9756SMustafa Ismail 			irdma_del_apbvt(listener->iwdev,
1921146b9756SMustafa Ismail 					listener->apbvt_entry);
1922146b9756SMustafa Ismail 		memcpy(nfo.loc_addr, listener->loc_addr, sizeof(nfo.loc_addr));
1923146b9756SMustafa Ismail 		nfo.loc_port = listener->loc_port;
1924146b9756SMustafa Ismail 		nfo.ipv4 = listener->ipv4;
1925146b9756SMustafa Ismail 		nfo.vlan_id = listener->vlan_id;
1926146b9756SMustafa Ismail 		nfo.user_pri = listener->user_pri;
1927146b9756SMustafa Ismail 		nfo.qh_qpid = listener->iwdev->vsi.ilq->qp_id;
1928146b9756SMustafa Ismail 
1929146b9756SMustafa Ismail 		if (!list_empty(&listener->child_listen_list)) {
1930146b9756SMustafa Ismail 			irdma_del_multiple_qhash(listener->iwdev, &nfo,
1931146b9756SMustafa Ismail 						 listener);
1932146b9756SMustafa Ismail 		} else {
1933146b9756SMustafa Ismail 			if (listener->qhash_set)
1934146b9756SMustafa Ismail 				irdma_manage_qhash(listener->iwdev,
1935146b9756SMustafa Ismail 						   &nfo,
1936146b9756SMustafa Ismail 						   IRDMA_QHASH_TYPE_TCP_SYN,
1937146b9756SMustafa Ismail 						   IRDMA_QHASH_MANAGE_TYPE_DELETE,
1938146b9756SMustafa Ismail 						   NULL, false);
1939146b9756SMustafa Ismail 		}
1940146b9756SMustafa Ismail 
1941146b9756SMustafa Ismail 		cm_core->stats_listen_destroyed++;
1942146b9756SMustafa Ismail 		cm_core->stats_listen_nodes_destroyed++;
1943146b9756SMustafa Ismail 		ibdev_dbg(&listener->iwdev->ibdev,
1944146b9756SMustafa Ismail 			  "CM: loc_port=0x%04x loc_addr=%pI4 cm_listen_node=%p cm_id=%p qhash_set=%d vlan_id=%d apbvt_del=%d\n",
1945146b9756SMustafa Ismail 			  listener->loc_port, listener->loc_addr, listener,
1946146b9756SMustafa Ismail 			  listener->cm_id, listener->qhash_set,
1947146b9756SMustafa Ismail 			  listener->vlan_id, apbvt_del);
1948146b9756SMustafa Ismail 		kfree(listener);
1949146b9756SMustafa Ismail 		listener = NULL;
1950146b9756SMustafa Ismail 		return 0;
1951146b9756SMustafa Ismail 	}
1952146b9756SMustafa Ismail 
1953146b9756SMustafa Ismail 	return -EINVAL;
1954146b9756SMustafa Ismail }
1955146b9756SMustafa Ismail 
1956146b9756SMustafa Ismail /**
1957146b9756SMustafa Ismail  * irdma_cm_del_listen - delete a listener
1958146b9756SMustafa Ismail  * @cm_core: cm's core
1959146b9756SMustafa Ismail  * @listener: passive connection's listener
1960146b9756SMustafa Ismail  * @apbvt_del: flag to delete apbvt
1961146b9756SMustafa Ismail  */
irdma_cm_del_listen(struct irdma_cm_core * cm_core,struct irdma_cm_listener * listener,bool apbvt_del)1962146b9756SMustafa Ismail static int irdma_cm_del_listen(struct irdma_cm_core *cm_core,
1963146b9756SMustafa Ismail 			       struct irdma_cm_listener *listener,
1964146b9756SMustafa Ismail 			       bool apbvt_del)
1965146b9756SMustafa Ismail {
1966146b9756SMustafa Ismail 	listener->listener_state = IRDMA_CM_LISTENER_PASSIVE_STATE;
1967146b9756SMustafa Ismail 	listener->cm_id = NULL;
1968146b9756SMustafa Ismail 
1969146b9756SMustafa Ismail 	return irdma_dec_refcnt_listen(cm_core, listener, 1, apbvt_del);
1970146b9756SMustafa Ismail }
1971146b9756SMustafa Ismail 
1972146b9756SMustafa Ismail /**
1973146b9756SMustafa Ismail  * irdma_addr_resolve_neigh - resolve neighbor address
1974146b9756SMustafa Ismail  * @iwdev: iwarp device structure
1975146b9756SMustafa Ismail  * @src_ip: local ip address
1976146b9756SMustafa Ismail  * @dst_ip: remote ip address
1977146b9756SMustafa Ismail  * @arpindex: if there is an arp entry
1978146b9756SMustafa Ismail  */
irdma_addr_resolve_neigh(struct irdma_device * iwdev,u32 src_ip,u32 dst_ip,int arpindex)1979146b9756SMustafa Ismail static int irdma_addr_resolve_neigh(struct irdma_device *iwdev, u32 src_ip,
1980146b9756SMustafa Ismail 				    u32 dst_ip, int arpindex)
1981146b9756SMustafa Ismail {
1982146b9756SMustafa Ismail 	struct rtable *rt;
1983146b9756SMustafa Ismail 	struct neighbour *neigh;
1984146b9756SMustafa Ismail 	int rc = arpindex;
1985146b9756SMustafa Ismail 	__be32 dst_ipaddr = htonl(dst_ip);
1986146b9756SMustafa Ismail 	__be32 src_ipaddr = htonl(src_ip);
1987146b9756SMustafa Ismail 
1988146b9756SMustafa Ismail 	rt = ip_route_output(&init_net, dst_ipaddr, src_ipaddr, 0, 0);
1989146b9756SMustafa Ismail 	if (IS_ERR(rt)) {
1990146b9756SMustafa Ismail 		ibdev_dbg(&iwdev->ibdev, "CM: ip_route_output fail\n");
1991146b9756SMustafa Ismail 		return -EINVAL;
1992146b9756SMustafa Ismail 	}
1993146b9756SMustafa Ismail 
1994146b9756SMustafa Ismail 	neigh = dst_neigh_lookup(&rt->dst, &dst_ipaddr);
1995146b9756SMustafa Ismail 	if (!neigh)
1996146b9756SMustafa Ismail 		goto exit;
1997146b9756SMustafa Ismail 
1998146b9756SMustafa Ismail 	if (neigh->nud_state & NUD_VALID)
1999146b9756SMustafa Ismail 		rc = irdma_add_arp(iwdev->rf, &dst_ip, true, neigh->ha);
2000146b9756SMustafa Ismail 	else
2001146b9756SMustafa Ismail 		neigh_event_send(neigh, NULL);
2002146b9756SMustafa Ismail 	if (neigh)
2003146b9756SMustafa Ismail 		neigh_release(neigh);
2004146b9756SMustafa Ismail exit:
2005146b9756SMustafa Ismail 	ip_rt_put(rt);
2006146b9756SMustafa Ismail 
2007146b9756SMustafa Ismail 	return rc;
2008146b9756SMustafa Ismail }
2009146b9756SMustafa Ismail 
2010146b9756SMustafa Ismail /**
2011146b9756SMustafa Ismail  * irdma_get_dst_ipv6 - get destination cache entry via ipv6 lookup
2012146b9756SMustafa Ismail  * @src_addr: local ipv6 sock address
2013146b9756SMustafa Ismail  * @dst_addr: destination ipv6 sock address
2014146b9756SMustafa Ismail  */
irdma_get_dst_ipv6(struct sockaddr_in6 * src_addr,struct sockaddr_in6 * dst_addr)2015146b9756SMustafa Ismail static struct dst_entry *irdma_get_dst_ipv6(struct sockaddr_in6 *src_addr,
2016146b9756SMustafa Ismail 					    struct sockaddr_in6 *dst_addr)
2017146b9756SMustafa Ismail {
2018146b9756SMustafa Ismail 	struct dst_entry *dst = NULL;
2019146b9756SMustafa Ismail 
2020146b9756SMustafa Ismail 	if ((IS_ENABLED(CONFIG_IPV6))) {
2021146b9756SMustafa Ismail 		struct flowi6 fl6 = {};
2022146b9756SMustafa Ismail 
2023146b9756SMustafa Ismail 		fl6.daddr = dst_addr->sin6_addr;
2024146b9756SMustafa Ismail 		fl6.saddr = src_addr->sin6_addr;
2025146b9756SMustafa Ismail 		if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL)
2026146b9756SMustafa Ismail 			fl6.flowi6_oif = dst_addr->sin6_scope_id;
2027146b9756SMustafa Ismail 
2028146b9756SMustafa Ismail 		dst = ip6_route_output(&init_net, NULL, &fl6);
2029146b9756SMustafa Ismail 	}
2030146b9756SMustafa Ismail 
2031146b9756SMustafa Ismail 	return dst;
2032146b9756SMustafa Ismail }
2033146b9756SMustafa Ismail 
2034146b9756SMustafa Ismail /**
2035146b9756SMustafa Ismail  * irdma_addr_resolve_neigh_ipv6 - resolve neighbor ipv6 address
2036146b9756SMustafa Ismail  * @iwdev: iwarp device structure
2037146b9756SMustafa Ismail  * @src: local ip address
2038146b9756SMustafa Ismail  * @dest: remote ip address
2039146b9756SMustafa Ismail  * @arpindex: if there is an arp entry
2040146b9756SMustafa Ismail  */
irdma_addr_resolve_neigh_ipv6(struct irdma_device * iwdev,u32 * src,u32 * dest,int arpindex)2041146b9756SMustafa Ismail static int irdma_addr_resolve_neigh_ipv6(struct irdma_device *iwdev, u32 *src,
2042146b9756SMustafa Ismail 					 u32 *dest, int arpindex)
2043146b9756SMustafa Ismail {
2044146b9756SMustafa Ismail 	struct neighbour *neigh;
2045146b9756SMustafa Ismail 	int rc = arpindex;
2046146b9756SMustafa Ismail 	struct dst_entry *dst;
2047146b9756SMustafa Ismail 	struct sockaddr_in6 dst_addr = {};
2048146b9756SMustafa Ismail 	struct sockaddr_in6 src_addr = {};
2049146b9756SMustafa Ismail 
2050146b9756SMustafa Ismail 	dst_addr.sin6_family = AF_INET6;
2051146b9756SMustafa Ismail 	irdma_copy_ip_htonl(dst_addr.sin6_addr.in6_u.u6_addr32, dest);
2052146b9756SMustafa Ismail 	src_addr.sin6_family = AF_INET6;
2053146b9756SMustafa Ismail 	irdma_copy_ip_htonl(src_addr.sin6_addr.in6_u.u6_addr32, src);
2054146b9756SMustafa Ismail 	dst = irdma_get_dst_ipv6(&src_addr, &dst_addr);
2055146b9756SMustafa Ismail 	if (!dst || dst->error) {
2056146b9756SMustafa Ismail 		if (dst) {
2057146b9756SMustafa Ismail 			dst_release(dst);
2058146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev,
2059146b9756SMustafa Ismail 				  "CM: ip6_route_output returned dst->error = %d\n",
2060146b9756SMustafa Ismail 				  dst->error);
2061146b9756SMustafa Ismail 		}
2062146b9756SMustafa Ismail 		return -EINVAL;
2063146b9756SMustafa Ismail 	}
2064146b9756SMustafa Ismail 
2065146b9756SMustafa Ismail 	neigh = dst_neigh_lookup(dst, dst_addr.sin6_addr.in6_u.u6_addr32);
2066146b9756SMustafa Ismail 	if (!neigh)
2067146b9756SMustafa Ismail 		goto exit;
2068146b9756SMustafa Ismail 
2069146b9756SMustafa Ismail 	ibdev_dbg(&iwdev->ibdev, "CM: dst_neigh_lookup MAC=%pM\n",
2070146b9756SMustafa Ismail 		  neigh->ha);
2071146b9756SMustafa Ismail 
2072146b9756SMustafa Ismail 	trace_irdma_addr_resolve(iwdev, neigh->ha);
2073146b9756SMustafa Ismail 
2074146b9756SMustafa Ismail 	if (neigh->nud_state & NUD_VALID)
2075146b9756SMustafa Ismail 		rc = irdma_add_arp(iwdev->rf, dest, false, neigh->ha);
2076146b9756SMustafa Ismail 	else
2077146b9756SMustafa Ismail 		neigh_event_send(neigh, NULL);
2078146b9756SMustafa Ismail 	if (neigh)
2079146b9756SMustafa Ismail 		neigh_release(neigh);
2080146b9756SMustafa Ismail exit:
2081146b9756SMustafa Ismail 	dst_release(dst);
2082146b9756SMustafa Ismail 
2083146b9756SMustafa Ismail 	return rc;
2084146b9756SMustafa Ismail }
2085146b9756SMustafa Ismail 
2086146b9756SMustafa Ismail /**
2087146b9756SMustafa Ismail  * irdma_find_node - find a cm node that matches the reference cm node
2088146b9756SMustafa Ismail  * @cm_core: cm's core
2089146b9756SMustafa Ismail  * @rem_port: remote tcp port num
2090146b9756SMustafa Ismail  * @rem_addr: remote ip addr
2091146b9756SMustafa Ismail  * @loc_port: local tcp port num
2092146b9756SMustafa Ismail  * @loc_addr: local ip addr
2093146b9756SMustafa Ismail  * @vlan_id: local VLAN ID
2094146b9756SMustafa Ismail  */
irdma_find_node(struct irdma_cm_core * cm_core,u16 rem_port,u32 * rem_addr,u16 loc_port,u32 * loc_addr,u16 vlan_id)2095146b9756SMustafa Ismail struct irdma_cm_node *irdma_find_node(struct irdma_cm_core *cm_core,
2096146b9756SMustafa Ismail 				      u16 rem_port, u32 *rem_addr, u16 loc_port,
2097146b9756SMustafa Ismail 				      u32 *loc_addr, u16 vlan_id)
2098146b9756SMustafa Ismail {
2099146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
2100146b9756SMustafa Ismail 	u32 key = (rem_port << 16) | loc_port;
2101146b9756SMustafa Ismail 
2102146b9756SMustafa Ismail 	rcu_read_lock();
2103146b9756SMustafa Ismail 	hash_for_each_possible_rcu(cm_core->cm_hash_tbl, cm_node, list, key) {
2104146b9756SMustafa Ismail 		if (cm_node->vlan_id == vlan_id &&
2105146b9756SMustafa Ismail 		    cm_node->loc_port == loc_port && cm_node->rem_port == rem_port &&
2106146b9756SMustafa Ismail 		    !memcmp(cm_node->loc_addr, loc_addr, sizeof(cm_node->loc_addr)) &&
2107146b9756SMustafa Ismail 		    !memcmp(cm_node->rem_addr, rem_addr, sizeof(cm_node->rem_addr))) {
2108146b9756SMustafa Ismail 			if (!refcount_inc_not_zero(&cm_node->refcnt))
2109146b9756SMustafa Ismail 				goto exit;
2110146b9756SMustafa Ismail 			rcu_read_unlock();
2111146b9756SMustafa Ismail 			trace_irdma_find_node(cm_node, 0, NULL);
2112146b9756SMustafa Ismail 			return cm_node;
2113146b9756SMustafa Ismail 		}
2114146b9756SMustafa Ismail 	}
2115146b9756SMustafa Ismail 
2116146b9756SMustafa Ismail exit:
2117146b9756SMustafa Ismail 	rcu_read_unlock();
2118146b9756SMustafa Ismail 
2119146b9756SMustafa Ismail 	/* no owner node */
2120146b9756SMustafa Ismail 	return NULL;
2121146b9756SMustafa Ismail }
2122146b9756SMustafa Ismail 
2123146b9756SMustafa Ismail /**
2124146b9756SMustafa Ismail  * irdma_add_hte_node - add a cm node to the hash table
2125146b9756SMustafa Ismail  * @cm_core: cm's core
2126146b9756SMustafa Ismail  * @cm_node: connection's node
2127146b9756SMustafa Ismail  */
irdma_add_hte_node(struct irdma_cm_core * cm_core,struct irdma_cm_node * cm_node)2128146b9756SMustafa Ismail static void irdma_add_hte_node(struct irdma_cm_core *cm_core,
2129146b9756SMustafa Ismail 			       struct irdma_cm_node *cm_node)
2130146b9756SMustafa Ismail {
2131146b9756SMustafa Ismail 	unsigned long flags;
2132146b9756SMustafa Ismail 	u32 key = (cm_node->rem_port << 16) | cm_node->loc_port;
2133146b9756SMustafa Ismail 
2134146b9756SMustafa Ismail 	spin_lock_irqsave(&cm_core->ht_lock, flags);
2135146b9756SMustafa Ismail 	hash_add_rcu(cm_core->cm_hash_tbl, &cm_node->list, key);
2136146b9756SMustafa Ismail 	spin_unlock_irqrestore(&cm_core->ht_lock, flags);
2137146b9756SMustafa Ismail }
2138146b9756SMustafa Ismail 
2139146b9756SMustafa Ismail /**
2140146b9756SMustafa Ismail  * irdma_ipv4_is_lpb - check if loopback
2141146b9756SMustafa Ismail  * @loc_addr: local addr to compare
2142146b9756SMustafa Ismail  * @rem_addr: remote address
2143146b9756SMustafa Ismail  */
irdma_ipv4_is_lpb(u32 loc_addr,u32 rem_addr)2144146b9756SMustafa Ismail bool irdma_ipv4_is_lpb(u32 loc_addr, u32 rem_addr)
2145146b9756SMustafa Ismail {
2146146b9756SMustafa Ismail 	return ipv4_is_loopback(htonl(rem_addr)) || (loc_addr == rem_addr);
2147146b9756SMustafa Ismail }
2148146b9756SMustafa Ismail 
2149146b9756SMustafa Ismail /**
2150146b9756SMustafa Ismail  * irdma_ipv6_is_lpb - check if loopback
2151146b9756SMustafa Ismail  * @loc_addr: local addr to compare
2152146b9756SMustafa Ismail  * @rem_addr: remote address
2153146b9756SMustafa Ismail  */
irdma_ipv6_is_lpb(u32 * loc_addr,u32 * rem_addr)2154146b9756SMustafa Ismail bool irdma_ipv6_is_lpb(u32 *loc_addr, u32 *rem_addr)
2155146b9756SMustafa Ismail {
2156146b9756SMustafa Ismail 	struct in6_addr raddr6;
2157146b9756SMustafa Ismail 
2158146b9756SMustafa Ismail 	irdma_copy_ip_htonl(raddr6.in6_u.u6_addr32, rem_addr);
2159146b9756SMustafa Ismail 
2160146b9756SMustafa Ismail 	return !memcmp(loc_addr, rem_addr, 16) || ipv6_addr_loopback(&raddr6);
2161146b9756SMustafa Ismail }
2162146b9756SMustafa Ismail 
2163146b9756SMustafa Ismail /**
2164146b9756SMustafa Ismail  * irdma_cm_create_ah - create a cm address handle
2165146b9756SMustafa Ismail  * @cm_node: The connection manager node to create AH for
2166146b9756SMustafa Ismail  * @wait: Provides option to wait for ah creation or not
2167146b9756SMustafa Ismail  */
irdma_cm_create_ah(struct irdma_cm_node * cm_node,bool wait)2168146b9756SMustafa Ismail static int irdma_cm_create_ah(struct irdma_cm_node *cm_node, bool wait)
2169146b9756SMustafa Ismail {
2170146b9756SMustafa Ismail 	struct irdma_ah_info ah_info = {};
2171146b9756SMustafa Ismail 	struct irdma_device *iwdev = cm_node->iwdev;
2172146b9756SMustafa Ismail 
2173146b9756SMustafa Ismail 	ether_addr_copy(ah_info.mac_addr, iwdev->netdev->dev_addr);
2174146b9756SMustafa Ismail 
2175146b9756SMustafa Ismail 	ah_info.hop_ttl = 0x40;
2176146b9756SMustafa Ismail 	ah_info.tc_tos = cm_node->tos;
2177146b9756SMustafa Ismail 	ah_info.vsi = &iwdev->vsi;
2178146b9756SMustafa Ismail 
2179146b9756SMustafa Ismail 	if (cm_node->ipv4) {
2180146b9756SMustafa Ismail 		ah_info.ipv4_valid = true;
2181146b9756SMustafa Ismail 		ah_info.dest_ip_addr[0] = cm_node->rem_addr[0];
2182146b9756SMustafa Ismail 		ah_info.src_ip_addr[0] = cm_node->loc_addr[0];
2183146b9756SMustafa Ismail 		ah_info.do_lpbk = irdma_ipv4_is_lpb(ah_info.src_ip_addr[0],
2184146b9756SMustafa Ismail 						    ah_info.dest_ip_addr[0]);
2185146b9756SMustafa Ismail 	} else {
2186146b9756SMustafa Ismail 		memcpy(ah_info.dest_ip_addr, cm_node->rem_addr,
2187146b9756SMustafa Ismail 		       sizeof(ah_info.dest_ip_addr));
2188146b9756SMustafa Ismail 		memcpy(ah_info.src_ip_addr, cm_node->loc_addr,
2189146b9756SMustafa Ismail 		       sizeof(ah_info.src_ip_addr));
2190146b9756SMustafa Ismail 		ah_info.do_lpbk = irdma_ipv6_is_lpb(ah_info.src_ip_addr,
2191146b9756SMustafa Ismail 						    ah_info.dest_ip_addr);
2192146b9756SMustafa Ismail 	}
2193146b9756SMustafa Ismail 
2194146b9756SMustafa Ismail 	ah_info.vlan_tag = cm_node->vlan_id;
2195146b9756SMustafa Ismail 	if (cm_node->vlan_id < VLAN_N_VID) {
2196146b9756SMustafa Ismail 		ah_info.insert_vlan_tag = 1;
2197146b9756SMustafa Ismail 		ah_info.vlan_tag |= cm_node->user_pri << VLAN_PRIO_SHIFT;
2198146b9756SMustafa Ismail 	}
2199146b9756SMustafa Ismail 
2200146b9756SMustafa Ismail 	ah_info.dst_arpindex =
2201146b9756SMustafa Ismail 		irdma_arp_table(iwdev->rf, ah_info.dest_ip_addr,
2202146b9756SMustafa Ismail 				ah_info.ipv4_valid, NULL, IRDMA_ARP_RESOLVE);
2203146b9756SMustafa Ismail 
2204146b9756SMustafa Ismail 	if (irdma_puda_create_ah(&iwdev->rf->sc_dev, &ah_info, wait,
2205146b9756SMustafa Ismail 				 IRDMA_PUDA_RSRC_TYPE_ILQ, cm_node,
2206146b9756SMustafa Ismail 				 &cm_node->ah))
2207146b9756SMustafa Ismail 		return -ENOMEM;
2208146b9756SMustafa Ismail 
2209146b9756SMustafa Ismail 	trace_irdma_create_ah(cm_node);
2210146b9756SMustafa Ismail 	return 0;
2211146b9756SMustafa Ismail }
2212146b9756SMustafa Ismail 
2213146b9756SMustafa Ismail /**
2214146b9756SMustafa Ismail  * irdma_cm_free_ah - free a cm address handle
2215146b9756SMustafa Ismail  * @cm_node: The connection manager node to create AH for
2216146b9756SMustafa Ismail  */
irdma_cm_free_ah(struct irdma_cm_node * cm_node)2217146b9756SMustafa Ismail static void irdma_cm_free_ah(struct irdma_cm_node *cm_node)
2218146b9756SMustafa Ismail {
2219146b9756SMustafa Ismail 	struct irdma_device *iwdev = cm_node->iwdev;
2220146b9756SMustafa Ismail 
2221146b9756SMustafa Ismail 	trace_irdma_cm_free_ah(cm_node);
2222146b9756SMustafa Ismail 	irdma_puda_free_ah(&iwdev->rf->sc_dev, cm_node->ah);
2223146b9756SMustafa Ismail 	cm_node->ah = NULL;
2224146b9756SMustafa Ismail }
2225146b9756SMustafa Ismail 
2226146b9756SMustafa Ismail /**
2227146b9756SMustafa Ismail  * irdma_make_cm_node - create a new instance of a cm node
2228146b9756SMustafa Ismail  * @cm_core: cm's core
2229146b9756SMustafa Ismail  * @iwdev: iwarp device structure
2230146b9756SMustafa Ismail  * @cm_info: quad info for connection
2231146b9756SMustafa Ismail  * @listener: passive connection's listener
2232146b9756SMustafa Ismail  */
2233146b9756SMustafa Ismail static struct irdma_cm_node *
irdma_make_cm_node(struct irdma_cm_core * cm_core,struct irdma_device * iwdev,struct irdma_cm_info * cm_info,struct irdma_cm_listener * listener)2234146b9756SMustafa Ismail irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,
2235146b9756SMustafa Ismail 		   struct irdma_cm_info *cm_info,
2236146b9756SMustafa Ismail 		   struct irdma_cm_listener *listener)
2237146b9756SMustafa Ismail {
2238146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
2239146b9756SMustafa Ismail 	int oldarpindex;
2240146b9756SMustafa Ismail 	int arpindex;
2241146b9756SMustafa Ismail 	struct net_device *netdev = iwdev->netdev;
2242146b9756SMustafa Ismail 
2243146b9756SMustafa Ismail 	/* create an hte and cm_node for this instance */
2244146b9756SMustafa Ismail 	cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);
2245146b9756SMustafa Ismail 	if (!cm_node)
2246146b9756SMustafa Ismail 		return NULL;
2247146b9756SMustafa Ismail 
2248146b9756SMustafa Ismail 	/* set our node specific transport info */
2249146b9756SMustafa Ismail 	cm_node->ipv4 = cm_info->ipv4;
2250146b9756SMustafa Ismail 	cm_node->vlan_id = cm_info->vlan_id;
225183483055SMustafa Ismail 	if (cm_node->vlan_id >= VLAN_N_VID && iwdev->dcb_vlan_mode)
2252146b9756SMustafa Ismail 		cm_node->vlan_id = 0;
2253146b9756SMustafa Ismail 	cm_node->tos = cm_info->tos;
2254146b9756SMustafa Ismail 	cm_node->user_pri = cm_info->user_pri;
2255146b9756SMustafa Ismail 	if (listener) {
2256146b9756SMustafa Ismail 		if (listener->tos != cm_info->tos)
2257146b9756SMustafa Ismail 			ibdev_warn(&iwdev->ibdev,
2258146b9756SMustafa Ismail 				   "application TOS[%d] and remote client TOS[%d] mismatch\n",
2259146b9756SMustafa Ismail 				   listener->tos, cm_info->tos);
22604b860c91SMustafa Ismail 		if (iwdev->vsi.dscp_mode) {
22614b860c91SMustafa Ismail 			cm_node->user_pri = listener->user_pri;
22624b860c91SMustafa Ismail 		} else {
2263146b9756SMustafa Ismail 			cm_node->tos = max(listener->tos, cm_info->tos);
2264146b9756SMustafa Ismail 			cm_node->user_pri = rt_tos2priority(cm_node->tos);
2265f877f22aSMustafa Ismail 			cm_node->user_pri =
2266f877f22aSMustafa Ismail 				irdma_iw_get_vlan_prio(cm_info->loc_addr,
2267f877f22aSMustafa Ismail 						       cm_node->user_pri,
2268f877f22aSMustafa Ismail 						       cm_info->ipv4);
22694b860c91SMustafa Ismail 		}
2270146b9756SMustafa Ismail 		ibdev_dbg(&iwdev->ibdev,
2271146b9756SMustafa Ismail 			  "DCB: listener: TOS:[%d] UP:[%d]\n", cm_node->tos,
2272146b9756SMustafa Ismail 			  cm_node->user_pri);
2273146b9756SMustafa Ismail 		trace_irdma_listener_tos(iwdev, cm_node->tos,
2274146b9756SMustafa Ismail 					 cm_node->user_pri);
2275146b9756SMustafa Ismail 	}
2276146b9756SMustafa Ismail 	memcpy(cm_node->loc_addr, cm_info->loc_addr, sizeof(cm_node->loc_addr));
2277146b9756SMustafa Ismail 	memcpy(cm_node->rem_addr, cm_info->rem_addr, sizeof(cm_node->rem_addr));
2278146b9756SMustafa Ismail 	cm_node->loc_port = cm_info->loc_port;
2279146b9756SMustafa Ismail 	cm_node->rem_port = cm_info->rem_port;
2280146b9756SMustafa Ismail 
2281146b9756SMustafa Ismail 	cm_node->mpa_frame_rev = IRDMA_CM_DEFAULT_MPA_VER;
2282146b9756SMustafa Ismail 	cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
2283146b9756SMustafa Ismail 	cm_node->iwdev = iwdev;
2284146b9756SMustafa Ismail 	cm_node->dev = &iwdev->rf->sc_dev;
2285146b9756SMustafa Ismail 
2286146b9756SMustafa Ismail 	cm_node->ird_size = cm_node->dev->hw_attrs.max_hw_ird;
2287146b9756SMustafa Ismail 	cm_node->ord_size = cm_node->dev->hw_attrs.max_hw_ord;
2288146b9756SMustafa Ismail 
2289146b9756SMustafa Ismail 	cm_node->listener = listener;
2290146b9756SMustafa Ismail 	cm_node->cm_id = cm_info->cm_id;
2291146b9756SMustafa Ismail 	ether_addr_copy(cm_node->loc_mac, netdev->dev_addr);
2292146b9756SMustafa Ismail 	spin_lock_init(&cm_node->retrans_list_lock);
2293146b9756SMustafa Ismail 	cm_node->ack_rcvd = false;
2294146b9756SMustafa Ismail 
2295146b9756SMustafa Ismail 	init_completion(&cm_node->establish_comp);
2296146b9756SMustafa Ismail 	refcount_set(&cm_node->refcnt, 1);
2297146b9756SMustafa Ismail 	/* associate our parent CM core */
2298146b9756SMustafa Ismail 	cm_node->cm_core = cm_core;
2299146b9756SMustafa Ismail 	cm_node->tcp_cntxt.loc_id = IRDMA_CM_DEFAULT_LOCAL_ID;
2300146b9756SMustafa Ismail 	cm_node->tcp_cntxt.rcv_wscale = iwdev->rcv_wscale;
2301146b9756SMustafa Ismail 	cm_node->tcp_cntxt.rcv_wnd = iwdev->rcv_wnd >> cm_node->tcp_cntxt.rcv_wscale;
2302146b9756SMustafa Ismail 	if (cm_node->ipv4) {
2303146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num = secure_tcp_seq(htonl(cm_node->loc_addr[0]),
2304146b9756SMustafa Ismail 								htonl(cm_node->rem_addr[0]),
2305146b9756SMustafa Ismail 								htons(cm_node->loc_port),
2306146b9756SMustafa Ismail 								htons(cm_node->rem_port));
2307146b9756SMustafa Ismail 		cm_node->tcp_cntxt.mss = iwdev->vsi.mtu - IRDMA_MTU_TO_MSS_IPV4;
2308146b9756SMustafa Ismail 	} else if (IS_ENABLED(CONFIG_IPV6)) {
2309146b9756SMustafa Ismail 		__be32 loc[4] = {
2310146b9756SMustafa Ismail 			htonl(cm_node->loc_addr[0]), htonl(cm_node->loc_addr[1]),
2311146b9756SMustafa Ismail 			htonl(cm_node->loc_addr[2]), htonl(cm_node->loc_addr[3])
2312146b9756SMustafa Ismail 		};
2313146b9756SMustafa Ismail 		__be32 rem[4] = {
2314146b9756SMustafa Ismail 			htonl(cm_node->rem_addr[0]), htonl(cm_node->rem_addr[1]),
2315146b9756SMustafa Ismail 			htonl(cm_node->rem_addr[2]), htonl(cm_node->rem_addr[3])
2316146b9756SMustafa Ismail 		};
2317146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num = secure_tcpv6_seq(loc, rem,
2318146b9756SMustafa Ismail 								  htons(cm_node->loc_port),
2319146b9756SMustafa Ismail 								  htons(cm_node->rem_port));
2320146b9756SMustafa Ismail 		cm_node->tcp_cntxt.mss = iwdev->vsi.mtu - IRDMA_MTU_TO_MSS_IPV6;
2321146b9756SMustafa Ismail 	}
2322146b9756SMustafa Ismail 
2323146b9756SMustafa Ismail 	if ((cm_node->ipv4 &&
2324146b9756SMustafa Ismail 	     irdma_ipv4_is_lpb(cm_node->loc_addr[0], cm_node->rem_addr[0])) ||
2325146b9756SMustafa Ismail 	    (!cm_node->ipv4 &&
2326146b9756SMustafa Ismail 	     irdma_ipv6_is_lpb(cm_node->loc_addr, cm_node->rem_addr))) {
2327146b9756SMustafa Ismail 		cm_node->do_lpb = true;
2328146b9756SMustafa Ismail 		arpindex = irdma_arp_table(iwdev->rf, cm_node->rem_addr,
2329146b9756SMustafa Ismail 					   cm_node->ipv4, NULL,
2330146b9756SMustafa Ismail 					   IRDMA_ARP_RESOLVE);
2331146b9756SMustafa Ismail 	} else {
2332146b9756SMustafa Ismail 		oldarpindex = irdma_arp_table(iwdev->rf, cm_node->rem_addr,
2333146b9756SMustafa Ismail 					      cm_node->ipv4, NULL,
2334146b9756SMustafa Ismail 					      IRDMA_ARP_RESOLVE);
2335146b9756SMustafa Ismail 		if (cm_node->ipv4)
2336146b9756SMustafa Ismail 			arpindex = irdma_addr_resolve_neigh(iwdev,
2337146b9756SMustafa Ismail 							    cm_info->loc_addr[0],
2338146b9756SMustafa Ismail 							    cm_info->rem_addr[0],
2339146b9756SMustafa Ismail 							    oldarpindex);
2340146b9756SMustafa Ismail 		else if (IS_ENABLED(CONFIG_IPV6))
2341146b9756SMustafa Ismail 			arpindex = irdma_addr_resolve_neigh_ipv6(iwdev,
2342146b9756SMustafa Ismail 								 cm_info->loc_addr,
2343146b9756SMustafa Ismail 								 cm_info->rem_addr,
2344146b9756SMustafa Ismail 								 oldarpindex);
2345146b9756SMustafa Ismail 		else
2346146b9756SMustafa Ismail 			arpindex = -EINVAL;
2347146b9756SMustafa Ismail 	}
2348146b9756SMustafa Ismail 
2349146b9756SMustafa Ismail 	if (arpindex < 0)
2350146b9756SMustafa Ismail 		goto err;
2351146b9756SMustafa Ismail 
2352146b9756SMustafa Ismail 	ether_addr_copy(cm_node->rem_mac,
2353146b9756SMustafa Ismail 			iwdev->rf->arp_table[arpindex].mac_addr);
2354146b9756SMustafa Ismail 	irdma_add_hte_node(cm_core, cm_node);
2355146b9756SMustafa Ismail 	cm_core->stats_nodes_created++;
2356146b9756SMustafa Ismail 	return cm_node;
2357146b9756SMustafa Ismail 
2358146b9756SMustafa Ismail err:
2359146b9756SMustafa Ismail 	kfree(cm_node);
2360146b9756SMustafa Ismail 
2361146b9756SMustafa Ismail 	return NULL;
2362146b9756SMustafa Ismail }
2363146b9756SMustafa Ismail 
irdma_destroy_connection(struct irdma_cm_node * cm_node)23642df6d895SShiraz Saleem static void irdma_destroy_connection(struct irdma_cm_node *cm_node)
2365146b9756SMustafa Ismail {
2366146b9756SMustafa Ismail 	struct irdma_cm_core *cm_core = cm_node->cm_core;
2367146b9756SMustafa Ismail 	struct irdma_qp *iwqp;
2368146b9756SMustafa Ismail 	struct irdma_cm_info nfo;
2369146b9756SMustafa Ismail 
2370146b9756SMustafa Ismail 	/* if the node is destroyed before connection was accelerated */
2371146b9756SMustafa Ismail 	if (!cm_node->accelerated && cm_node->accept_pend) {
2372146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
2373146b9756SMustafa Ismail 			  "CM: node destroyed before established\n");
2374146b9756SMustafa Ismail 		atomic_dec(&cm_node->listener->pend_accepts_cnt);
2375146b9756SMustafa Ismail 	}
2376146b9756SMustafa Ismail 	if (cm_node->close_entry)
2377146b9756SMustafa Ismail 		irdma_handle_close_entry(cm_node, 0);
2378146b9756SMustafa Ismail 	if (cm_node->listener) {
2379146b9756SMustafa Ismail 		irdma_dec_refcnt_listen(cm_core, cm_node->listener, 0, true);
2380146b9756SMustafa Ismail 	} else {
2381146b9756SMustafa Ismail 		if (cm_node->apbvt_set) {
2382146b9756SMustafa Ismail 			irdma_del_apbvt(cm_node->iwdev, cm_node->apbvt_entry);
2383146b9756SMustafa Ismail 			cm_node->apbvt_set = 0;
2384146b9756SMustafa Ismail 		}
2385146b9756SMustafa Ismail 		irdma_get_addr_info(cm_node, &nfo);
2386146b9756SMustafa Ismail 		if (cm_node->qhash_set) {
2387146b9756SMustafa Ismail 			nfo.qh_qpid = cm_node->iwdev->vsi.ilq->qp_id;
2388146b9756SMustafa Ismail 			irdma_manage_qhash(cm_node->iwdev, &nfo,
2389146b9756SMustafa Ismail 					   IRDMA_QHASH_TYPE_TCP_ESTABLISHED,
2390146b9756SMustafa Ismail 					   IRDMA_QHASH_MANAGE_TYPE_DELETE, NULL,
2391146b9756SMustafa Ismail 					   false);
2392146b9756SMustafa Ismail 			cm_node->qhash_set = 0;
2393146b9756SMustafa Ismail 		}
2394146b9756SMustafa Ismail 	}
2395146b9756SMustafa Ismail 
2396146b9756SMustafa Ismail 	iwqp = cm_node->iwqp;
2397146b9756SMustafa Ismail 	if (iwqp) {
2398146b9756SMustafa Ismail 		cm_node->cm_id->rem_ref(cm_node->cm_id);
2399146b9756SMustafa Ismail 		cm_node->cm_id = NULL;
2400146b9756SMustafa Ismail 		iwqp->cm_id = NULL;
2401146b9756SMustafa Ismail 		irdma_qp_rem_ref(&iwqp->ibqp);
2402146b9756SMustafa Ismail 		cm_node->iwqp = NULL;
2403146b9756SMustafa Ismail 	} else if (cm_node->qhash_set) {
2404146b9756SMustafa Ismail 		irdma_get_addr_info(cm_node, &nfo);
2405146b9756SMustafa Ismail 		nfo.qh_qpid = cm_node->iwdev->vsi.ilq->qp_id;
2406146b9756SMustafa Ismail 		irdma_manage_qhash(cm_node->iwdev, &nfo,
2407146b9756SMustafa Ismail 				   IRDMA_QHASH_TYPE_TCP_ESTABLISHED,
2408146b9756SMustafa Ismail 				   IRDMA_QHASH_MANAGE_TYPE_DELETE, NULL, false);
2409146b9756SMustafa Ismail 		cm_node->qhash_set = 0;
2410146b9756SMustafa Ismail 	}
2411146b9756SMustafa Ismail 
2412146b9756SMustafa Ismail 	cm_core->cm_free_ah(cm_node);
2413146b9756SMustafa Ismail }
2414146b9756SMustafa Ismail 
2415146b9756SMustafa Ismail /**
2416146b9756SMustafa Ismail  * irdma_rem_ref_cm_node - destroy an instance of a cm node
2417146b9756SMustafa Ismail  * @cm_node: connection's node
2418146b9756SMustafa Ismail  */
irdma_rem_ref_cm_node(struct irdma_cm_node * cm_node)2419146b9756SMustafa Ismail void irdma_rem_ref_cm_node(struct irdma_cm_node *cm_node)
2420146b9756SMustafa Ismail {
2421146b9756SMustafa Ismail 	struct irdma_cm_core *cm_core = cm_node->cm_core;
2422146b9756SMustafa Ismail 	unsigned long flags;
2423146b9756SMustafa Ismail 
2424146b9756SMustafa Ismail 	trace_irdma_rem_ref_cm_node(cm_node, 0, __builtin_return_address(0));
2425146b9756SMustafa Ismail 	spin_lock_irqsave(&cm_core->ht_lock, flags);
2426146b9756SMustafa Ismail 
2427146b9756SMustafa Ismail 	if (!refcount_dec_and_test(&cm_node->refcnt)) {
2428146b9756SMustafa Ismail 		spin_unlock_irqrestore(&cm_core->ht_lock, flags);
2429146b9756SMustafa Ismail 		return;
2430146b9756SMustafa Ismail 	}
2431146b9756SMustafa Ismail 	if (cm_node->iwqp) {
2432146b9756SMustafa Ismail 		cm_node->iwqp->cm_node = NULL;
2433146b9756SMustafa Ismail 		cm_node->iwqp->cm_id = NULL;
2434146b9756SMustafa Ismail 	}
2435146b9756SMustafa Ismail 	hash_del_rcu(&cm_node->list);
2436146b9756SMustafa Ismail 	cm_node->cm_core->stats_nodes_destroyed++;
2437146b9756SMustafa Ismail 
2438146b9756SMustafa Ismail 	spin_unlock_irqrestore(&cm_core->ht_lock, flags);
2439146b9756SMustafa Ismail 
24402df6d895SShiraz Saleem 	irdma_destroy_connection(cm_node);
24412df6d895SShiraz Saleem 
24422df6d895SShiraz Saleem 	kfree_rcu(cm_node, rcu_head);
2443146b9756SMustafa Ismail }
2444146b9756SMustafa Ismail 
2445146b9756SMustafa Ismail /**
2446146b9756SMustafa Ismail  * irdma_handle_fin_pkt - FIN packet received
2447146b9756SMustafa Ismail  * @cm_node: connection's node
2448146b9756SMustafa Ismail  */
irdma_handle_fin_pkt(struct irdma_cm_node * cm_node)2449146b9756SMustafa Ismail static void irdma_handle_fin_pkt(struct irdma_cm_node *cm_node)
2450146b9756SMustafa Ismail {
2451146b9756SMustafa Ismail 	switch (cm_node->state) {
2452146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_RCVD:
2453146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_SENT:
2454146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ESTABLISHED:
2455146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREJ_RCVD:
2456146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rcv_nxt++;
2457146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2458146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_LAST_ACK;
2459146b9756SMustafa Ismail 		irdma_send_fin(cm_node);
2460146b9756SMustafa Ismail 		break;
2461146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_SENT:
2462146b9756SMustafa Ismail 		irdma_create_event(cm_node, IRDMA_CM_EVENT_ABORTED);
2463146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rcv_nxt++;
2464146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2465146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_CLOSED;
2466146b9756SMustafa Ismail 		refcount_inc(&cm_node->refcnt);
2467146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
2468146b9756SMustafa Ismail 		break;
2469146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT1:
2470146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rcv_nxt++;
2471146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2472146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_CLOSING;
2473146b9756SMustafa Ismail 		irdma_send_ack(cm_node);
2474146b9756SMustafa Ismail 		/*
2475146b9756SMustafa Ismail 		 * Wait for ACK as this is simultaneous close.
2476146b9756SMustafa Ismail 		 * After we receive ACK, do not send anything.
2477146b9756SMustafa Ismail 		 * Just rm the node.
2478146b9756SMustafa Ismail 		 */
2479146b9756SMustafa Ismail 		break;
2480146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT2:
2481146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rcv_nxt++;
2482146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2483146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_TIME_WAIT;
2484146b9756SMustafa Ismail 		irdma_send_ack(cm_node);
2485146b9756SMustafa Ismail 		irdma_schedule_cm_timer(cm_node, NULL, IRDMA_TIMER_TYPE_CLOSE,
2486146b9756SMustafa Ismail 					1, 0);
2487146b9756SMustafa Ismail 		break;
2488146b9756SMustafa Ismail 	case IRDMA_CM_STATE_TIME_WAIT:
2489146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rcv_nxt++;
2490146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2491146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_CLOSED;
2492146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
2493146b9756SMustafa Ismail 		break;
2494146b9756SMustafa Ismail 	case IRDMA_CM_STATE_OFFLOADED:
2495146b9756SMustafa Ismail 	default:
2496146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
2497146b9756SMustafa Ismail 			  "CM: bad state node state = %d\n", cm_node->state);
2498146b9756SMustafa Ismail 		break;
2499146b9756SMustafa Ismail 	}
2500146b9756SMustafa Ismail }
2501146b9756SMustafa Ismail 
2502146b9756SMustafa Ismail /**
2503146b9756SMustafa Ismail  * irdma_handle_rst_pkt - process received RST packet
2504146b9756SMustafa Ismail  * @cm_node: connection's node
2505146b9756SMustafa Ismail  * @rbuf: receive buffer
2506146b9756SMustafa Ismail  */
irdma_handle_rst_pkt(struct irdma_cm_node * cm_node,struct irdma_puda_buf * rbuf)2507146b9756SMustafa Ismail static void irdma_handle_rst_pkt(struct irdma_cm_node *cm_node,
2508146b9756SMustafa Ismail 				 struct irdma_puda_buf *rbuf)
2509146b9756SMustafa Ismail {
2510146b9756SMustafa Ismail 	ibdev_dbg(&cm_node->iwdev->ibdev,
2511146b9756SMustafa Ismail 		  "CM: caller: %pS cm_node=%p state=%d rem_port=0x%04x loc_port=0x%04x rem_addr=%pI4 loc_addr=%pI4\n",
2512146b9756SMustafa Ismail 		  __builtin_return_address(0), cm_node, cm_node->state,
2513146b9756SMustafa Ismail 		  cm_node->rem_port, cm_node->loc_port, cm_node->rem_addr,
2514146b9756SMustafa Ismail 		  cm_node->loc_addr);
2515146b9756SMustafa Ismail 
2516146b9756SMustafa Ismail 	irdma_cleanup_retrans_entry(cm_node);
2517146b9756SMustafa Ismail 	switch (cm_node->state) {
2518146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_SENT:
2519146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_SENT:
2520146b9756SMustafa Ismail 		switch (cm_node->mpa_frame_rev) {
2521146b9756SMustafa Ismail 		case IETF_MPA_V2:
2522146b9756SMustafa Ismail 			/* Drop down to MPA_V1*/
2523146b9756SMustafa Ismail 			cm_node->mpa_frame_rev = IETF_MPA_V1;
2524146b9756SMustafa Ismail 			/* send a syn and goto syn sent state */
2525146b9756SMustafa Ismail 			cm_node->state = IRDMA_CM_STATE_SYN_SENT;
2526146b9756SMustafa Ismail 			if (irdma_send_syn(cm_node, 0))
2527146b9756SMustafa Ismail 				irdma_active_open_err(cm_node, false);
2528146b9756SMustafa Ismail 			break;
2529146b9756SMustafa Ismail 		case IETF_MPA_V1:
2530146b9756SMustafa Ismail 		default:
2531146b9756SMustafa Ismail 			irdma_active_open_err(cm_node, false);
2532146b9756SMustafa Ismail 			break;
2533146b9756SMustafa Ismail 		}
2534146b9756SMustafa Ismail 		break;
2535146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_RCVD:
2536146b9756SMustafa Ismail 		atomic_inc(&cm_node->passive_state);
2537146b9756SMustafa Ismail 		break;
2538146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ESTABLISHED:
2539146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_RCVD:
2540146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LISTENING:
2541146b9756SMustafa Ismail 		irdma_passive_open_err(cm_node, false);
2542146b9756SMustafa Ismail 		break;
2543146b9756SMustafa Ismail 	case IRDMA_CM_STATE_OFFLOADED:
2544146b9756SMustafa Ismail 		irdma_active_open_err(cm_node, false);
2545146b9756SMustafa Ismail 		break;
2546146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSED:
2547146b9756SMustafa Ismail 		break;
2548146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT2:
2549146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT1:
2550146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LAST_ACK:
2551146b9756SMustafa Ismail 	case IRDMA_CM_STATE_TIME_WAIT:
2552146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_CLOSED;
2553146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
2554146b9756SMustafa Ismail 		break;
2555146b9756SMustafa Ismail 	default:
2556146b9756SMustafa Ismail 		break;
2557146b9756SMustafa Ismail 	}
2558146b9756SMustafa Ismail }
2559146b9756SMustafa Ismail 
2560146b9756SMustafa Ismail /**
2561146b9756SMustafa Ismail  * irdma_handle_rcv_mpa - Process a recv'd mpa buffer
2562146b9756SMustafa Ismail  * @cm_node: connection's node
2563146b9756SMustafa Ismail  * @rbuf: receive buffer
2564146b9756SMustafa Ismail  */
irdma_handle_rcv_mpa(struct irdma_cm_node * cm_node,struct irdma_puda_buf * rbuf)2565146b9756SMustafa Ismail static void irdma_handle_rcv_mpa(struct irdma_cm_node *cm_node,
2566146b9756SMustafa Ismail 				 struct irdma_puda_buf *rbuf)
2567146b9756SMustafa Ismail {
2568146b9756SMustafa Ismail 	int err;
2569146b9756SMustafa Ismail 	int datasize = rbuf->datalen;
2570146b9756SMustafa Ismail 	u8 *dataloc = rbuf->data;
2571146b9756SMustafa Ismail 
2572146b9756SMustafa Ismail 	enum irdma_cm_event_type type = IRDMA_CM_EVENT_UNKNOWN;
2573146b9756SMustafa Ismail 	u32 res_type;
2574146b9756SMustafa Ismail 
2575146b9756SMustafa Ismail 	err = irdma_parse_mpa(cm_node, dataloc, &res_type, datasize);
2576146b9756SMustafa Ismail 	if (err) {
2577146b9756SMustafa Ismail 		if (cm_node->state == IRDMA_CM_STATE_MPAREQ_SENT)
2578146b9756SMustafa Ismail 			irdma_active_open_err(cm_node, true);
2579146b9756SMustafa Ismail 		else
2580146b9756SMustafa Ismail 			irdma_passive_open_err(cm_node, true);
2581146b9756SMustafa Ismail 		return;
2582146b9756SMustafa Ismail 	}
2583146b9756SMustafa Ismail 
2584146b9756SMustafa Ismail 	switch (cm_node->state) {
2585146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ESTABLISHED:
2586146b9756SMustafa Ismail 		if (res_type == IRDMA_MPA_REQUEST_REJECT)
2587146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
2588146b9756SMustafa Ismail 				  "CM: state for reject\n");
2589146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_MPAREQ_RCVD;
2590146b9756SMustafa Ismail 		type = IRDMA_CM_EVENT_MPA_REQ;
2591146b9756SMustafa Ismail 		irdma_send_ack(cm_node); /* ACK received MPA request */
2592146b9756SMustafa Ismail 		atomic_set(&cm_node->passive_state,
2593146b9756SMustafa Ismail 			   IRDMA_PASSIVE_STATE_INDICATED);
2594146b9756SMustafa Ismail 		break;
2595146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_SENT:
2596146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2597146b9756SMustafa Ismail 		if (res_type == IRDMA_MPA_REQUEST_REJECT) {
2598146b9756SMustafa Ismail 			type = IRDMA_CM_EVENT_MPA_REJECT;
2599146b9756SMustafa Ismail 			cm_node->state = IRDMA_CM_STATE_MPAREJ_RCVD;
2600146b9756SMustafa Ismail 		} else {
2601146b9756SMustafa Ismail 			type = IRDMA_CM_EVENT_CONNECTED;
2602146b9756SMustafa Ismail 			cm_node->state = IRDMA_CM_STATE_OFFLOADED;
2603146b9756SMustafa Ismail 		}
2604146b9756SMustafa Ismail 		irdma_send_ack(cm_node);
2605146b9756SMustafa Ismail 		break;
2606146b9756SMustafa Ismail 	default:
2607146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
2608146b9756SMustafa Ismail 			  "CM: wrong cm_node state =%d\n", cm_node->state);
2609146b9756SMustafa Ismail 		break;
2610146b9756SMustafa Ismail 	}
2611146b9756SMustafa Ismail 	irdma_create_event(cm_node, type);
2612146b9756SMustafa Ismail }
2613146b9756SMustafa Ismail 
2614146b9756SMustafa Ismail /**
2615146b9756SMustafa Ismail  * irdma_check_syn - Check for error on received syn ack
2616146b9756SMustafa Ismail  * @cm_node: connection's node
2617146b9756SMustafa Ismail  * @tcph: pointer tcp header
2618146b9756SMustafa Ismail  */
irdma_check_syn(struct irdma_cm_node * cm_node,struct tcphdr * tcph)2619146b9756SMustafa Ismail static int irdma_check_syn(struct irdma_cm_node *cm_node, struct tcphdr *tcph)
2620146b9756SMustafa Ismail {
2621146b9756SMustafa Ismail 	if (ntohl(tcph->ack_seq) != cm_node->tcp_cntxt.loc_seq_num) {
2622146b9756SMustafa Ismail 		irdma_active_open_err(cm_node, true);
2623146b9756SMustafa Ismail 		return 1;
2624146b9756SMustafa Ismail 	}
2625146b9756SMustafa Ismail 
2626146b9756SMustafa Ismail 	return 0;
2627146b9756SMustafa Ismail }
2628146b9756SMustafa Ismail 
2629146b9756SMustafa Ismail /**
2630146b9756SMustafa Ismail  * irdma_check_seq - check seq numbers if OK
2631146b9756SMustafa Ismail  * @cm_node: connection's node
2632146b9756SMustafa Ismail  * @tcph: pointer tcp header
2633146b9756SMustafa Ismail  */
irdma_check_seq(struct irdma_cm_node * cm_node,struct tcphdr * tcph)2634146b9756SMustafa Ismail static int irdma_check_seq(struct irdma_cm_node *cm_node, struct tcphdr *tcph)
2635146b9756SMustafa Ismail {
2636146b9756SMustafa Ismail 	u32 seq;
2637146b9756SMustafa Ismail 	u32 ack_seq;
2638146b9756SMustafa Ismail 	u32 loc_seq_num = cm_node->tcp_cntxt.loc_seq_num;
2639146b9756SMustafa Ismail 	u32 rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;
2640146b9756SMustafa Ismail 	u32 rcv_wnd;
2641146b9756SMustafa Ismail 	int err = 0;
2642146b9756SMustafa Ismail 
2643146b9756SMustafa Ismail 	seq = ntohl(tcph->seq);
2644146b9756SMustafa Ismail 	ack_seq = ntohl(tcph->ack_seq);
2645146b9756SMustafa Ismail 	rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;
2646146b9756SMustafa Ismail 	if (ack_seq != loc_seq_num ||
2647146b9756SMustafa Ismail 	    !between(seq, rcv_nxt, (rcv_nxt + rcv_wnd)))
2648146b9756SMustafa Ismail 		err = -1;
2649146b9756SMustafa Ismail 	if (err)
2650146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
2651146b9756SMustafa Ismail 			  "CM: seq number err\n");
2652146b9756SMustafa Ismail 
2653146b9756SMustafa Ismail 	return err;
2654146b9756SMustafa Ismail }
2655146b9756SMustafa Ismail 
irdma_add_conn_est_qh(struct irdma_cm_node * cm_node)2656146b9756SMustafa Ismail void irdma_add_conn_est_qh(struct irdma_cm_node *cm_node)
2657146b9756SMustafa Ismail {
2658146b9756SMustafa Ismail 	struct irdma_cm_info nfo;
2659146b9756SMustafa Ismail 
2660146b9756SMustafa Ismail 	irdma_get_addr_info(cm_node, &nfo);
2661146b9756SMustafa Ismail 	nfo.qh_qpid = cm_node->iwdev->vsi.ilq->qp_id;
2662146b9756SMustafa Ismail 	irdma_manage_qhash(cm_node->iwdev, &nfo,
2663146b9756SMustafa Ismail 			   IRDMA_QHASH_TYPE_TCP_ESTABLISHED,
2664146b9756SMustafa Ismail 			   IRDMA_QHASH_MANAGE_TYPE_ADD,
2665146b9756SMustafa Ismail 			   cm_node, false);
2666146b9756SMustafa Ismail 	cm_node->qhash_set = true;
2667146b9756SMustafa Ismail }
2668146b9756SMustafa Ismail 
2669146b9756SMustafa Ismail /**
2670146b9756SMustafa Ismail  * irdma_handle_syn_pkt - is for Passive node
2671146b9756SMustafa Ismail  * @cm_node: connection's node
2672146b9756SMustafa Ismail  * @rbuf: receive buffer
2673146b9756SMustafa Ismail  */
irdma_handle_syn_pkt(struct irdma_cm_node * cm_node,struct irdma_puda_buf * rbuf)2674146b9756SMustafa Ismail static void irdma_handle_syn_pkt(struct irdma_cm_node *cm_node,
2675146b9756SMustafa Ismail 				 struct irdma_puda_buf *rbuf)
2676146b9756SMustafa Ismail {
2677146b9756SMustafa Ismail 	struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
2678146b9756SMustafa Ismail 	int err;
2679146b9756SMustafa Ismail 	u32 inc_sequence;
2680146b9756SMustafa Ismail 	int optionsize;
2681146b9756SMustafa Ismail 
2682146b9756SMustafa Ismail 	optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
2683146b9756SMustafa Ismail 	inc_sequence = ntohl(tcph->seq);
2684146b9756SMustafa Ismail 
2685146b9756SMustafa Ismail 	switch (cm_node->state) {
2686146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_SENT:
2687146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_SENT:
2688146b9756SMustafa Ismail 		/* Rcvd syn on active open connection */
2689146b9756SMustafa Ismail 		irdma_active_open_err(cm_node, 1);
2690146b9756SMustafa Ismail 		break;
2691146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LISTENING:
2692146b9756SMustafa Ismail 		/* Passive OPEN */
2693146b9756SMustafa Ismail 		if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
2694146b9756SMustafa Ismail 		    cm_node->listener->backlog) {
2695146b9756SMustafa Ismail 			cm_node->cm_core->stats_backlog_drops++;
2696146b9756SMustafa Ismail 			irdma_passive_open_err(cm_node, false);
2697146b9756SMustafa Ismail 			break;
2698146b9756SMustafa Ismail 		}
2699146b9756SMustafa Ismail 		err = irdma_handle_tcp_options(cm_node, tcph, optionsize, 1);
2700146b9756SMustafa Ismail 		if (err) {
2701146b9756SMustafa Ismail 			irdma_passive_open_err(cm_node, false);
2702146b9756SMustafa Ismail 			/* drop pkt */
2703146b9756SMustafa Ismail 			break;
2704146b9756SMustafa Ismail 		}
2705146b9756SMustafa Ismail 		err = cm_node->cm_core->cm_create_ah(cm_node, false);
2706146b9756SMustafa Ismail 		if (err) {
2707146b9756SMustafa Ismail 			irdma_passive_open_err(cm_node, false);
2708146b9756SMustafa Ismail 			/* drop pkt */
2709146b9756SMustafa Ismail 			break;
2710146b9756SMustafa Ismail 		}
2711146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
2712146b9756SMustafa Ismail 		cm_node->accept_pend = 1;
2713146b9756SMustafa Ismail 		atomic_inc(&cm_node->listener->pend_accepts_cnt);
2714146b9756SMustafa Ismail 
2715146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_SYN_RCVD;
2716146b9756SMustafa Ismail 		break;
2717146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSED:
2718146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2719146b9756SMustafa Ismail 		refcount_inc(&cm_node->refcnt);
2720146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
2721146b9756SMustafa Ismail 		break;
2722146b9756SMustafa Ismail 	case IRDMA_CM_STATE_OFFLOADED:
2723146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ESTABLISHED:
2724146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT1:
2725146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT2:
2726146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_RCVD:
2727146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LAST_ACK:
2728146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSING:
2729146b9756SMustafa Ismail 	case IRDMA_CM_STATE_UNKNOWN:
2730146b9756SMustafa Ismail 	default:
2731146b9756SMustafa Ismail 		break;
2732146b9756SMustafa Ismail 	}
2733146b9756SMustafa Ismail }
2734146b9756SMustafa Ismail 
2735146b9756SMustafa Ismail /**
2736146b9756SMustafa Ismail  * irdma_handle_synack_pkt - Process SYN+ACK packet (active side)
2737146b9756SMustafa Ismail  * @cm_node: connection's node
2738146b9756SMustafa Ismail  * @rbuf: receive buffer
2739146b9756SMustafa Ismail  */
irdma_handle_synack_pkt(struct irdma_cm_node * cm_node,struct irdma_puda_buf * rbuf)2740146b9756SMustafa Ismail static void irdma_handle_synack_pkt(struct irdma_cm_node *cm_node,
2741146b9756SMustafa Ismail 				    struct irdma_puda_buf *rbuf)
2742146b9756SMustafa Ismail {
2743146b9756SMustafa Ismail 	struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
2744146b9756SMustafa Ismail 	int err;
2745146b9756SMustafa Ismail 	u32 inc_sequence;
2746146b9756SMustafa Ismail 	int optionsize;
2747146b9756SMustafa Ismail 
2748146b9756SMustafa Ismail 	optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
2749146b9756SMustafa Ismail 	inc_sequence = ntohl(tcph->seq);
2750146b9756SMustafa Ismail 	switch (cm_node->state) {
2751146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_SENT:
2752146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2753146b9756SMustafa Ismail 		/* active open */
2754146b9756SMustafa Ismail 		if (irdma_check_syn(cm_node, tcph)) {
2755146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
2756146b9756SMustafa Ismail 				  "CM: check syn fail\n");
2757146b9756SMustafa Ismail 			return;
2758146b9756SMustafa Ismail 		}
2759146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
2760146b9756SMustafa Ismail 		/* setup options */
2761146b9756SMustafa Ismail 		err = irdma_handle_tcp_options(cm_node, tcph, optionsize, 0);
2762146b9756SMustafa Ismail 		if (err) {
2763146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
2764146b9756SMustafa Ismail 				  "CM: cm_node=%p tcp_options failed\n",
2765146b9756SMustafa Ismail 				  cm_node);
2766146b9756SMustafa Ismail 			break;
2767146b9756SMustafa Ismail 		}
2768146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2769146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
2770146b9756SMustafa Ismail 		irdma_send_ack(cm_node); /* ACK  for the syn_ack */
2771146b9756SMustafa Ismail 		err = irdma_send_mpa_request(cm_node);
2772146b9756SMustafa Ismail 		if (err) {
2773146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
2774146b9756SMustafa Ismail 				  "CM: cm_node=%p irdma_send_mpa_request failed\n",
2775146b9756SMustafa Ismail 				  cm_node);
2776146b9756SMustafa Ismail 			break;
2777146b9756SMustafa Ismail 		}
2778146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_MPAREQ_SENT;
2779146b9756SMustafa Ismail 		break;
2780146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_RCVD:
2781146b9756SMustafa Ismail 		irdma_passive_open_err(cm_node, true);
2782146b9756SMustafa Ismail 		break;
2783146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LISTENING:
2784146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
2785146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2786146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_CLOSED;
2787146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
2788146b9756SMustafa Ismail 		break;
2789146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSED:
2790146b9756SMustafa Ismail 		cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
2791146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2792146b9756SMustafa Ismail 		refcount_inc(&cm_node->refcnt);
2793146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
2794146b9756SMustafa Ismail 		break;
2795146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ESTABLISHED:
2796146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT1:
2797146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT2:
2798146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LAST_ACK:
2799146b9756SMustafa Ismail 	case IRDMA_CM_STATE_OFFLOADED:
2800146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSING:
2801146b9756SMustafa Ismail 	case IRDMA_CM_STATE_UNKNOWN:
2802146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_SENT:
2803146b9756SMustafa Ismail 	default:
2804146b9756SMustafa Ismail 		break;
2805146b9756SMustafa Ismail 	}
2806146b9756SMustafa Ismail }
2807146b9756SMustafa Ismail 
2808146b9756SMustafa Ismail /**
2809146b9756SMustafa Ismail  * irdma_handle_ack_pkt - process packet with ACK
2810146b9756SMustafa Ismail  * @cm_node: connection's node
2811146b9756SMustafa Ismail  * @rbuf: receive buffer
2812146b9756SMustafa Ismail  */
irdma_handle_ack_pkt(struct irdma_cm_node * cm_node,struct irdma_puda_buf * rbuf)2813146b9756SMustafa Ismail static int irdma_handle_ack_pkt(struct irdma_cm_node *cm_node,
2814146b9756SMustafa Ismail 				struct irdma_puda_buf *rbuf)
2815146b9756SMustafa Ismail {
2816146b9756SMustafa Ismail 	struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
2817146b9756SMustafa Ismail 	u32 inc_sequence;
2818146b9756SMustafa Ismail 	int ret;
2819146b9756SMustafa Ismail 	int optionsize;
2820146b9756SMustafa Ismail 	u32 datasize = rbuf->datalen;
2821146b9756SMustafa Ismail 
2822146b9756SMustafa Ismail 	optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
2823146b9756SMustafa Ismail 
2824146b9756SMustafa Ismail 	if (irdma_check_seq(cm_node, tcph))
2825146b9756SMustafa Ismail 		return -EINVAL;
2826146b9756SMustafa Ismail 
2827146b9756SMustafa Ismail 	inc_sequence = ntohl(tcph->seq);
2828146b9756SMustafa Ismail 	switch (cm_node->state) {
2829146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_RCVD:
2830146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2831146b9756SMustafa Ismail 		ret = irdma_handle_tcp_options(cm_node, tcph, optionsize, 1);
2832146b9756SMustafa Ismail 		if (ret)
2833146b9756SMustafa Ismail 			return ret;
2834146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
2835146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_ESTABLISHED;
2836146b9756SMustafa Ismail 		if (datasize) {
2837146b9756SMustafa Ismail 			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
2838146b9756SMustafa Ismail 			irdma_handle_rcv_mpa(cm_node, rbuf);
2839146b9756SMustafa Ismail 		}
2840146b9756SMustafa Ismail 		break;
2841146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ESTABLISHED:
2842146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2843146b9756SMustafa Ismail 		if (datasize) {
2844146b9756SMustafa Ismail 			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
2845146b9756SMustafa Ismail 			irdma_handle_rcv_mpa(cm_node, rbuf);
2846146b9756SMustafa Ismail 		}
2847146b9756SMustafa Ismail 		break;
2848146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_SENT:
2849146b9756SMustafa Ismail 		cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
2850146b9756SMustafa Ismail 		if (datasize) {
2851146b9756SMustafa Ismail 			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
2852146b9756SMustafa Ismail 			cm_node->ack_rcvd = false;
2853146b9756SMustafa Ismail 			irdma_handle_rcv_mpa(cm_node, rbuf);
2854146b9756SMustafa Ismail 		} else {
2855146b9756SMustafa Ismail 			cm_node->ack_rcvd = true;
2856146b9756SMustafa Ismail 		}
2857146b9756SMustafa Ismail 		break;
2858146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LISTENING:
2859146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2860146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_CLOSED;
2861146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
2862146b9756SMustafa Ismail 		break;
2863146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSED:
2864146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2865146b9756SMustafa Ismail 		refcount_inc(&cm_node->refcnt);
2866146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
2867146b9756SMustafa Ismail 		break;
2868146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LAST_ACK:
2869146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSING:
2870146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2871146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_CLOSED;
2872146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
2873146b9756SMustafa Ismail 		break;
2874146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT1:
2875146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2876146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_FIN_WAIT2;
2877146b9756SMustafa Ismail 		break;
2878146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_SENT:
2879146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT2:
2880146b9756SMustafa Ismail 	case IRDMA_CM_STATE_OFFLOADED:
2881146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_RCVD:
2882146b9756SMustafa Ismail 	case IRDMA_CM_STATE_UNKNOWN:
2883146b9756SMustafa Ismail 	default:
2884146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
2885146b9756SMustafa Ismail 		break;
2886146b9756SMustafa Ismail 	}
2887146b9756SMustafa Ismail 
2888146b9756SMustafa Ismail 	return 0;
2889146b9756SMustafa Ismail }
2890146b9756SMustafa Ismail 
2891146b9756SMustafa Ismail /**
2892146b9756SMustafa Ismail  * irdma_process_pkt - process cm packet
2893146b9756SMustafa Ismail  * @cm_node: connection's node
2894146b9756SMustafa Ismail  * @rbuf: receive buffer
2895146b9756SMustafa Ismail  */
irdma_process_pkt(struct irdma_cm_node * cm_node,struct irdma_puda_buf * rbuf)2896146b9756SMustafa Ismail static void irdma_process_pkt(struct irdma_cm_node *cm_node,
2897146b9756SMustafa Ismail 			      struct irdma_puda_buf *rbuf)
2898146b9756SMustafa Ismail {
2899146b9756SMustafa Ismail 	enum irdma_tcpip_pkt_type pkt_type = IRDMA_PKT_TYPE_UNKNOWN;
2900146b9756SMustafa Ismail 	struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
2901146b9756SMustafa Ismail 	u32 fin_set = 0;
2902146b9756SMustafa Ismail 	int err;
2903146b9756SMustafa Ismail 
2904146b9756SMustafa Ismail 	if (tcph->rst) {
2905146b9756SMustafa Ismail 		pkt_type = IRDMA_PKT_TYPE_RST;
2906146b9756SMustafa Ismail 	} else if (tcph->syn) {
2907146b9756SMustafa Ismail 		pkt_type = IRDMA_PKT_TYPE_SYN;
2908146b9756SMustafa Ismail 		if (tcph->ack)
2909146b9756SMustafa Ismail 			pkt_type = IRDMA_PKT_TYPE_SYNACK;
2910146b9756SMustafa Ismail 	} else if (tcph->ack) {
2911146b9756SMustafa Ismail 		pkt_type = IRDMA_PKT_TYPE_ACK;
2912146b9756SMustafa Ismail 	}
2913146b9756SMustafa Ismail 	if (tcph->fin)
2914146b9756SMustafa Ismail 		fin_set = 1;
2915146b9756SMustafa Ismail 
2916146b9756SMustafa Ismail 	switch (pkt_type) {
2917146b9756SMustafa Ismail 	case IRDMA_PKT_TYPE_SYN:
2918146b9756SMustafa Ismail 		irdma_handle_syn_pkt(cm_node, rbuf);
2919146b9756SMustafa Ismail 		break;
2920146b9756SMustafa Ismail 	case IRDMA_PKT_TYPE_SYNACK:
2921146b9756SMustafa Ismail 		irdma_handle_synack_pkt(cm_node, rbuf);
2922146b9756SMustafa Ismail 		break;
2923146b9756SMustafa Ismail 	case IRDMA_PKT_TYPE_ACK:
2924146b9756SMustafa Ismail 		err = irdma_handle_ack_pkt(cm_node, rbuf);
2925146b9756SMustafa Ismail 		if (fin_set && !err)
2926146b9756SMustafa Ismail 			irdma_handle_fin_pkt(cm_node);
2927146b9756SMustafa Ismail 		break;
2928146b9756SMustafa Ismail 	case IRDMA_PKT_TYPE_RST:
2929146b9756SMustafa Ismail 		irdma_handle_rst_pkt(cm_node, rbuf);
2930146b9756SMustafa Ismail 		break;
2931146b9756SMustafa Ismail 	default:
2932146b9756SMustafa Ismail 		if (fin_set &&
2933146b9756SMustafa Ismail 		    (!irdma_check_seq(cm_node, (struct tcphdr *)rbuf->tcph)))
2934146b9756SMustafa Ismail 			irdma_handle_fin_pkt(cm_node);
2935146b9756SMustafa Ismail 		break;
2936146b9756SMustafa Ismail 	}
2937146b9756SMustafa Ismail }
2938146b9756SMustafa Ismail 
2939146b9756SMustafa Ismail /**
2940146b9756SMustafa Ismail  * irdma_make_listen_node - create a listen node with params
2941146b9756SMustafa Ismail  * @cm_core: cm's core
2942146b9756SMustafa Ismail  * @iwdev: iwarp device structure
2943146b9756SMustafa Ismail  * @cm_info: quad info for connection
2944146b9756SMustafa Ismail  */
2945146b9756SMustafa Ismail static struct irdma_cm_listener *
irdma_make_listen_node(struct irdma_cm_core * cm_core,struct irdma_device * iwdev,struct irdma_cm_info * cm_info)2946146b9756SMustafa Ismail irdma_make_listen_node(struct irdma_cm_core *cm_core,
2947146b9756SMustafa Ismail 		       struct irdma_device *iwdev,
2948146b9756SMustafa Ismail 		       struct irdma_cm_info *cm_info)
2949146b9756SMustafa Ismail {
2950146b9756SMustafa Ismail 	struct irdma_cm_listener *listener;
2951146b9756SMustafa Ismail 	unsigned long flags;
2952146b9756SMustafa Ismail 
2953146b9756SMustafa Ismail 	/* cannot have multiple matching listeners */
2954e4522c09STatyana Nikolova 	listener =
2955e4522c09STatyana Nikolova 		irdma_find_listener(cm_core, cm_info->loc_addr, cm_info->ipv4,
2956146b9756SMustafa Ismail 				    cm_info->loc_port, cm_info->vlan_id,
2957146b9756SMustafa Ismail 				    IRDMA_CM_LISTENER_EITHER_STATE);
2958146b9756SMustafa Ismail 	if (listener &&
2959146b9756SMustafa Ismail 	    listener->listener_state == IRDMA_CM_LISTENER_ACTIVE_STATE) {
2960146b9756SMustafa Ismail 		refcount_dec(&listener->refcnt);
2961146b9756SMustafa Ismail 		return NULL;
2962146b9756SMustafa Ismail 	}
2963146b9756SMustafa Ismail 
2964146b9756SMustafa Ismail 	if (!listener) {
2965146b9756SMustafa Ismail 		/* create a CM listen node
2966146b9756SMustafa Ismail 		 * 1/2 node to compare incoming traffic to
2967146b9756SMustafa Ismail 		 */
2968146b9756SMustafa Ismail 		listener = kzalloc(sizeof(*listener), GFP_KERNEL);
2969146b9756SMustafa Ismail 		if (!listener)
2970146b9756SMustafa Ismail 			return NULL;
2971146b9756SMustafa Ismail 		cm_core->stats_listen_nodes_created++;
2972146b9756SMustafa Ismail 		memcpy(listener->loc_addr, cm_info->loc_addr,
2973146b9756SMustafa Ismail 		       sizeof(listener->loc_addr));
2974146b9756SMustafa Ismail 		listener->loc_port = cm_info->loc_port;
2975146b9756SMustafa Ismail 
2976146b9756SMustafa Ismail 		INIT_LIST_HEAD(&listener->child_listen_list);
2977146b9756SMustafa Ismail 
2978146b9756SMustafa Ismail 		refcount_set(&listener->refcnt, 1);
2979146b9756SMustafa Ismail 	} else {
2980146b9756SMustafa Ismail 		listener->reused_node = 1;
2981146b9756SMustafa Ismail 	}
2982146b9756SMustafa Ismail 
2983146b9756SMustafa Ismail 	listener->cm_id = cm_info->cm_id;
2984146b9756SMustafa Ismail 	listener->ipv4 = cm_info->ipv4;
2985146b9756SMustafa Ismail 	listener->vlan_id = cm_info->vlan_id;
2986146b9756SMustafa Ismail 	atomic_set(&listener->pend_accepts_cnt, 0);
2987146b9756SMustafa Ismail 	listener->cm_core = cm_core;
2988146b9756SMustafa Ismail 	listener->iwdev = iwdev;
2989146b9756SMustafa Ismail 
2990146b9756SMustafa Ismail 	listener->backlog = cm_info->backlog;
2991146b9756SMustafa Ismail 	listener->listener_state = IRDMA_CM_LISTENER_ACTIVE_STATE;
2992146b9756SMustafa Ismail 
2993146b9756SMustafa Ismail 	if (!listener->reused_node) {
2994146b9756SMustafa Ismail 		spin_lock_irqsave(&cm_core->listen_list_lock, flags);
2995146b9756SMustafa Ismail 		list_add(&listener->list, &cm_core->listen_list);
2996146b9756SMustafa Ismail 		spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
2997146b9756SMustafa Ismail 	}
2998146b9756SMustafa Ismail 
2999146b9756SMustafa Ismail 	return listener;
3000146b9756SMustafa Ismail }
3001146b9756SMustafa Ismail 
3002146b9756SMustafa Ismail /**
3003146b9756SMustafa Ismail  * irdma_create_cm_node - make a connection node with params
3004146b9756SMustafa Ismail  * @cm_core: cm's core
3005146b9756SMustafa Ismail  * @iwdev: iwarp device structure
3006146b9756SMustafa Ismail  * @conn_param: connection parameters
3007146b9756SMustafa Ismail  * @cm_info: quad info for connection
3008146b9756SMustafa Ismail  * @caller_cm_node: pointer to cm_node structure to return
3009146b9756SMustafa Ismail  */
irdma_create_cm_node(struct irdma_cm_core * cm_core,struct irdma_device * iwdev,struct iw_cm_conn_param * conn_param,struct irdma_cm_info * cm_info,struct irdma_cm_node ** caller_cm_node)3010146b9756SMustafa Ismail static int irdma_create_cm_node(struct irdma_cm_core *cm_core,
3011146b9756SMustafa Ismail 				struct irdma_device *iwdev,
3012146b9756SMustafa Ismail 				struct iw_cm_conn_param *conn_param,
3013146b9756SMustafa Ismail 				struct irdma_cm_info *cm_info,
3014146b9756SMustafa Ismail 				struct irdma_cm_node **caller_cm_node)
3015146b9756SMustafa Ismail {
3016146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
3017146b9756SMustafa Ismail 	u16 private_data_len = conn_param->private_data_len;
3018146b9756SMustafa Ismail 	const void *private_data = conn_param->private_data;
3019146b9756SMustafa Ismail 
3020146b9756SMustafa Ismail 	/* create a CM connection node */
3021146b9756SMustafa Ismail 	cm_node = irdma_make_cm_node(cm_core, iwdev, cm_info, NULL);
3022146b9756SMustafa Ismail 	if (!cm_node)
3023146b9756SMustafa Ismail 		return -ENOMEM;
3024146b9756SMustafa Ismail 
3025146b9756SMustafa Ismail 	/* set our node side to client (active) side */
3026146b9756SMustafa Ismail 	cm_node->tcp_cntxt.client = 1;
3027146b9756SMustafa Ismail 	cm_node->tcp_cntxt.rcv_wscale = IRDMA_CM_DEFAULT_RCV_WND_SCALE;
3028146b9756SMustafa Ismail 
3029146b9756SMustafa Ismail 	irdma_record_ird_ord(cm_node, conn_param->ird, conn_param->ord);
3030146b9756SMustafa Ismail 
3031146b9756SMustafa Ismail 	cm_node->pdata.size = private_data_len;
3032146b9756SMustafa Ismail 	cm_node->pdata.addr = cm_node->pdata_buf;
3033146b9756SMustafa Ismail 
3034146b9756SMustafa Ismail 	memcpy(cm_node->pdata_buf, private_data, private_data_len);
3035146b9756SMustafa Ismail 	*caller_cm_node = cm_node;
3036146b9756SMustafa Ismail 
3037146b9756SMustafa Ismail 	return 0;
3038146b9756SMustafa Ismail }
3039146b9756SMustafa Ismail 
3040146b9756SMustafa Ismail /**
3041146b9756SMustafa Ismail  * irdma_cm_reject - reject and teardown a connection
3042146b9756SMustafa Ismail  * @cm_node: connection's node
3043146b9756SMustafa Ismail  * @pdata: ptr to private data for reject
3044146b9756SMustafa Ismail  * @plen: size of private data
3045146b9756SMustafa Ismail  */
irdma_cm_reject(struct irdma_cm_node * cm_node,const void * pdata,u8 plen)3046146b9756SMustafa Ismail static int irdma_cm_reject(struct irdma_cm_node *cm_node, const void *pdata,
3047146b9756SMustafa Ismail 			   u8 plen)
3048146b9756SMustafa Ismail {
3049146b9756SMustafa Ismail 	int ret;
3050146b9756SMustafa Ismail 	int passive_state;
3051146b9756SMustafa Ismail 
3052146b9756SMustafa Ismail 	if (cm_node->tcp_cntxt.client)
3053146b9756SMustafa Ismail 		return 0;
3054146b9756SMustafa Ismail 
3055146b9756SMustafa Ismail 	irdma_cleanup_retrans_entry(cm_node);
3056146b9756SMustafa Ismail 
3057146b9756SMustafa Ismail 	passive_state = atomic_add_return(1, &cm_node->passive_state);
3058146b9756SMustafa Ismail 	if (passive_state == IRDMA_SEND_RESET_EVENT) {
3059146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_CLOSED;
3060146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
3061146b9756SMustafa Ismail 		return 0;
3062146b9756SMustafa Ismail 	}
3063146b9756SMustafa Ismail 
3064146b9756SMustafa Ismail 	if (cm_node->state == IRDMA_CM_STATE_LISTENER_DESTROYED) {
3065146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
3066146b9756SMustafa Ismail 		return 0;
3067146b9756SMustafa Ismail 	}
3068146b9756SMustafa Ismail 
3069146b9756SMustafa Ismail 	ret = irdma_send_mpa_reject(cm_node, pdata, plen);
3070146b9756SMustafa Ismail 	if (!ret)
3071146b9756SMustafa Ismail 		return 0;
3072146b9756SMustafa Ismail 
3073146b9756SMustafa Ismail 	cm_node->state = IRDMA_CM_STATE_CLOSED;
3074146b9756SMustafa Ismail 	if (irdma_send_reset(cm_node))
3075146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
3076146b9756SMustafa Ismail 			  "CM: send reset failed\n");
3077146b9756SMustafa Ismail 
3078146b9756SMustafa Ismail 	return ret;
3079146b9756SMustafa Ismail }
3080146b9756SMustafa Ismail 
3081146b9756SMustafa Ismail /**
3082146b9756SMustafa Ismail  * irdma_cm_close - close of cm connection
3083146b9756SMustafa Ismail  * @cm_node: connection's node
3084146b9756SMustafa Ismail  */
irdma_cm_close(struct irdma_cm_node * cm_node)3085146b9756SMustafa Ismail static int irdma_cm_close(struct irdma_cm_node *cm_node)
3086146b9756SMustafa Ismail {
3087146b9756SMustafa Ismail 	switch (cm_node->state) {
3088146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_RCVD:
3089146b9756SMustafa Ismail 	case IRDMA_CM_STATE_SYN_SENT:
3090146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ONE_SIDE_ESTABLISHED:
3091146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ESTABLISHED:
3092146b9756SMustafa Ismail 	case IRDMA_CM_STATE_ACCEPTING:
3093146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_SENT:
3094146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREQ_RCVD:
3095146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
3096146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
3097146b9756SMustafa Ismail 		break;
3098146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSE_WAIT:
3099146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_LAST_ACK;
3100146b9756SMustafa Ismail 		irdma_send_fin(cm_node);
3101146b9756SMustafa Ismail 		break;
3102146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT1:
3103146b9756SMustafa Ismail 	case IRDMA_CM_STATE_FIN_WAIT2:
3104146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LAST_ACK:
3105146b9756SMustafa Ismail 	case IRDMA_CM_STATE_TIME_WAIT:
3106146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSING:
3107146b9756SMustafa Ismail 		return -EINVAL;
3108146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LISTENING:
3109146b9756SMustafa Ismail 		irdma_cleanup_retrans_entry(cm_node);
3110146b9756SMustafa Ismail 		irdma_send_reset(cm_node);
3111146b9756SMustafa Ismail 		break;
3112146b9756SMustafa Ismail 	case IRDMA_CM_STATE_MPAREJ_RCVD:
3113146b9756SMustafa Ismail 	case IRDMA_CM_STATE_UNKNOWN:
3114146b9756SMustafa Ismail 	case IRDMA_CM_STATE_INITED:
3115146b9756SMustafa Ismail 	case IRDMA_CM_STATE_CLOSED:
3116146b9756SMustafa Ismail 	case IRDMA_CM_STATE_LISTENER_DESTROYED:
3117146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
3118146b9756SMustafa Ismail 		break;
3119146b9756SMustafa Ismail 	case IRDMA_CM_STATE_OFFLOADED:
3120146b9756SMustafa Ismail 		if (cm_node->send_entry)
3121146b9756SMustafa Ismail 			ibdev_dbg(&cm_node->iwdev->ibdev,
3122146b9756SMustafa Ismail 				  "CM: CM send_entry in OFFLOADED state\n");
3123146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
3124146b9756SMustafa Ismail 		break;
3125146b9756SMustafa Ismail 	}
3126146b9756SMustafa Ismail 
3127146b9756SMustafa Ismail 	return 0;
3128146b9756SMustafa Ismail }
3129146b9756SMustafa Ismail 
3130146b9756SMustafa Ismail /**
3131146b9756SMustafa Ismail  * irdma_receive_ilq - recv an ETHERNET packet, and process it
3132146b9756SMustafa Ismail  * through CM
3133146b9756SMustafa Ismail  * @vsi: VSI structure of dev
3134146b9756SMustafa Ismail  * @rbuf: receive buffer
3135146b9756SMustafa Ismail  */
irdma_receive_ilq(struct irdma_sc_vsi * vsi,struct irdma_puda_buf * rbuf)3136146b9756SMustafa Ismail void irdma_receive_ilq(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *rbuf)
3137146b9756SMustafa Ismail {
3138146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
3139146b9756SMustafa Ismail 	struct irdma_cm_listener *listener;
3140146b9756SMustafa Ismail 	struct iphdr *iph;
3141146b9756SMustafa Ismail 	struct ipv6hdr *ip6h;
3142146b9756SMustafa Ismail 	struct tcphdr *tcph;
3143146b9756SMustafa Ismail 	struct irdma_cm_info cm_info = {};
3144146b9756SMustafa Ismail 	struct irdma_device *iwdev = vsi->back_vsi;
3145146b9756SMustafa Ismail 	struct irdma_cm_core *cm_core = &iwdev->cm_core;
3146146b9756SMustafa Ismail 	struct vlan_ethhdr *ethh;
3147146b9756SMustafa Ismail 	u16 vtag;
3148146b9756SMustafa Ismail 
3149146b9756SMustafa Ismail 	/* if vlan, then maclen = 18 else 14 */
3150146b9756SMustafa Ismail 	iph = (struct iphdr *)rbuf->iph;
3151146b9756SMustafa Ismail 	print_hex_dump_debug("ILQ: RECEIVE ILQ BUFFER", DUMP_PREFIX_OFFSET,
3152146b9756SMustafa Ismail 			     16, 8, rbuf->mem.va, rbuf->totallen, false);
3153146b9756SMustafa Ismail 	if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
3154146b9756SMustafa Ismail 		if (rbuf->vlan_valid) {
3155146b9756SMustafa Ismail 			vtag = rbuf->vlan_id;
3156146b9756SMustafa Ismail 			cm_info.user_pri = (vtag & VLAN_PRIO_MASK) >>
3157146b9756SMustafa Ismail 					   VLAN_PRIO_SHIFT;
3158146b9756SMustafa Ismail 			cm_info.vlan_id = vtag & VLAN_VID_MASK;
3159146b9756SMustafa Ismail 		} else {
3160146b9756SMustafa Ismail 			cm_info.vlan_id = 0xFFFF;
3161146b9756SMustafa Ismail 		}
3162146b9756SMustafa Ismail 	} else {
3163146b9756SMustafa Ismail 		ethh = rbuf->mem.va;
3164146b9756SMustafa Ismail 
3165146b9756SMustafa Ismail 		if (ethh->h_vlan_proto == htons(ETH_P_8021Q)) {
3166146b9756SMustafa Ismail 			vtag = ntohs(ethh->h_vlan_TCI);
3167146b9756SMustafa Ismail 			cm_info.user_pri = (vtag & VLAN_PRIO_MASK) >>
3168146b9756SMustafa Ismail 					   VLAN_PRIO_SHIFT;
3169146b9756SMustafa Ismail 			cm_info.vlan_id = vtag & VLAN_VID_MASK;
3170146b9756SMustafa Ismail 			ibdev_dbg(&cm_core->iwdev->ibdev,
3171146b9756SMustafa Ismail 				  "CM: vlan_id=%d\n", cm_info.vlan_id);
3172146b9756SMustafa Ismail 		} else {
3173146b9756SMustafa Ismail 			cm_info.vlan_id = 0xFFFF;
3174146b9756SMustafa Ismail 		}
3175146b9756SMustafa Ismail 	}
3176146b9756SMustafa Ismail 	tcph = (struct tcphdr *)rbuf->tcph;
3177146b9756SMustafa Ismail 
3178146b9756SMustafa Ismail 	if (rbuf->ipv4) {
3179146b9756SMustafa Ismail 		cm_info.loc_addr[0] = ntohl(iph->daddr);
3180146b9756SMustafa Ismail 		cm_info.rem_addr[0] = ntohl(iph->saddr);
3181146b9756SMustafa Ismail 		cm_info.ipv4 = true;
3182146b9756SMustafa Ismail 		cm_info.tos = iph->tos;
3183146b9756SMustafa Ismail 	} else {
3184146b9756SMustafa Ismail 		ip6h = (struct ipv6hdr *)rbuf->iph;
3185146b9756SMustafa Ismail 		irdma_copy_ip_ntohl(cm_info.loc_addr,
3186146b9756SMustafa Ismail 				    ip6h->daddr.in6_u.u6_addr32);
3187146b9756SMustafa Ismail 		irdma_copy_ip_ntohl(cm_info.rem_addr,
3188146b9756SMustafa Ismail 				    ip6h->saddr.in6_u.u6_addr32);
3189146b9756SMustafa Ismail 		cm_info.ipv4 = false;
3190146b9756SMustafa Ismail 		cm_info.tos = (ip6h->priority << 4) | (ip6h->flow_lbl[0] >> 4);
3191146b9756SMustafa Ismail 	}
3192146b9756SMustafa Ismail 	cm_info.loc_port = ntohs(tcph->dest);
3193146b9756SMustafa Ismail 	cm_info.rem_port = ntohs(tcph->source);
3194146b9756SMustafa Ismail 	cm_node = irdma_find_node(cm_core, cm_info.rem_port, cm_info.rem_addr,
3195146b9756SMustafa Ismail 				  cm_info.loc_port, cm_info.loc_addr, cm_info.vlan_id);
3196146b9756SMustafa Ismail 
3197146b9756SMustafa Ismail 	if (!cm_node) {
3198146b9756SMustafa Ismail 		/* Only type of packet accepted are for the
3199146b9756SMustafa Ismail 		 * PASSIVE open (syn only)
3200146b9756SMustafa Ismail 		 */
3201146b9756SMustafa Ismail 		if (!tcph->syn || tcph->ack)
3202146b9756SMustafa Ismail 			return;
3203146b9756SMustafa Ismail 
3204146b9756SMustafa Ismail 		listener = irdma_find_listener(cm_core,
3205146b9756SMustafa Ismail 					       cm_info.loc_addr,
3206e4522c09STatyana Nikolova 					       cm_info.ipv4,
3207146b9756SMustafa Ismail 					       cm_info.loc_port,
3208146b9756SMustafa Ismail 					       cm_info.vlan_id,
3209146b9756SMustafa Ismail 					       IRDMA_CM_LISTENER_ACTIVE_STATE);
3210146b9756SMustafa Ismail 		if (!listener) {
3211146b9756SMustafa Ismail 			cm_info.cm_id = NULL;
3212146b9756SMustafa Ismail 			ibdev_dbg(&cm_core->iwdev->ibdev,
3213146b9756SMustafa Ismail 				  "CM: no listener found\n");
3214146b9756SMustafa Ismail 			return;
3215146b9756SMustafa Ismail 		}
3216146b9756SMustafa Ismail 
3217146b9756SMustafa Ismail 		cm_info.cm_id = listener->cm_id;
3218146b9756SMustafa Ismail 		cm_node = irdma_make_cm_node(cm_core, iwdev, &cm_info,
3219146b9756SMustafa Ismail 					     listener);
3220146b9756SMustafa Ismail 		if (!cm_node) {
3221146b9756SMustafa Ismail 			ibdev_dbg(&cm_core->iwdev->ibdev,
3222146b9756SMustafa Ismail 				  "CM: allocate node failed\n");
3223146b9756SMustafa Ismail 			refcount_dec(&listener->refcnt);
3224146b9756SMustafa Ismail 			return;
3225146b9756SMustafa Ismail 		}
3226146b9756SMustafa Ismail 
3227146b9756SMustafa Ismail 		if (!tcph->rst && !tcph->fin) {
3228146b9756SMustafa Ismail 			cm_node->state = IRDMA_CM_STATE_LISTENING;
3229146b9756SMustafa Ismail 		} else {
3230146b9756SMustafa Ismail 			irdma_rem_ref_cm_node(cm_node);
3231146b9756SMustafa Ismail 			return;
3232146b9756SMustafa Ismail 		}
3233146b9756SMustafa Ismail 
3234146b9756SMustafa Ismail 		refcount_inc(&cm_node->refcnt);
3235146b9756SMustafa Ismail 	} else if (cm_node->state == IRDMA_CM_STATE_OFFLOADED) {
3236146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
3237146b9756SMustafa Ismail 		return;
3238146b9756SMustafa Ismail 	}
3239146b9756SMustafa Ismail 
3240146b9756SMustafa Ismail 	irdma_process_pkt(cm_node, rbuf);
3241146b9756SMustafa Ismail 	irdma_rem_ref_cm_node(cm_node);
3242146b9756SMustafa Ismail }
3243146b9756SMustafa Ismail 
irdma_add_qh(struct irdma_cm_node * cm_node,bool active)3244146b9756SMustafa Ismail static int irdma_add_qh(struct irdma_cm_node *cm_node, bool active)
3245146b9756SMustafa Ismail {
3246146b9756SMustafa Ismail 	if (!active)
3247146b9756SMustafa Ismail 		irdma_add_conn_est_qh(cm_node);
3248146b9756SMustafa Ismail 	return 0;
3249146b9756SMustafa Ismail }
3250146b9756SMustafa Ismail 
irdma_cm_free_ah_nop(struct irdma_cm_node * cm_node)3251146b9756SMustafa Ismail static void irdma_cm_free_ah_nop(struct irdma_cm_node *cm_node)
3252146b9756SMustafa Ismail {
3253146b9756SMustafa Ismail }
3254146b9756SMustafa Ismail 
3255146b9756SMustafa Ismail /**
3256146b9756SMustafa Ismail  * irdma_setup_cm_core - setup top level instance of a cm core
3257146b9756SMustafa Ismail  * @iwdev: iwarp device structure
3258146b9756SMustafa Ismail  * @rdma_ver: HW version
3259146b9756SMustafa Ismail  */
irdma_setup_cm_core(struct irdma_device * iwdev,u8 rdma_ver)32602c4b14eaSShiraz Saleem int irdma_setup_cm_core(struct irdma_device *iwdev, u8 rdma_ver)
3261146b9756SMustafa Ismail {
3262146b9756SMustafa Ismail 	struct irdma_cm_core *cm_core = &iwdev->cm_core;
3263146b9756SMustafa Ismail 
3264146b9756SMustafa Ismail 	cm_core->iwdev = iwdev;
3265146b9756SMustafa Ismail 	cm_core->dev = &iwdev->rf->sc_dev;
3266146b9756SMustafa Ismail 
3267146b9756SMustafa Ismail 	/* Handles CM event work items send to Iwarp core */
3268146b9756SMustafa Ismail 	cm_core->event_wq = alloc_ordered_workqueue("iwarp-event-wq", 0);
3269146b9756SMustafa Ismail 	if (!cm_core->event_wq)
32702c4b14eaSShiraz Saleem 		return -ENOMEM;
3271146b9756SMustafa Ismail 
3272146b9756SMustafa Ismail 	INIT_LIST_HEAD(&cm_core->listen_list);
3273146b9756SMustafa Ismail 
3274146b9756SMustafa Ismail 	timer_setup(&cm_core->tcp_timer, irdma_cm_timer_tick, 0);
3275146b9756SMustafa Ismail 
3276146b9756SMustafa Ismail 	spin_lock_init(&cm_core->ht_lock);
3277146b9756SMustafa Ismail 	spin_lock_init(&cm_core->listen_list_lock);
3278146b9756SMustafa Ismail 	spin_lock_init(&cm_core->apbvt_lock);
3279146b9756SMustafa Ismail 	switch (rdma_ver) {
3280146b9756SMustafa Ismail 	case IRDMA_GEN_1:
3281146b9756SMustafa Ismail 		cm_core->form_cm_frame = irdma_form_uda_cm_frame;
3282146b9756SMustafa Ismail 		cm_core->cm_create_ah = irdma_add_qh;
3283146b9756SMustafa Ismail 		cm_core->cm_free_ah = irdma_cm_free_ah_nop;
3284146b9756SMustafa Ismail 		break;
3285146b9756SMustafa Ismail 	case IRDMA_GEN_2:
3286146b9756SMustafa Ismail 	default:
3287146b9756SMustafa Ismail 		cm_core->form_cm_frame = irdma_form_ah_cm_frame;
3288146b9756SMustafa Ismail 		cm_core->cm_create_ah = irdma_cm_create_ah;
3289146b9756SMustafa Ismail 		cm_core->cm_free_ah = irdma_cm_free_ah;
3290146b9756SMustafa Ismail 	}
3291146b9756SMustafa Ismail 
3292146b9756SMustafa Ismail 	return 0;
3293146b9756SMustafa Ismail }
3294146b9756SMustafa Ismail 
3295146b9756SMustafa Ismail /**
3296146b9756SMustafa Ismail  * irdma_cleanup_cm_core - deallocate a top level instance of a
3297146b9756SMustafa Ismail  * cm core
3298146b9756SMustafa Ismail  * @cm_core: cm's core
3299146b9756SMustafa Ismail  */
irdma_cleanup_cm_core(struct irdma_cm_core * cm_core)3300146b9756SMustafa Ismail void irdma_cleanup_cm_core(struct irdma_cm_core *cm_core)
3301146b9756SMustafa Ismail {
3302146b9756SMustafa Ismail 	if (!cm_core)
3303146b9756SMustafa Ismail 		return;
3304146b9756SMustafa Ismail 
3305146b9756SMustafa Ismail 	del_timer_sync(&cm_core->tcp_timer);
3306146b9756SMustafa Ismail 
3307146b9756SMustafa Ismail 	destroy_workqueue(cm_core->event_wq);
3308146b9756SMustafa Ismail 	cm_core->dev->ws_reset(&cm_core->iwdev->vsi);
3309146b9756SMustafa Ismail }
3310146b9756SMustafa Ismail 
3311146b9756SMustafa Ismail /**
3312146b9756SMustafa Ismail  * irdma_init_tcp_ctx - setup qp context
3313146b9756SMustafa Ismail  * @cm_node: connection's node
3314146b9756SMustafa Ismail  * @tcp_info: offload info for tcp
3315146b9756SMustafa Ismail  * @iwqp: associate qp for the connection
3316146b9756SMustafa Ismail  */
irdma_init_tcp_ctx(struct irdma_cm_node * cm_node,struct irdma_tcp_offload_info * tcp_info,struct irdma_qp * iwqp)3317146b9756SMustafa Ismail static void irdma_init_tcp_ctx(struct irdma_cm_node *cm_node,
3318146b9756SMustafa Ismail 			       struct irdma_tcp_offload_info *tcp_info,
3319146b9756SMustafa Ismail 			       struct irdma_qp *iwqp)
3320146b9756SMustafa Ismail {
3321146b9756SMustafa Ismail 	tcp_info->ipv4 = cm_node->ipv4;
3322146b9756SMustafa Ismail 	tcp_info->drop_ooo_seg = !iwqp->iwdev->iw_ooo;
3323146b9756SMustafa Ismail 	tcp_info->wscale = true;
3324146b9756SMustafa Ismail 	tcp_info->ignore_tcp_opt = true;
3325146b9756SMustafa Ismail 	tcp_info->ignore_tcp_uns_opt = true;
3326146b9756SMustafa Ismail 	tcp_info->no_nagle = false;
3327146b9756SMustafa Ismail 
3328146b9756SMustafa Ismail 	tcp_info->ttl = IRDMA_DEFAULT_TTL;
3329146b9756SMustafa Ismail 	tcp_info->rtt_var = IRDMA_DEFAULT_RTT_VAR;
3330146b9756SMustafa Ismail 	tcp_info->ss_thresh = IRDMA_DEFAULT_SS_THRESH;
3331146b9756SMustafa Ismail 	tcp_info->rexmit_thresh = IRDMA_DEFAULT_REXMIT_THRESH;
3332146b9756SMustafa Ismail 
3333146b9756SMustafa Ismail 	tcp_info->tcp_state = IRDMA_TCP_STATE_ESTABLISHED;
3334146b9756SMustafa Ismail 	tcp_info->snd_wscale = cm_node->tcp_cntxt.snd_wscale;
3335146b9756SMustafa Ismail 	tcp_info->rcv_wscale = cm_node->tcp_cntxt.rcv_wscale;
3336146b9756SMustafa Ismail 
3337146b9756SMustafa Ismail 	tcp_info->snd_nxt = cm_node->tcp_cntxt.loc_seq_num;
3338146b9756SMustafa Ismail 	tcp_info->snd_wnd = cm_node->tcp_cntxt.snd_wnd;
3339146b9756SMustafa Ismail 	tcp_info->rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;
3340146b9756SMustafa Ismail 	tcp_info->snd_max = cm_node->tcp_cntxt.loc_seq_num;
3341146b9756SMustafa Ismail 
3342146b9756SMustafa Ismail 	tcp_info->snd_una = cm_node->tcp_cntxt.loc_seq_num;
3343146b9756SMustafa Ismail 	tcp_info->cwnd = 2 * cm_node->tcp_cntxt.mss;
3344146b9756SMustafa Ismail 	tcp_info->snd_wl1 = cm_node->tcp_cntxt.rcv_nxt;
3345146b9756SMustafa Ismail 	tcp_info->snd_wl2 = cm_node->tcp_cntxt.loc_seq_num;
3346146b9756SMustafa Ismail 	tcp_info->max_snd_window = cm_node->tcp_cntxt.max_snd_wnd;
3347146b9756SMustafa Ismail 	tcp_info->rcv_wnd = cm_node->tcp_cntxt.rcv_wnd
3348146b9756SMustafa Ismail 			    << cm_node->tcp_cntxt.rcv_wscale;
3349146b9756SMustafa Ismail 
3350146b9756SMustafa Ismail 	tcp_info->flow_label = 0;
3351146b9756SMustafa Ismail 	tcp_info->snd_mss = (u32)cm_node->tcp_cntxt.mss;
3352146b9756SMustafa Ismail 	tcp_info->tos = cm_node->tos;
3353146b9756SMustafa Ismail 	if (cm_node->vlan_id < VLAN_N_VID) {
3354146b9756SMustafa Ismail 		tcp_info->insert_vlan_tag = true;
3355146b9756SMustafa Ismail 		tcp_info->vlan_tag = cm_node->vlan_id;
3356146b9756SMustafa Ismail 		tcp_info->vlan_tag |= cm_node->user_pri << VLAN_PRIO_SHIFT;
3357146b9756SMustafa Ismail 	}
3358146b9756SMustafa Ismail 	if (cm_node->ipv4) {
3359146b9756SMustafa Ismail 		tcp_info->src_port = cm_node->loc_port;
3360146b9756SMustafa Ismail 		tcp_info->dst_port = cm_node->rem_port;
3361146b9756SMustafa Ismail 
3362146b9756SMustafa Ismail 		tcp_info->dest_ip_addr[3] = cm_node->rem_addr[0];
3363146b9756SMustafa Ismail 		tcp_info->local_ipaddr[3] = cm_node->loc_addr[0];
3364146b9756SMustafa Ismail 		tcp_info->arp_idx = (u16)irdma_arp_table(iwqp->iwdev->rf,
3365146b9756SMustafa Ismail 							 &tcp_info->dest_ip_addr[3],
3366146b9756SMustafa Ismail 							 true, NULL,
3367146b9756SMustafa Ismail 							 IRDMA_ARP_RESOLVE);
3368146b9756SMustafa Ismail 	} else {
3369146b9756SMustafa Ismail 		tcp_info->src_port = cm_node->loc_port;
3370146b9756SMustafa Ismail 		tcp_info->dst_port = cm_node->rem_port;
3371146b9756SMustafa Ismail 		memcpy(tcp_info->dest_ip_addr, cm_node->rem_addr,
3372146b9756SMustafa Ismail 		       sizeof(tcp_info->dest_ip_addr));
3373146b9756SMustafa Ismail 		memcpy(tcp_info->local_ipaddr, cm_node->loc_addr,
3374146b9756SMustafa Ismail 		       sizeof(tcp_info->local_ipaddr));
3375146b9756SMustafa Ismail 
3376146b9756SMustafa Ismail 		tcp_info->arp_idx = (u16)irdma_arp_table(iwqp->iwdev->rf,
3377146b9756SMustafa Ismail 							 &tcp_info->dest_ip_addr[0],
3378146b9756SMustafa Ismail 							 false, NULL,
3379146b9756SMustafa Ismail 							 IRDMA_ARP_RESOLVE);
3380146b9756SMustafa Ismail 	}
3381146b9756SMustafa Ismail }
3382146b9756SMustafa Ismail 
3383146b9756SMustafa Ismail /**
3384146b9756SMustafa Ismail  * irdma_cm_init_tsa_conn - setup qp for RTS
3385146b9756SMustafa Ismail  * @iwqp: associate qp for the connection
3386146b9756SMustafa Ismail  * @cm_node: connection's node
3387146b9756SMustafa Ismail  */
irdma_cm_init_tsa_conn(struct irdma_qp * iwqp,struct irdma_cm_node * cm_node)3388146b9756SMustafa Ismail static void irdma_cm_init_tsa_conn(struct irdma_qp *iwqp,
3389146b9756SMustafa Ismail 				   struct irdma_cm_node *cm_node)
3390146b9756SMustafa Ismail {
3391146b9756SMustafa Ismail 	struct irdma_iwarp_offload_info *iwarp_info;
3392146b9756SMustafa Ismail 	struct irdma_qp_host_ctx_info *ctx_info;
3393146b9756SMustafa Ismail 
3394146b9756SMustafa Ismail 	iwarp_info = &iwqp->iwarp_info;
3395146b9756SMustafa Ismail 	ctx_info = &iwqp->ctx_info;
3396146b9756SMustafa Ismail 
3397146b9756SMustafa Ismail 	ctx_info->tcp_info = &iwqp->tcp_info;
3398146b9756SMustafa Ismail 	ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
3399146b9756SMustafa Ismail 	ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
3400146b9756SMustafa Ismail 
3401146b9756SMustafa Ismail 	iwarp_info->ord_size = cm_node->ord_size;
3402146b9756SMustafa Ismail 	iwarp_info->ird_size = cm_node->ird_size;
3403146b9756SMustafa Ismail 	iwarp_info->rd_en = true;
3404146b9756SMustafa Ismail 	iwarp_info->rdmap_ver = 1;
3405146b9756SMustafa Ismail 	iwarp_info->ddp_ver = 1;
3406146b9756SMustafa Ismail 	iwarp_info->pd_id = iwqp->iwpd->sc_pd.pd_id;
3407146b9756SMustafa Ismail 
3408146b9756SMustafa Ismail 	ctx_info->tcp_info_valid = true;
3409146b9756SMustafa Ismail 	ctx_info->iwarp_info_valid = true;
3410146b9756SMustafa Ismail 	ctx_info->user_pri = cm_node->user_pri;
3411146b9756SMustafa Ismail 
3412146b9756SMustafa Ismail 	irdma_init_tcp_ctx(cm_node, &iwqp->tcp_info, iwqp);
3413146b9756SMustafa Ismail 	if (cm_node->snd_mark_en) {
3414146b9756SMustafa Ismail 		iwarp_info->snd_mark_en = true;
3415146b9756SMustafa Ismail 		iwarp_info->snd_mark_offset = (iwqp->tcp_info.snd_nxt & SNDMARKER_SEQNMASK) +
3416146b9756SMustafa Ismail 					       cm_node->lsmm_size;
3417146b9756SMustafa Ismail 	}
3418146b9756SMustafa Ismail 
3419146b9756SMustafa Ismail 	cm_node->state = IRDMA_CM_STATE_OFFLOADED;
3420146b9756SMustafa Ismail 	iwqp->tcp_info.tcp_state = IRDMA_TCP_STATE_ESTABLISHED;
3421146b9756SMustafa Ismail 	iwqp->tcp_info.src_mac_addr_idx = iwqp->iwdev->mac_ip_table_idx;
3422146b9756SMustafa Ismail 
3423146b9756SMustafa Ismail 	if (cm_node->rcv_mark_en) {
3424146b9756SMustafa Ismail 		iwarp_info->rcv_mark_en = true;
3425146b9756SMustafa Ismail 		iwarp_info->align_hdrs = true;
3426146b9756SMustafa Ismail 	}
3427146b9756SMustafa Ismail 
3428146b9756SMustafa Ismail 	irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
3429146b9756SMustafa Ismail 
3430146b9756SMustafa Ismail 	/* once tcp_info is set, no need to do it again */
3431146b9756SMustafa Ismail 	ctx_info->tcp_info_valid = false;
3432146b9756SMustafa Ismail 	ctx_info->iwarp_info_valid = false;
3433146b9756SMustafa Ismail }
3434146b9756SMustafa Ismail 
3435146b9756SMustafa Ismail /**
3436146b9756SMustafa Ismail  * irdma_cm_disconn - when a connection is being closed
3437146b9756SMustafa Ismail  * @iwqp: associated qp for the connection
3438146b9756SMustafa Ismail  */
irdma_cm_disconn(struct irdma_qp * iwqp)3439146b9756SMustafa Ismail void irdma_cm_disconn(struct irdma_qp *iwqp)
3440146b9756SMustafa Ismail {
3441146b9756SMustafa Ismail 	struct irdma_device *iwdev = iwqp->iwdev;
3442146b9756SMustafa Ismail 	struct disconn_work *work;
3443146b9756SMustafa Ismail 	unsigned long flags;
3444146b9756SMustafa Ismail 
3445146b9756SMustafa Ismail 	work = kzalloc(sizeof(*work), GFP_ATOMIC);
3446146b9756SMustafa Ismail 	if (!work)
3447146b9756SMustafa Ismail 		return;
3448146b9756SMustafa Ismail 
3449146b9756SMustafa Ismail 	spin_lock_irqsave(&iwdev->rf->qptable_lock, flags);
3450146b9756SMustafa Ismail 	if (!iwdev->rf->qp_table[iwqp->ibqp.qp_num]) {
3451146b9756SMustafa Ismail 		spin_unlock_irqrestore(&iwdev->rf->qptable_lock, flags);
3452146b9756SMustafa Ismail 		ibdev_dbg(&iwdev->ibdev,
3453146b9756SMustafa Ismail 			  "CM: qp_id %d is already freed\n",
3454146b9756SMustafa Ismail 			  iwqp->ibqp.qp_num);
3455146b9756SMustafa Ismail 		kfree(work);
3456146b9756SMustafa Ismail 		return;
3457146b9756SMustafa Ismail 	}
3458146b9756SMustafa Ismail 	irdma_qp_add_ref(&iwqp->ibqp);
3459146b9756SMustafa Ismail 	spin_unlock_irqrestore(&iwdev->rf->qptable_lock, flags);
3460146b9756SMustafa Ismail 
3461146b9756SMustafa Ismail 	work->iwqp = iwqp;
3462146b9756SMustafa Ismail 	INIT_WORK(&work->work, irdma_disconnect_worker);
3463146b9756SMustafa Ismail 	queue_work(iwdev->cleanup_wq, &work->work);
3464146b9756SMustafa Ismail }
3465146b9756SMustafa Ismail 
3466146b9756SMustafa Ismail /**
3467146b9756SMustafa Ismail  * irdma_qp_disconnect - free qp and close cm
3468146b9756SMustafa Ismail  * @iwqp: associate qp for the connection
3469146b9756SMustafa Ismail  */
irdma_qp_disconnect(struct irdma_qp * iwqp)3470146b9756SMustafa Ismail static void irdma_qp_disconnect(struct irdma_qp *iwqp)
3471146b9756SMustafa Ismail {
3472146b9756SMustafa Ismail 	struct irdma_device *iwdev = iwqp->iwdev;
3473146b9756SMustafa Ismail 
3474146b9756SMustafa Ismail 	iwqp->active_conn = 0;
3475146b9756SMustafa Ismail 	/* close the CM node down if it is still active */
3476146b9756SMustafa Ismail 	ibdev_dbg(&iwdev->ibdev, "CM: Call close API\n");
3477146b9756SMustafa Ismail 	irdma_cm_close(iwqp->cm_node);
3478146b9756SMustafa Ismail }
3479146b9756SMustafa Ismail 
3480146b9756SMustafa Ismail /**
3481146b9756SMustafa Ismail  * irdma_cm_disconn_true - called by worker thread to disconnect qp
3482146b9756SMustafa Ismail  * @iwqp: associate qp for the connection
3483146b9756SMustafa Ismail  */
irdma_cm_disconn_true(struct irdma_qp * iwqp)3484146b9756SMustafa Ismail static void irdma_cm_disconn_true(struct irdma_qp *iwqp)
3485146b9756SMustafa Ismail {
3486146b9756SMustafa Ismail 	struct iw_cm_id *cm_id;
3487146b9756SMustafa Ismail 	struct irdma_device *iwdev;
3488146b9756SMustafa Ismail 	struct irdma_sc_qp *qp = &iwqp->sc_qp;
3489146b9756SMustafa Ismail 	u16 last_ae;
3490146b9756SMustafa Ismail 	u8 original_hw_tcp_state;
3491146b9756SMustafa Ismail 	u8 original_ibqp_state;
3492146b9756SMustafa Ismail 	int disconn_status = 0;
3493146b9756SMustafa Ismail 	int issue_disconn = 0;
3494146b9756SMustafa Ismail 	int issue_close = 0;
3495146b9756SMustafa Ismail 	int issue_flush = 0;
3496146b9756SMustafa Ismail 	unsigned long flags;
3497146b9756SMustafa Ismail 	int err;
3498146b9756SMustafa Ismail 
3499146b9756SMustafa Ismail 	iwdev = iwqp->iwdev;
3500146b9756SMustafa Ismail 	spin_lock_irqsave(&iwqp->lock, flags);
3501146b9756SMustafa Ismail 	if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
3502146b9756SMustafa Ismail 		struct ib_qp_attr attr;
3503146b9756SMustafa Ismail 
3504146b9756SMustafa Ismail 		if (iwqp->flush_issued || iwqp->sc_qp.qp_uk.destroy_pending) {
3505146b9756SMustafa Ismail 			spin_unlock_irqrestore(&iwqp->lock, flags);
3506146b9756SMustafa Ismail 			return;
3507146b9756SMustafa Ismail 		}
3508146b9756SMustafa Ismail 
3509146b9756SMustafa Ismail 		spin_unlock_irqrestore(&iwqp->lock, flags);
3510146b9756SMustafa Ismail 
3511146b9756SMustafa Ismail 		attr.qp_state = IB_QPS_ERR;
3512146b9756SMustafa Ismail 		irdma_modify_qp_roce(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
3513146b9756SMustafa Ismail 		irdma_ib_qp_event(iwqp, qp->event_type);
3514146b9756SMustafa Ismail 		return;
3515146b9756SMustafa Ismail 	}
3516146b9756SMustafa Ismail 
3517146b9756SMustafa Ismail 	cm_id = iwqp->cm_id;
3518146b9756SMustafa Ismail 	original_hw_tcp_state = iwqp->hw_tcp_state;
3519146b9756SMustafa Ismail 	original_ibqp_state = iwqp->ibqp_state;
3520146b9756SMustafa Ismail 	last_ae = iwqp->last_aeq;
3521146b9756SMustafa Ismail 
3522146b9756SMustafa Ismail 	if (qp->term_flags) {
3523146b9756SMustafa Ismail 		issue_disconn = 1;
3524146b9756SMustafa Ismail 		issue_close = 1;
3525146b9756SMustafa Ismail 		iwqp->cm_id = NULL;
3526146b9756SMustafa Ismail 		irdma_terminate_del_timer(qp);
3527146b9756SMustafa Ismail 		if (!iwqp->flush_issued) {
3528146b9756SMustafa Ismail 			iwqp->flush_issued = 1;
3529146b9756SMustafa Ismail 			issue_flush = 1;
3530146b9756SMustafa Ismail 		}
3531146b9756SMustafa Ismail 	} else if ((original_hw_tcp_state == IRDMA_TCP_STATE_CLOSE_WAIT) ||
3532146b9756SMustafa Ismail 		   ((original_ibqp_state == IB_QPS_RTS) &&
3533146b9756SMustafa Ismail 		    (last_ae == IRDMA_AE_LLP_CONNECTION_RESET))) {
3534146b9756SMustafa Ismail 		issue_disconn = 1;
3535146b9756SMustafa Ismail 		if (last_ae == IRDMA_AE_LLP_CONNECTION_RESET)
3536146b9756SMustafa Ismail 			disconn_status = -ECONNRESET;
3537146b9756SMustafa Ismail 	}
3538146b9756SMustafa Ismail 
35397b8943b8STatyana Nikolova 	if (original_hw_tcp_state == IRDMA_TCP_STATE_CLOSED ||
3540146b9756SMustafa Ismail 	    original_hw_tcp_state == IRDMA_TCP_STATE_TIME_WAIT ||
3541146b9756SMustafa Ismail 	    last_ae == IRDMA_AE_RDMAP_ROE_BAD_LLP_CLOSE ||
3542146b9756SMustafa Ismail 	    last_ae == IRDMA_AE_BAD_CLOSE ||
35437b8943b8STatyana Nikolova 	    last_ae == IRDMA_AE_LLP_CONNECTION_RESET || iwdev->rf->reset || !cm_id) {
3544146b9756SMustafa Ismail 		issue_close = 1;
3545146b9756SMustafa Ismail 		iwqp->cm_id = NULL;
3546146b9756SMustafa Ismail 		qp->term_flags = 0;
3547146b9756SMustafa Ismail 		if (!iwqp->flush_issued) {
3548146b9756SMustafa Ismail 			iwqp->flush_issued = 1;
3549146b9756SMustafa Ismail 			issue_flush = 1;
3550146b9756SMustafa Ismail 		}
3551146b9756SMustafa Ismail 	}
3552146b9756SMustafa Ismail 
3553146b9756SMustafa Ismail 	spin_unlock_irqrestore(&iwqp->lock, flags);
3554146b9756SMustafa Ismail 	if (issue_flush && !iwqp->sc_qp.qp_uk.destroy_pending) {
3555146b9756SMustafa Ismail 		irdma_flush_wqes(iwqp, IRDMA_FLUSH_SQ | IRDMA_FLUSH_RQ |
3556146b9756SMustafa Ismail 				 IRDMA_FLUSH_WAIT);
3557146b9756SMustafa Ismail 
3558146b9756SMustafa Ismail 		if (qp->term_flags)
3559146b9756SMustafa Ismail 			irdma_ib_qp_event(iwqp, qp->event_type);
3560146b9756SMustafa Ismail 	}
3561146b9756SMustafa Ismail 
3562146b9756SMustafa Ismail 	if (!cm_id || !cm_id->event_handler)
3563146b9756SMustafa Ismail 		return;
3564146b9756SMustafa Ismail 
3565146b9756SMustafa Ismail 	spin_lock_irqsave(&iwdev->cm_core.ht_lock, flags);
3566146b9756SMustafa Ismail 	if (!iwqp->cm_node) {
3567146b9756SMustafa Ismail 		spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
3568146b9756SMustafa Ismail 		return;
3569146b9756SMustafa Ismail 	}
3570146b9756SMustafa Ismail 	refcount_inc(&iwqp->cm_node->refcnt);
3571146b9756SMustafa Ismail 
3572146b9756SMustafa Ismail 	spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
3573146b9756SMustafa Ismail 
3574146b9756SMustafa Ismail 	if (issue_disconn) {
3575146b9756SMustafa Ismail 		err = irdma_send_cm_event(iwqp->cm_node, cm_id,
3576146b9756SMustafa Ismail 					  IW_CM_EVENT_DISCONNECT,
3577146b9756SMustafa Ismail 					  disconn_status);
3578146b9756SMustafa Ismail 		if (err)
3579146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev,
3580146b9756SMustafa Ismail 				  "CM: disconnect event failed: - cm_id = %p\n",
3581146b9756SMustafa Ismail 				  cm_id);
3582146b9756SMustafa Ismail 	}
3583146b9756SMustafa Ismail 	if (issue_close) {
3584146b9756SMustafa Ismail 		cm_id->provider_data = iwqp;
3585146b9756SMustafa Ismail 		err = irdma_send_cm_event(iwqp->cm_node, cm_id,
3586146b9756SMustafa Ismail 					  IW_CM_EVENT_CLOSE, 0);
3587146b9756SMustafa Ismail 		if (err)
3588146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev,
3589146b9756SMustafa Ismail 				  "CM: close event failed: - cm_id = %p\n",
3590146b9756SMustafa Ismail 				  cm_id);
3591146b9756SMustafa Ismail 		irdma_qp_disconnect(iwqp);
3592146b9756SMustafa Ismail 	}
3593146b9756SMustafa Ismail 	irdma_rem_ref_cm_node(iwqp->cm_node);
3594146b9756SMustafa Ismail }
3595146b9756SMustafa Ismail 
3596146b9756SMustafa Ismail /**
3597146b9756SMustafa Ismail  * irdma_disconnect_worker - worker for connection close
3598146b9756SMustafa Ismail  * @work: points or disconn structure
3599146b9756SMustafa Ismail  */
irdma_disconnect_worker(struct work_struct * work)3600146b9756SMustafa Ismail static void irdma_disconnect_worker(struct work_struct *work)
3601146b9756SMustafa Ismail {
3602146b9756SMustafa Ismail 	struct disconn_work *dwork = container_of(work, struct disconn_work, work);
3603146b9756SMustafa Ismail 	struct irdma_qp *iwqp = dwork->iwqp;
3604146b9756SMustafa Ismail 
3605146b9756SMustafa Ismail 	kfree(dwork);
3606146b9756SMustafa Ismail 	irdma_cm_disconn_true(iwqp);
3607146b9756SMustafa Ismail 	irdma_qp_rem_ref(&iwqp->ibqp);
3608146b9756SMustafa Ismail }
3609146b9756SMustafa Ismail 
3610146b9756SMustafa Ismail /**
3611146b9756SMustafa Ismail  * irdma_free_lsmm_rsrc - free lsmm memory and deregister
3612146b9756SMustafa Ismail  * @iwqp: associate qp for the connection
3613146b9756SMustafa Ismail  */
irdma_free_lsmm_rsrc(struct irdma_qp * iwqp)3614146b9756SMustafa Ismail void irdma_free_lsmm_rsrc(struct irdma_qp *iwqp)
3615146b9756SMustafa Ismail {
3616146b9756SMustafa Ismail 	struct irdma_device *iwdev;
3617146b9756SMustafa Ismail 
3618146b9756SMustafa Ismail 	iwdev = iwqp->iwdev;
3619146b9756SMustafa Ismail 
3620146b9756SMustafa Ismail 	if (iwqp->ietf_mem.va) {
3621146b9756SMustafa Ismail 		if (iwqp->lsmm_mr)
3622146b9756SMustafa Ismail 			iwdev->ibdev.ops.dereg_mr(iwqp->lsmm_mr, NULL);
3623146b9756SMustafa Ismail 		dma_free_coherent(iwdev->rf->sc_dev.hw->device,
3624146b9756SMustafa Ismail 				  iwqp->ietf_mem.size, iwqp->ietf_mem.va,
3625146b9756SMustafa Ismail 				  iwqp->ietf_mem.pa);
3626146b9756SMustafa Ismail 		iwqp->ietf_mem.va = NULL;
3627146b9756SMustafa Ismail 	}
3628146b9756SMustafa Ismail }
3629146b9756SMustafa Ismail 
3630146b9756SMustafa Ismail /**
3631146b9756SMustafa Ismail  * irdma_accept - registered call for connection to be accepted
3632146b9756SMustafa Ismail  * @cm_id: cm information for passive connection
3633*af29c430SAlexander Zubkov  * @conn_param: accept parameters
3634146b9756SMustafa Ismail  */
irdma_accept(struct iw_cm_id * cm_id,struct iw_cm_conn_param * conn_param)3635146b9756SMustafa Ismail int irdma_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
3636146b9756SMustafa Ismail {
3637146b9756SMustafa Ismail 	struct ib_qp *ibqp;
3638146b9756SMustafa Ismail 	struct irdma_qp *iwqp;
3639146b9756SMustafa Ismail 	struct irdma_device *iwdev;
3640146b9756SMustafa Ismail 	struct irdma_sc_dev *dev;
3641146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
3642146b9756SMustafa Ismail 	struct ib_qp_attr attr = {};
3643146b9756SMustafa Ismail 	int passive_state;
3644146b9756SMustafa Ismail 	struct ib_mr *ibmr;
3645146b9756SMustafa Ismail 	struct irdma_pd *iwpd;
3646146b9756SMustafa Ismail 	u16 buf_len = 0;
3647146b9756SMustafa Ismail 	struct irdma_kmem_info accept;
3648146b9756SMustafa Ismail 	u64 tagged_offset;
3649146b9756SMustafa Ismail 	int wait_ret;
3650146b9756SMustafa Ismail 	int ret = 0;
3651146b9756SMustafa Ismail 
3652146b9756SMustafa Ismail 	ibqp = irdma_get_qp(cm_id->device, conn_param->qpn);
3653146b9756SMustafa Ismail 	if (!ibqp)
3654146b9756SMustafa Ismail 		return -EINVAL;
3655146b9756SMustafa Ismail 
3656146b9756SMustafa Ismail 	iwqp = to_iwqp(ibqp);
3657146b9756SMustafa Ismail 	iwdev = iwqp->iwdev;
3658146b9756SMustafa Ismail 	dev = &iwdev->rf->sc_dev;
3659146b9756SMustafa Ismail 	cm_node = cm_id->provider_data;
3660146b9756SMustafa Ismail 
3661146b9756SMustafa Ismail 	if (((struct sockaddr_in *)&cm_id->local_addr)->sin_family == AF_INET) {
3662146b9756SMustafa Ismail 		cm_node->ipv4 = true;
3663146b9756SMustafa Ismail 		cm_node->vlan_id = irdma_get_vlan_ipv4(cm_node->loc_addr);
3664146b9756SMustafa Ismail 	} else {
3665146b9756SMustafa Ismail 		cm_node->ipv4 = false;
3666693e1cdeSMustafa Ismail 		irdma_get_vlan_mac_ipv6(cm_node->loc_addr, &cm_node->vlan_id,
3667146b9756SMustafa Ismail 					NULL);
3668146b9756SMustafa Ismail 	}
3669146b9756SMustafa Ismail 	ibdev_dbg(&iwdev->ibdev, "CM: Accept vlan_id=%d\n",
3670146b9756SMustafa Ismail 		  cm_node->vlan_id);
3671146b9756SMustafa Ismail 
3672146b9756SMustafa Ismail 	trace_irdma_accept(cm_node, 0, NULL);
3673146b9756SMustafa Ismail 
3674146b9756SMustafa Ismail 	if (cm_node->state == IRDMA_CM_STATE_LISTENER_DESTROYED) {
3675146b9756SMustafa Ismail 		ret = -EINVAL;
3676146b9756SMustafa Ismail 		goto error;
3677146b9756SMustafa Ismail 	}
3678146b9756SMustafa Ismail 
3679146b9756SMustafa Ismail 	passive_state = atomic_add_return(1, &cm_node->passive_state);
3680146b9756SMustafa Ismail 	if (passive_state == IRDMA_SEND_RESET_EVENT) {
3681146b9756SMustafa Ismail 		ret = -ECONNRESET;
3682146b9756SMustafa Ismail 		goto error;
3683146b9756SMustafa Ismail 	}
3684146b9756SMustafa Ismail 
3685146b9756SMustafa Ismail 	buf_len = conn_param->private_data_len + IRDMA_MAX_IETF_SIZE;
3686146b9756SMustafa Ismail 	iwqp->ietf_mem.size = ALIGN(buf_len, 1);
3687146b9756SMustafa Ismail 	iwqp->ietf_mem.va = dma_alloc_coherent(dev->hw->device,
3688146b9756SMustafa Ismail 					       iwqp->ietf_mem.size,
3689146b9756SMustafa Ismail 					       &iwqp->ietf_mem.pa, GFP_KERNEL);
3690146b9756SMustafa Ismail 	if (!iwqp->ietf_mem.va) {
3691146b9756SMustafa Ismail 		ret = -ENOMEM;
3692146b9756SMustafa Ismail 		goto error;
3693146b9756SMustafa Ismail 	}
3694146b9756SMustafa Ismail 
3695146b9756SMustafa Ismail 	cm_node->pdata.size = conn_param->private_data_len;
3696146b9756SMustafa Ismail 	accept.addr = iwqp->ietf_mem.va;
3697146b9756SMustafa Ismail 	accept.size = irdma_cm_build_mpa_frame(cm_node, &accept, MPA_KEY_REPLY);
3698146b9756SMustafa Ismail 	memcpy((u8 *)accept.addr + accept.size, conn_param->private_data,
3699146b9756SMustafa Ismail 	       conn_param->private_data_len);
3700146b9756SMustafa Ismail 
3701146b9756SMustafa Ismail 	if (cm_node->dev->ws_add(iwqp->sc_qp.vsi, cm_node->user_pri)) {
3702146b9756SMustafa Ismail 		ret = -ENOMEM;
3703146b9756SMustafa Ismail 		goto error;
3704146b9756SMustafa Ismail 	}
3705146b9756SMustafa Ismail 	iwqp->sc_qp.user_pri = cm_node->user_pri;
3706146b9756SMustafa Ismail 	irdma_qp_add_qos(&iwqp->sc_qp);
3707146b9756SMustafa Ismail 	/* setup our first outgoing iWarp send WQE (the IETF frame response) */
3708146b9756SMustafa Ismail 	iwpd = iwqp->iwpd;
3709146b9756SMustafa Ismail 	tagged_offset = (uintptr_t)iwqp->ietf_mem.va;
3710146b9756SMustafa Ismail 	ibmr = irdma_reg_phys_mr(&iwpd->ibpd, iwqp->ietf_mem.pa, buf_len,
3711146b9756SMustafa Ismail 				 IB_ACCESS_LOCAL_WRITE, &tagged_offset);
3712146b9756SMustafa Ismail 	if (IS_ERR(ibmr)) {
3713146b9756SMustafa Ismail 		ret = -ENOMEM;
3714146b9756SMustafa Ismail 		goto error;
3715146b9756SMustafa Ismail 	}
3716146b9756SMustafa Ismail 
3717146b9756SMustafa Ismail 	ibmr->pd = &iwpd->ibpd;
3718146b9756SMustafa Ismail 	ibmr->device = iwpd->ibpd.device;
3719146b9756SMustafa Ismail 	iwqp->lsmm_mr = ibmr;
3720146b9756SMustafa Ismail 	if (iwqp->page)
37217364e74dSIra Weiny 		iwqp->sc_qp.qp_uk.sq_base = kmap_local_page(iwqp->page);
3722146b9756SMustafa Ismail 
3723146b9756SMustafa Ismail 	cm_node->lsmm_size = accept.size + conn_param->private_data_len;
3724146b9756SMustafa Ismail 	irdma_sc_send_lsmm(&iwqp->sc_qp, iwqp->ietf_mem.va, cm_node->lsmm_size,
3725146b9756SMustafa Ismail 			   ibmr->lkey);
3726146b9756SMustafa Ismail 
3727146b9756SMustafa Ismail 	if (iwqp->page)
37287364e74dSIra Weiny 		kunmap_local(iwqp->sc_qp.qp_uk.sq_base);
3729146b9756SMustafa Ismail 
3730146b9756SMustafa Ismail 	iwqp->cm_id = cm_id;
3731146b9756SMustafa Ismail 	cm_node->cm_id = cm_id;
3732146b9756SMustafa Ismail 
3733146b9756SMustafa Ismail 	cm_id->provider_data = iwqp;
3734146b9756SMustafa Ismail 	iwqp->active_conn = 0;
3735146b9756SMustafa Ismail 	iwqp->cm_node = cm_node;
3736146b9756SMustafa Ismail 	cm_node->iwqp = iwqp;
3737146b9756SMustafa Ismail 	irdma_cm_init_tsa_conn(iwqp, cm_node);
3738146b9756SMustafa Ismail 	irdma_qp_add_ref(&iwqp->ibqp);
3739146b9756SMustafa Ismail 	cm_id->add_ref(cm_id);
3740146b9756SMustafa Ismail 
3741146b9756SMustafa Ismail 	attr.qp_state = IB_QPS_RTS;
3742146b9756SMustafa Ismail 	cm_node->qhash_set = false;
3743146b9756SMustafa Ismail 	cm_node->cm_core->cm_free_ah(cm_node);
3744146b9756SMustafa Ismail 
3745146b9756SMustafa Ismail 	irdma_modify_qp(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
3746146b9756SMustafa Ismail 	if (dev->hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_RTS_AE) {
3747146b9756SMustafa Ismail 		wait_ret = wait_event_interruptible_timeout(iwqp->waitq,
3748146b9756SMustafa Ismail 							    iwqp->rts_ae_rcvd,
3749146b9756SMustafa Ismail 							    IRDMA_MAX_TIMEOUT);
3750146b9756SMustafa Ismail 		if (!wait_ret) {
3751146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev,
3752146b9756SMustafa Ismail 				  "CM: Slow Connection: cm_node=%p, loc_port=%d, rem_port=%d, cm_id=%p\n",
3753146b9756SMustafa Ismail 				  cm_node, cm_node->loc_port,
3754146b9756SMustafa Ismail 				  cm_node->rem_port, cm_node->cm_id);
3755146b9756SMustafa Ismail 			ret = -ECONNRESET;
3756146b9756SMustafa Ismail 			goto error;
3757146b9756SMustafa Ismail 		}
3758146b9756SMustafa Ismail 	}
3759146b9756SMustafa Ismail 
3760146b9756SMustafa Ismail 	irdma_send_cm_event(cm_node, cm_id, IW_CM_EVENT_ESTABLISHED, 0);
3761146b9756SMustafa Ismail 	cm_node->accelerated = true;
3762146b9756SMustafa Ismail 	complete(&cm_node->establish_comp);
3763146b9756SMustafa Ismail 
3764146b9756SMustafa Ismail 	if (cm_node->accept_pend) {
3765146b9756SMustafa Ismail 		atomic_dec(&cm_node->listener->pend_accepts_cnt);
3766146b9756SMustafa Ismail 		cm_node->accept_pend = 0;
3767146b9756SMustafa Ismail 	}
3768146b9756SMustafa Ismail 
3769146b9756SMustafa Ismail 	ibdev_dbg(&iwdev->ibdev,
3770146b9756SMustafa Ismail 		  "CM: rem_port=0x%04x, loc_port=0x%04x rem_addr=%pI4 loc_addr=%pI4 cm_node=%p cm_id=%p qp_id = %d\n\n",
3771146b9756SMustafa Ismail 		  cm_node->rem_port, cm_node->loc_port, cm_node->rem_addr,
3772146b9756SMustafa Ismail 		  cm_node->loc_addr, cm_node, cm_id, ibqp->qp_num);
3773146b9756SMustafa Ismail 	cm_node->cm_core->stats_accepts++;
3774146b9756SMustafa Ismail 
3775146b9756SMustafa Ismail 	return 0;
3776146b9756SMustafa Ismail error:
3777146b9756SMustafa Ismail 	irdma_free_lsmm_rsrc(iwqp);
3778146b9756SMustafa Ismail 	irdma_rem_ref_cm_node(cm_node);
3779146b9756SMustafa Ismail 
3780146b9756SMustafa Ismail 	return ret;
3781146b9756SMustafa Ismail }
3782146b9756SMustafa Ismail 
3783146b9756SMustafa Ismail /**
3784146b9756SMustafa Ismail  * irdma_reject - registered call for connection to be rejected
3785146b9756SMustafa Ismail  * @cm_id: cm information for passive connection
3786146b9756SMustafa Ismail  * @pdata: private data to be sent
3787146b9756SMustafa Ismail  * @pdata_len: private data length
3788146b9756SMustafa Ismail  */
irdma_reject(struct iw_cm_id * cm_id,const void * pdata,u8 pdata_len)3789146b9756SMustafa Ismail int irdma_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
3790146b9756SMustafa Ismail {
3791146b9756SMustafa Ismail 	struct irdma_device *iwdev;
3792146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
3793146b9756SMustafa Ismail 
3794146b9756SMustafa Ismail 	cm_node = cm_id->provider_data;
3795146b9756SMustafa Ismail 	cm_node->pdata.size = pdata_len;
3796146b9756SMustafa Ismail 
3797146b9756SMustafa Ismail 	trace_irdma_reject(cm_node, 0, NULL);
3798146b9756SMustafa Ismail 
3799146b9756SMustafa Ismail 	iwdev = to_iwdev(cm_id->device);
3800146b9756SMustafa Ismail 	if (!iwdev)
3801146b9756SMustafa Ismail 		return -EINVAL;
3802146b9756SMustafa Ismail 
3803146b9756SMustafa Ismail 	cm_node->cm_core->stats_rejects++;
3804146b9756SMustafa Ismail 
3805146b9756SMustafa Ismail 	if (pdata_len + sizeof(struct ietf_mpa_v2) > IRDMA_MAX_CM_BUF)
3806146b9756SMustafa Ismail 		return -EINVAL;
3807146b9756SMustafa Ismail 
3808146b9756SMustafa Ismail 	return irdma_cm_reject(cm_node, pdata, pdata_len);
3809146b9756SMustafa Ismail }
3810146b9756SMustafa Ismail 
3811146b9756SMustafa Ismail /**
3812146b9756SMustafa Ismail  * irdma_connect - registered call for connection to be established
3813146b9756SMustafa Ismail  * @cm_id: cm information for passive connection
3814146b9756SMustafa Ismail  * @conn_param: Information about the connection
3815146b9756SMustafa Ismail  */
irdma_connect(struct iw_cm_id * cm_id,struct iw_cm_conn_param * conn_param)3816146b9756SMustafa Ismail int irdma_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
3817146b9756SMustafa Ismail {
3818146b9756SMustafa Ismail 	struct ib_qp *ibqp;
3819146b9756SMustafa Ismail 	struct irdma_qp *iwqp;
3820146b9756SMustafa Ismail 	struct irdma_device *iwdev;
3821146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
3822146b9756SMustafa Ismail 	struct irdma_cm_info cm_info;
3823146b9756SMustafa Ismail 	struct sockaddr_in *laddr;
3824146b9756SMustafa Ismail 	struct sockaddr_in *raddr;
3825146b9756SMustafa Ismail 	struct sockaddr_in6 *laddr6;
3826146b9756SMustafa Ismail 	struct sockaddr_in6 *raddr6;
3827146b9756SMustafa Ismail 	int ret = 0;
3828146b9756SMustafa Ismail 
3829146b9756SMustafa Ismail 	ibqp = irdma_get_qp(cm_id->device, conn_param->qpn);
3830146b9756SMustafa Ismail 	if (!ibqp)
3831146b9756SMustafa Ismail 		return -EINVAL;
3832146b9756SMustafa Ismail 	iwqp = to_iwqp(ibqp);
3833146b9756SMustafa Ismail 	if (!iwqp)
3834146b9756SMustafa Ismail 		return -EINVAL;
3835146b9756SMustafa Ismail 	iwdev = iwqp->iwdev;
3836146b9756SMustafa Ismail 	if (!iwdev)
3837146b9756SMustafa Ismail 		return -EINVAL;
3838146b9756SMustafa Ismail 
3839146b9756SMustafa Ismail 	laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
3840146b9756SMustafa Ismail 	raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
3841146b9756SMustafa Ismail 	laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
3842146b9756SMustafa Ismail 	raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;
3843146b9756SMustafa Ismail 
3844146b9756SMustafa Ismail 	if (!(laddr->sin_port) || !(raddr->sin_port))
3845146b9756SMustafa Ismail 		return -EINVAL;
3846146b9756SMustafa Ismail 
3847146b9756SMustafa Ismail 	iwqp->active_conn = 1;
3848146b9756SMustafa Ismail 	iwqp->cm_id = NULL;
3849146b9756SMustafa Ismail 	cm_id->provider_data = iwqp;
3850146b9756SMustafa Ismail 
3851146b9756SMustafa Ismail 	/* set up the connection params for the node */
3852146b9756SMustafa Ismail 	if (cm_id->remote_addr.ss_family == AF_INET) {
3853146b9756SMustafa Ismail 		if (iwdev->vsi.mtu < IRDMA_MIN_MTU_IPV4)
3854146b9756SMustafa Ismail 			return -EINVAL;
3855146b9756SMustafa Ismail 
3856146b9756SMustafa Ismail 		cm_info.ipv4 = true;
3857146b9756SMustafa Ismail 		memset(cm_info.loc_addr, 0, sizeof(cm_info.loc_addr));
3858146b9756SMustafa Ismail 		memset(cm_info.rem_addr, 0, sizeof(cm_info.rem_addr));
3859146b9756SMustafa Ismail 		cm_info.loc_addr[0] = ntohl(laddr->sin_addr.s_addr);
3860146b9756SMustafa Ismail 		cm_info.rem_addr[0] = ntohl(raddr->sin_addr.s_addr);
3861146b9756SMustafa Ismail 		cm_info.loc_port = ntohs(laddr->sin_port);
3862146b9756SMustafa Ismail 		cm_info.rem_port = ntohs(raddr->sin_port);
3863146b9756SMustafa Ismail 		cm_info.vlan_id = irdma_get_vlan_ipv4(cm_info.loc_addr);
3864146b9756SMustafa Ismail 	} else {
3865146b9756SMustafa Ismail 		if (iwdev->vsi.mtu < IRDMA_MIN_MTU_IPV6)
3866146b9756SMustafa Ismail 			return -EINVAL;
3867146b9756SMustafa Ismail 
3868146b9756SMustafa Ismail 		cm_info.ipv4 = false;
3869146b9756SMustafa Ismail 		irdma_copy_ip_ntohl(cm_info.loc_addr,
3870146b9756SMustafa Ismail 				    laddr6->sin6_addr.in6_u.u6_addr32);
3871146b9756SMustafa Ismail 		irdma_copy_ip_ntohl(cm_info.rem_addr,
3872146b9756SMustafa Ismail 				    raddr6->sin6_addr.in6_u.u6_addr32);
3873146b9756SMustafa Ismail 		cm_info.loc_port = ntohs(laddr6->sin6_port);
3874146b9756SMustafa Ismail 		cm_info.rem_port = ntohs(raddr6->sin6_port);
3875693e1cdeSMustafa Ismail 		irdma_get_vlan_mac_ipv6(cm_info.loc_addr, &cm_info.vlan_id,
3876146b9756SMustafa Ismail 					NULL);
3877146b9756SMustafa Ismail 	}
3878146b9756SMustafa Ismail 	cm_info.cm_id = cm_id;
3879146b9756SMustafa Ismail 	cm_info.qh_qpid = iwdev->vsi.ilq->qp_id;
3880146b9756SMustafa Ismail 	cm_info.tos = cm_id->tos;
3881f877f22aSMustafa Ismail 	if (iwdev->vsi.dscp_mode) {
38824b860c91SMustafa Ismail 		cm_info.user_pri =
38834b860c91SMustafa Ismail 			iwqp->sc_qp.vsi->dscp_map[irdma_tos2dscp(cm_info.tos)];
3884f877f22aSMustafa Ismail 	} else {
3885146b9756SMustafa Ismail 		cm_info.user_pri = rt_tos2priority(cm_id->tos);
3886f877f22aSMustafa Ismail 		cm_info.user_pri = irdma_iw_get_vlan_prio(cm_info.loc_addr,
3887f877f22aSMustafa Ismail 							  cm_info.user_pri,
3888f877f22aSMustafa Ismail 							  cm_info.ipv4);
3889f877f22aSMustafa Ismail 	}
3890146b9756SMustafa Ismail 
3891146b9756SMustafa Ismail 	if (iwqp->sc_qp.dev->ws_add(iwqp->sc_qp.vsi, cm_info.user_pri))
3892146b9756SMustafa Ismail 		return -ENOMEM;
3893146b9756SMustafa Ismail 	iwqp->sc_qp.user_pri = cm_info.user_pri;
3894146b9756SMustafa Ismail 	irdma_qp_add_qos(&iwqp->sc_qp);
3895146b9756SMustafa Ismail 	ibdev_dbg(&iwdev->ibdev, "DCB: TOS:[%d] UP:[%d]\n", cm_id->tos,
3896146b9756SMustafa Ismail 		  cm_info.user_pri);
3897146b9756SMustafa Ismail 
3898146b9756SMustafa Ismail 	trace_irdma_dcb_tos(iwdev, cm_id->tos, cm_info.user_pri);
3899146b9756SMustafa Ismail 
3900146b9756SMustafa Ismail 	ret = irdma_create_cm_node(&iwdev->cm_core, iwdev, conn_param, &cm_info,
3901146b9756SMustafa Ismail 				   &cm_node);
3902146b9756SMustafa Ismail 	if (ret)
3903146b9756SMustafa Ismail 		return ret;
3904146b9756SMustafa Ismail 	ret = cm_node->cm_core->cm_create_ah(cm_node, true);
3905146b9756SMustafa Ismail 	if (ret)
3906146b9756SMustafa Ismail 		goto err;
3907146b9756SMustafa Ismail 	if (irdma_manage_qhash(iwdev, &cm_info,
3908146b9756SMustafa Ismail 			       IRDMA_QHASH_TYPE_TCP_ESTABLISHED,
3909146b9756SMustafa Ismail 			       IRDMA_QHASH_MANAGE_TYPE_ADD, NULL, true)) {
3910146b9756SMustafa Ismail 		ret = -EINVAL;
3911146b9756SMustafa Ismail 		goto err;
3912146b9756SMustafa Ismail 	}
3913146b9756SMustafa Ismail 	cm_node->qhash_set = true;
3914146b9756SMustafa Ismail 
3915146b9756SMustafa Ismail 	cm_node->apbvt_entry = irdma_add_apbvt(iwdev, cm_info.loc_port);
3916146b9756SMustafa Ismail 	if (!cm_node->apbvt_entry) {
3917146b9756SMustafa Ismail 		ret = -EINVAL;
3918146b9756SMustafa Ismail 		goto err;
3919146b9756SMustafa Ismail 	}
3920146b9756SMustafa Ismail 
3921146b9756SMustafa Ismail 	cm_node->apbvt_set = true;
3922146b9756SMustafa Ismail 	iwqp->cm_node = cm_node;
3923146b9756SMustafa Ismail 	cm_node->iwqp = iwqp;
3924146b9756SMustafa Ismail 	iwqp->cm_id = cm_id;
3925146b9756SMustafa Ismail 	irdma_qp_add_ref(&iwqp->ibqp);
3926146b9756SMustafa Ismail 	cm_id->add_ref(cm_id);
3927146b9756SMustafa Ismail 
3928146b9756SMustafa Ismail 	if (cm_node->state != IRDMA_CM_STATE_OFFLOADED) {
3929146b9756SMustafa Ismail 		cm_node->state = IRDMA_CM_STATE_SYN_SENT;
3930146b9756SMustafa Ismail 		ret = irdma_send_syn(cm_node, 0);
3931146b9756SMustafa Ismail 		if (ret)
3932146b9756SMustafa Ismail 			goto err;
3933146b9756SMustafa Ismail 	}
3934146b9756SMustafa Ismail 
3935146b9756SMustafa Ismail 	ibdev_dbg(&iwdev->ibdev,
3936146b9756SMustafa Ismail 		  "CM: rem_port=0x%04x, loc_port=0x%04x rem_addr=%pI4 loc_addr=%pI4 cm_node=%p cm_id=%p qp_id = %d\n\n",
3937146b9756SMustafa Ismail 		  cm_node->rem_port, cm_node->loc_port, cm_node->rem_addr,
3938146b9756SMustafa Ismail 		  cm_node->loc_addr, cm_node, cm_id, ibqp->qp_num);
3939146b9756SMustafa Ismail 
3940146b9756SMustafa Ismail 	trace_irdma_connect(cm_node, 0, NULL);
3941146b9756SMustafa Ismail 
3942146b9756SMustafa Ismail 	return 0;
3943146b9756SMustafa Ismail 
3944146b9756SMustafa Ismail err:
3945146b9756SMustafa Ismail 	if (cm_info.ipv4)
3946146b9756SMustafa Ismail 		ibdev_dbg(&iwdev->ibdev,
3947146b9756SMustafa Ismail 			  "CM: connect() FAILED: dest addr=%pI4",
3948146b9756SMustafa Ismail 			  cm_info.rem_addr);
3949146b9756SMustafa Ismail 	else
3950146b9756SMustafa Ismail 		ibdev_dbg(&iwdev->ibdev,
3951146b9756SMustafa Ismail 			  "CM: connect() FAILED: dest addr=%pI6",
3952146b9756SMustafa Ismail 			  cm_info.rem_addr);
3953146b9756SMustafa Ismail 	irdma_rem_ref_cm_node(cm_node);
3954146b9756SMustafa Ismail 	iwdev->cm_core.stats_connect_errs++;
3955146b9756SMustafa Ismail 
3956146b9756SMustafa Ismail 	return ret;
3957146b9756SMustafa Ismail }
3958146b9756SMustafa Ismail 
3959146b9756SMustafa Ismail /**
3960146b9756SMustafa Ismail  * irdma_create_listen - registered call creating listener
3961146b9756SMustafa Ismail  * @cm_id: cm information for passive connection
3962146b9756SMustafa Ismail  * @backlog: to max accept pending count
3963146b9756SMustafa Ismail  */
irdma_create_listen(struct iw_cm_id * cm_id,int backlog)3964146b9756SMustafa Ismail int irdma_create_listen(struct iw_cm_id *cm_id, int backlog)
3965146b9756SMustafa Ismail {
3966146b9756SMustafa Ismail 	struct irdma_device *iwdev;
3967146b9756SMustafa Ismail 	struct irdma_cm_listener *cm_listen_node;
3968146b9756SMustafa Ismail 	struct irdma_cm_info cm_info = {};
3969146b9756SMustafa Ismail 	struct sockaddr_in *laddr;
3970146b9756SMustafa Ismail 	struct sockaddr_in6 *laddr6;
3971146b9756SMustafa Ismail 	bool wildcard = false;
39722c4b14eaSShiraz Saleem 	int err;
3973146b9756SMustafa Ismail 
3974146b9756SMustafa Ismail 	iwdev = to_iwdev(cm_id->device);
3975146b9756SMustafa Ismail 	if (!iwdev)
3976146b9756SMustafa Ismail 		return -EINVAL;
3977146b9756SMustafa Ismail 
3978146b9756SMustafa Ismail 	laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
3979146b9756SMustafa Ismail 	laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
3980146b9756SMustafa Ismail 	cm_info.qh_qpid = iwdev->vsi.ilq->qp_id;
3981146b9756SMustafa Ismail 
3982146b9756SMustafa Ismail 	if (laddr->sin_family == AF_INET) {
3983146b9756SMustafa Ismail 		if (iwdev->vsi.mtu < IRDMA_MIN_MTU_IPV4)
3984146b9756SMustafa Ismail 			return -EINVAL;
3985146b9756SMustafa Ismail 
3986146b9756SMustafa Ismail 		cm_info.ipv4 = true;
3987146b9756SMustafa Ismail 		cm_info.loc_addr[0] = ntohl(laddr->sin_addr.s_addr);
3988146b9756SMustafa Ismail 		cm_info.loc_port = ntohs(laddr->sin_port);
3989146b9756SMustafa Ismail 
3990146b9756SMustafa Ismail 		if (laddr->sin_addr.s_addr != htonl(INADDR_ANY)) {
3991146b9756SMustafa Ismail 			cm_info.vlan_id = irdma_get_vlan_ipv4(cm_info.loc_addr);
3992146b9756SMustafa Ismail 		} else {
3993146b9756SMustafa Ismail 			cm_info.vlan_id = 0xFFFF;
3994146b9756SMustafa Ismail 			wildcard = true;
3995146b9756SMustafa Ismail 		}
3996146b9756SMustafa Ismail 	} else {
3997146b9756SMustafa Ismail 		if (iwdev->vsi.mtu < IRDMA_MIN_MTU_IPV6)
3998146b9756SMustafa Ismail 			return -EINVAL;
3999146b9756SMustafa Ismail 
4000146b9756SMustafa Ismail 		cm_info.ipv4 = false;
4001146b9756SMustafa Ismail 		irdma_copy_ip_ntohl(cm_info.loc_addr,
4002146b9756SMustafa Ismail 				    laddr6->sin6_addr.in6_u.u6_addr32);
4003146b9756SMustafa Ismail 		cm_info.loc_port = ntohs(laddr6->sin6_port);
4004146b9756SMustafa Ismail 		if (ipv6_addr_type(&laddr6->sin6_addr) != IPV6_ADDR_ANY) {
4005693e1cdeSMustafa Ismail 			irdma_get_vlan_mac_ipv6(cm_info.loc_addr,
4006146b9756SMustafa Ismail 						&cm_info.vlan_id, NULL);
4007146b9756SMustafa Ismail 		} else {
4008146b9756SMustafa Ismail 			cm_info.vlan_id = 0xFFFF;
4009146b9756SMustafa Ismail 			wildcard = true;
4010146b9756SMustafa Ismail 		}
4011146b9756SMustafa Ismail 	}
4012146b9756SMustafa Ismail 
401383483055SMustafa Ismail 	if (cm_info.vlan_id >= VLAN_N_VID && iwdev->dcb_vlan_mode)
4014146b9756SMustafa Ismail 		cm_info.vlan_id = 0;
4015146b9756SMustafa Ismail 	cm_info.backlog = backlog;
4016146b9756SMustafa Ismail 	cm_info.cm_id = cm_id;
4017146b9756SMustafa Ismail 
4018146b9756SMustafa Ismail 	trace_irdma_create_listen(iwdev, &cm_info);
4019146b9756SMustafa Ismail 
4020146b9756SMustafa Ismail 	cm_listen_node = irdma_make_listen_node(&iwdev->cm_core, iwdev,
4021146b9756SMustafa Ismail 						&cm_info);
4022146b9756SMustafa Ismail 	if (!cm_listen_node) {
4023146b9756SMustafa Ismail 		ibdev_dbg(&iwdev->ibdev,
4024146b9756SMustafa Ismail 			  "CM: cm_listen_node == NULL\n");
4025146b9756SMustafa Ismail 		return -ENOMEM;
4026146b9756SMustafa Ismail 	}
4027146b9756SMustafa Ismail 
4028146b9756SMustafa Ismail 	cm_id->provider_data = cm_listen_node;
4029146b9756SMustafa Ismail 
4030146b9756SMustafa Ismail 	cm_listen_node->tos = cm_id->tos;
40314b860c91SMustafa Ismail 	if (iwdev->vsi.dscp_mode)
40324b860c91SMustafa Ismail 		cm_listen_node->user_pri =
40334b860c91SMustafa Ismail 		iwdev->vsi.dscp_map[irdma_tos2dscp(cm_id->tos)];
40344b860c91SMustafa Ismail 	else
4035146b9756SMustafa Ismail 		cm_listen_node->user_pri = rt_tos2priority(cm_id->tos);
4036146b9756SMustafa Ismail 	cm_info.user_pri = cm_listen_node->user_pri;
4037146b9756SMustafa Ismail 	if (!cm_listen_node->reused_node) {
4038146b9756SMustafa Ismail 		if (wildcard) {
4039146b9756SMustafa Ismail 			err = irdma_add_mqh(iwdev, &cm_info, cm_listen_node);
4040146b9756SMustafa Ismail 			if (err)
4041146b9756SMustafa Ismail 				goto error;
4042146b9756SMustafa Ismail 		} else {
4043f877f22aSMustafa Ismail 			if (!iwdev->vsi.dscp_mode)
4044f877f22aSMustafa Ismail 				cm_listen_node->user_pri =
4045f877f22aSMustafa Ismail 				irdma_iw_get_vlan_prio(cm_info.loc_addr,
4046f877f22aSMustafa Ismail 						       cm_info.user_pri,
4047f877f22aSMustafa Ismail 						       cm_info.ipv4);
4048f877f22aSMustafa Ismail 			cm_info.user_pri = cm_listen_node->user_pri;
4049146b9756SMustafa Ismail 			err = irdma_manage_qhash(iwdev, &cm_info,
4050146b9756SMustafa Ismail 						 IRDMA_QHASH_TYPE_TCP_SYN,
4051146b9756SMustafa Ismail 						 IRDMA_QHASH_MANAGE_TYPE_ADD,
4052146b9756SMustafa Ismail 						 NULL, true);
4053146b9756SMustafa Ismail 			if (err)
4054146b9756SMustafa Ismail 				goto error;
4055146b9756SMustafa Ismail 
4056146b9756SMustafa Ismail 			cm_listen_node->qhash_set = true;
4057146b9756SMustafa Ismail 		}
4058146b9756SMustafa Ismail 
4059146b9756SMustafa Ismail 		cm_listen_node->apbvt_entry = irdma_add_apbvt(iwdev,
4060146b9756SMustafa Ismail 							      cm_info.loc_port);
4061146b9756SMustafa Ismail 		if (!cm_listen_node->apbvt_entry)
4062146b9756SMustafa Ismail 			goto error;
4063146b9756SMustafa Ismail 	}
4064146b9756SMustafa Ismail 	cm_id->add_ref(cm_id);
4065146b9756SMustafa Ismail 	cm_listen_node->cm_core->stats_listen_created++;
4066146b9756SMustafa Ismail 	ibdev_dbg(&iwdev->ibdev,
4067146b9756SMustafa Ismail 		  "CM: loc_port=0x%04x loc_addr=%pI4 cm_listen_node=%p cm_id=%p qhash_set=%d vlan_id=%d\n",
4068146b9756SMustafa Ismail 		  cm_listen_node->loc_port, cm_listen_node->loc_addr,
4069146b9756SMustafa Ismail 		  cm_listen_node, cm_listen_node->cm_id,
4070146b9756SMustafa Ismail 		  cm_listen_node->qhash_set, cm_listen_node->vlan_id);
4071146b9756SMustafa Ismail 
4072146b9756SMustafa Ismail 	return 0;
4073146b9756SMustafa Ismail 
4074146b9756SMustafa Ismail error:
4075146b9756SMustafa Ismail 
4076146b9756SMustafa Ismail 	irdma_cm_del_listen(&iwdev->cm_core, cm_listen_node, false);
4077146b9756SMustafa Ismail 
4078146b9756SMustafa Ismail 	return -EINVAL;
4079146b9756SMustafa Ismail }
4080146b9756SMustafa Ismail 
4081146b9756SMustafa Ismail /**
4082146b9756SMustafa Ismail  * irdma_destroy_listen - registered call to destroy listener
4083146b9756SMustafa Ismail  * @cm_id: cm information for passive connection
4084146b9756SMustafa Ismail  */
irdma_destroy_listen(struct iw_cm_id * cm_id)4085146b9756SMustafa Ismail int irdma_destroy_listen(struct iw_cm_id *cm_id)
4086146b9756SMustafa Ismail {
4087146b9756SMustafa Ismail 	struct irdma_device *iwdev;
4088146b9756SMustafa Ismail 
4089146b9756SMustafa Ismail 	iwdev = to_iwdev(cm_id->device);
4090146b9756SMustafa Ismail 	if (cm_id->provider_data)
4091146b9756SMustafa Ismail 		irdma_cm_del_listen(&iwdev->cm_core, cm_id->provider_data,
4092146b9756SMustafa Ismail 				    true);
4093146b9756SMustafa Ismail 	else
4094146b9756SMustafa Ismail 		ibdev_dbg(&iwdev->ibdev,
4095146b9756SMustafa Ismail 			  "CM: cm_id->provider_data was NULL\n");
4096146b9756SMustafa Ismail 
4097146b9756SMustafa Ismail 	cm_id->rem_ref(cm_id);
4098146b9756SMustafa Ismail 
4099146b9756SMustafa Ismail 	return 0;
4100146b9756SMustafa Ismail }
4101146b9756SMustafa Ismail 
4102146b9756SMustafa Ismail /**
4103146b9756SMustafa Ismail  * irdma_teardown_list_prep - add conn nodes slated for tear down to list
4104146b9756SMustafa Ismail  * @cm_core: cm's core
4105146b9756SMustafa Ismail  * @teardown_list: a list to which cm_node will be selected
4106146b9756SMustafa Ismail  * @ipaddr: pointer to ip address
4107146b9756SMustafa Ismail  * @nfo: pointer to cm_info structure instance
4108146b9756SMustafa Ismail  * @disconnect_all: flag indicating disconnect all QPs
4109146b9756SMustafa Ismail  */
irdma_teardown_list_prep(struct irdma_cm_core * cm_core,struct list_head * teardown_list,u32 * ipaddr,struct irdma_cm_info * nfo,bool disconnect_all)4110146b9756SMustafa Ismail static void irdma_teardown_list_prep(struct irdma_cm_core *cm_core,
4111146b9756SMustafa Ismail 				     struct list_head *teardown_list,
4112146b9756SMustafa Ismail 				     u32 *ipaddr,
4113146b9756SMustafa Ismail 				     struct irdma_cm_info *nfo,
4114146b9756SMustafa Ismail 				     bool disconnect_all)
4115146b9756SMustafa Ismail {
4116146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
4117146b9756SMustafa Ismail 	int bkt;
4118146b9756SMustafa Ismail 
4119146b9756SMustafa Ismail 	hash_for_each_rcu(cm_core->cm_hash_tbl, bkt, cm_node, list) {
4120146b9756SMustafa Ismail 		if ((disconnect_all ||
4121146b9756SMustafa Ismail 		     (nfo->vlan_id == cm_node->vlan_id &&
4122146b9756SMustafa Ismail 		      !memcmp(cm_node->loc_addr, ipaddr, nfo->ipv4 ? 4 : 16))) &&
4123146b9756SMustafa Ismail 		    refcount_inc_not_zero(&cm_node->refcnt))
4124146b9756SMustafa Ismail 			list_add(&cm_node->teardown_entry, teardown_list);
4125146b9756SMustafa Ismail 	}
4126146b9756SMustafa Ismail }
4127146b9756SMustafa Ismail 
4128146b9756SMustafa Ismail /**
4129146b9756SMustafa Ismail  * irdma_cm_event_connected - handle connected active node
4130146b9756SMustafa Ismail  * @event: the info for cm_node of connection
4131146b9756SMustafa Ismail  */
irdma_cm_event_connected(struct irdma_cm_event * event)4132146b9756SMustafa Ismail static void irdma_cm_event_connected(struct irdma_cm_event *event)
4133146b9756SMustafa Ismail {
4134146b9756SMustafa Ismail 	struct irdma_qp *iwqp;
4135146b9756SMustafa Ismail 	struct irdma_device *iwdev;
4136146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
4137146b9756SMustafa Ismail 	struct irdma_sc_dev *dev;
4138146b9756SMustafa Ismail 	struct ib_qp_attr attr = {};
4139146b9756SMustafa Ismail 	struct iw_cm_id *cm_id;
4140146b9756SMustafa Ismail 	int status;
4141146b9756SMustafa Ismail 	bool read0;
4142146b9756SMustafa Ismail 	int wait_ret = 0;
4143146b9756SMustafa Ismail 
4144146b9756SMustafa Ismail 	cm_node = event->cm_node;
4145146b9756SMustafa Ismail 	cm_id = cm_node->cm_id;
4146146b9756SMustafa Ismail 	iwqp = cm_id->provider_data;
4147146b9756SMustafa Ismail 	iwdev = iwqp->iwdev;
4148146b9756SMustafa Ismail 	dev = &iwdev->rf->sc_dev;
4149146b9756SMustafa Ismail 	if (iwqp->sc_qp.qp_uk.destroy_pending) {
4150146b9756SMustafa Ismail 		status = -ETIMEDOUT;
4151146b9756SMustafa Ismail 		goto error;
4152146b9756SMustafa Ismail 	}
4153146b9756SMustafa Ismail 
4154146b9756SMustafa Ismail 	irdma_cm_init_tsa_conn(iwqp, cm_node);
4155146b9756SMustafa Ismail 	read0 = (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO);
4156146b9756SMustafa Ismail 	if (iwqp->page)
41577364e74dSIra Weiny 		iwqp->sc_qp.qp_uk.sq_base = kmap_local_page(iwqp->page);
4158146b9756SMustafa Ismail 	irdma_sc_send_rtt(&iwqp->sc_qp, read0);
4159146b9756SMustafa Ismail 	if (iwqp->page)
41607364e74dSIra Weiny 		kunmap_local(iwqp->sc_qp.qp_uk.sq_base);
4161146b9756SMustafa Ismail 
4162146b9756SMustafa Ismail 	attr.qp_state = IB_QPS_RTS;
4163146b9756SMustafa Ismail 	cm_node->qhash_set = false;
4164146b9756SMustafa Ismail 	irdma_modify_qp(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
4165146b9756SMustafa Ismail 	if (dev->hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_RTS_AE) {
4166146b9756SMustafa Ismail 		wait_ret = wait_event_interruptible_timeout(iwqp->waitq,
4167146b9756SMustafa Ismail 							    iwqp->rts_ae_rcvd,
4168146b9756SMustafa Ismail 							    IRDMA_MAX_TIMEOUT);
4169146b9756SMustafa Ismail 		if (!wait_ret)
4170146b9756SMustafa Ismail 			ibdev_dbg(&iwdev->ibdev,
4171146b9756SMustafa Ismail 				  "CM: Slow Connection: cm_node=%p, loc_port=%d, rem_port=%d, cm_id=%p\n",
4172146b9756SMustafa Ismail 				  cm_node, cm_node->loc_port,
4173146b9756SMustafa Ismail 				  cm_node->rem_port, cm_node->cm_id);
4174146b9756SMustafa Ismail 	}
4175146b9756SMustafa Ismail 
4176146b9756SMustafa Ismail 	irdma_send_cm_event(cm_node, cm_id, IW_CM_EVENT_CONNECT_REPLY, 0);
4177146b9756SMustafa Ismail 	cm_node->accelerated = true;
4178146b9756SMustafa Ismail 	complete(&cm_node->establish_comp);
4179146b9756SMustafa Ismail 	cm_node->cm_core->cm_free_ah(cm_node);
4180146b9756SMustafa Ismail 	return;
4181146b9756SMustafa Ismail 
4182146b9756SMustafa Ismail error:
4183146b9756SMustafa Ismail 	iwqp->cm_id = NULL;
4184146b9756SMustafa Ismail 	cm_id->provider_data = NULL;
4185146b9756SMustafa Ismail 	irdma_send_cm_event(event->cm_node, cm_id, IW_CM_EVENT_CONNECT_REPLY,
4186146b9756SMustafa Ismail 			    status);
4187146b9756SMustafa Ismail 	irdma_rem_ref_cm_node(event->cm_node);
4188146b9756SMustafa Ismail }
4189146b9756SMustafa Ismail 
4190146b9756SMustafa Ismail /**
4191146b9756SMustafa Ismail  * irdma_cm_event_reset - handle reset
4192146b9756SMustafa Ismail  * @event: the info for cm_node of connection
4193146b9756SMustafa Ismail  */
irdma_cm_event_reset(struct irdma_cm_event * event)4194146b9756SMustafa Ismail static void irdma_cm_event_reset(struct irdma_cm_event *event)
4195146b9756SMustafa Ismail {
4196146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node = event->cm_node;
4197146b9756SMustafa Ismail 	struct iw_cm_id *cm_id = cm_node->cm_id;
4198146b9756SMustafa Ismail 	struct irdma_qp *iwqp;
4199146b9756SMustafa Ismail 
4200146b9756SMustafa Ismail 	if (!cm_id)
4201146b9756SMustafa Ismail 		return;
4202146b9756SMustafa Ismail 
4203146b9756SMustafa Ismail 	iwqp = cm_id->provider_data;
4204146b9756SMustafa Ismail 	if (!iwqp)
4205146b9756SMustafa Ismail 		return;
4206146b9756SMustafa Ismail 
4207146b9756SMustafa Ismail 	ibdev_dbg(&cm_node->iwdev->ibdev,
4208146b9756SMustafa Ismail 		  "CM: reset event %p - cm_id = %p\n", event->cm_node, cm_id);
4209146b9756SMustafa Ismail 	iwqp->cm_id = NULL;
4210146b9756SMustafa Ismail 
4211146b9756SMustafa Ismail 	irdma_send_cm_event(cm_node, cm_node->cm_id, IW_CM_EVENT_DISCONNECT,
4212146b9756SMustafa Ismail 			    -ECONNRESET);
4213146b9756SMustafa Ismail 	irdma_send_cm_event(cm_node, cm_node->cm_id, IW_CM_EVENT_CLOSE, 0);
4214146b9756SMustafa Ismail }
4215146b9756SMustafa Ismail 
4216146b9756SMustafa Ismail /**
4217146b9756SMustafa Ismail  * irdma_cm_event_handler - send event to cm upper layer
4218146b9756SMustafa Ismail  * @work: pointer of cm event info.
4219146b9756SMustafa Ismail  */
irdma_cm_event_handler(struct work_struct * work)4220146b9756SMustafa Ismail static void irdma_cm_event_handler(struct work_struct *work)
4221146b9756SMustafa Ismail {
4222146b9756SMustafa Ismail 	struct irdma_cm_event *event = container_of(work, struct irdma_cm_event, event_work);
4223146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
4224146b9756SMustafa Ismail 
4225146b9756SMustafa Ismail 	if (!event || !event->cm_node || !event->cm_node->cm_core)
4226146b9756SMustafa Ismail 		return;
4227146b9756SMustafa Ismail 
4228146b9756SMustafa Ismail 	cm_node = event->cm_node;
4229146b9756SMustafa Ismail 	trace_irdma_cm_event_handler(cm_node, event->type, NULL);
4230146b9756SMustafa Ismail 
4231146b9756SMustafa Ismail 	switch (event->type) {
4232146b9756SMustafa Ismail 	case IRDMA_CM_EVENT_MPA_REQ:
4233146b9756SMustafa Ismail 		irdma_send_cm_event(cm_node, cm_node->cm_id,
4234146b9756SMustafa Ismail 				    IW_CM_EVENT_CONNECT_REQUEST, 0);
4235146b9756SMustafa Ismail 		break;
4236146b9756SMustafa Ismail 	case IRDMA_CM_EVENT_RESET:
4237146b9756SMustafa Ismail 		irdma_cm_event_reset(event);
4238146b9756SMustafa Ismail 		break;
4239146b9756SMustafa Ismail 	case IRDMA_CM_EVENT_CONNECTED:
4240146b9756SMustafa Ismail 		if (!event->cm_node->cm_id ||
4241146b9756SMustafa Ismail 		    event->cm_node->state != IRDMA_CM_STATE_OFFLOADED)
4242146b9756SMustafa Ismail 			break;
4243146b9756SMustafa Ismail 		irdma_cm_event_connected(event);
4244146b9756SMustafa Ismail 		break;
4245146b9756SMustafa Ismail 	case IRDMA_CM_EVENT_MPA_REJECT:
4246146b9756SMustafa Ismail 		if (!event->cm_node->cm_id ||
4247146b9756SMustafa Ismail 		    cm_node->state == IRDMA_CM_STATE_OFFLOADED)
4248146b9756SMustafa Ismail 			break;
4249146b9756SMustafa Ismail 		irdma_send_cm_event(cm_node, cm_node->cm_id,
4250146b9756SMustafa Ismail 				    IW_CM_EVENT_CONNECT_REPLY, -ECONNREFUSED);
4251146b9756SMustafa Ismail 		break;
4252146b9756SMustafa Ismail 	case IRDMA_CM_EVENT_ABORTED:
4253146b9756SMustafa Ismail 		if (!event->cm_node->cm_id ||
4254146b9756SMustafa Ismail 		    event->cm_node->state == IRDMA_CM_STATE_OFFLOADED)
4255146b9756SMustafa Ismail 			break;
4256146b9756SMustafa Ismail 		irdma_event_connect_error(event);
4257146b9756SMustafa Ismail 		break;
4258146b9756SMustafa Ismail 	default:
4259146b9756SMustafa Ismail 		ibdev_dbg(&cm_node->iwdev->ibdev,
4260146b9756SMustafa Ismail 			  "CM: bad event type = %d\n", event->type);
4261146b9756SMustafa Ismail 		break;
4262146b9756SMustafa Ismail 	}
4263146b9756SMustafa Ismail 
4264146b9756SMustafa Ismail 	irdma_rem_ref_cm_node(event->cm_node);
4265146b9756SMustafa Ismail 	kfree(event);
4266146b9756SMustafa Ismail }
4267146b9756SMustafa Ismail 
4268146b9756SMustafa Ismail /**
4269146b9756SMustafa Ismail  * irdma_cm_post_event - queue event request for worker thread
4270146b9756SMustafa Ismail  * @event: cm node's info for up event call
4271146b9756SMustafa Ismail  */
irdma_cm_post_event(struct irdma_cm_event * event)4272146b9756SMustafa Ismail static void irdma_cm_post_event(struct irdma_cm_event *event)
4273146b9756SMustafa Ismail {
4274146b9756SMustafa Ismail 	refcount_inc(&event->cm_node->refcnt);
4275146b9756SMustafa Ismail 	INIT_WORK(&event->event_work, irdma_cm_event_handler);
4276146b9756SMustafa Ismail 	queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
4277146b9756SMustafa Ismail }
4278146b9756SMustafa Ismail 
4279146b9756SMustafa Ismail /**
4280146b9756SMustafa Ismail  * irdma_cm_teardown_connections - teardown QPs
4281146b9756SMustafa Ismail  * @iwdev: device pointer
4282146b9756SMustafa Ismail  * @ipaddr: Pointer to IPv4 or IPv6 address
4283146b9756SMustafa Ismail  * @nfo: Connection info
4284146b9756SMustafa Ismail  * @disconnect_all: flag indicating disconnect all QPs
4285146b9756SMustafa Ismail  *
4286146b9756SMustafa Ismail  * teardown QPs where source or destination addr matches ip addr
4287146b9756SMustafa Ismail  */
irdma_cm_teardown_connections(struct irdma_device * iwdev,u32 * ipaddr,struct irdma_cm_info * nfo,bool disconnect_all)4288146b9756SMustafa Ismail void irdma_cm_teardown_connections(struct irdma_device *iwdev, u32 *ipaddr,
4289146b9756SMustafa Ismail 				   struct irdma_cm_info *nfo,
4290146b9756SMustafa Ismail 				   bool disconnect_all)
4291146b9756SMustafa Ismail {
4292146b9756SMustafa Ismail 	struct irdma_cm_core *cm_core = &iwdev->cm_core;
4293146b9756SMustafa Ismail 	struct list_head *list_core_temp;
4294146b9756SMustafa Ismail 	struct list_head *list_node;
4295146b9756SMustafa Ismail 	struct irdma_cm_node *cm_node;
4296146b9756SMustafa Ismail 	struct list_head teardown_list;
4297146b9756SMustafa Ismail 	struct ib_qp_attr attr;
4298146b9756SMustafa Ismail 
4299146b9756SMustafa Ismail 	INIT_LIST_HEAD(&teardown_list);
4300146b9756SMustafa Ismail 
4301146b9756SMustafa Ismail 	rcu_read_lock();
4302146b9756SMustafa Ismail 	irdma_teardown_list_prep(cm_core, &teardown_list, ipaddr, nfo, disconnect_all);
4303146b9756SMustafa Ismail 	rcu_read_unlock();
4304146b9756SMustafa Ismail 
4305146b9756SMustafa Ismail 	list_for_each_safe (list_node, list_core_temp, &teardown_list) {
4306146b9756SMustafa Ismail 		cm_node = container_of(list_node, struct irdma_cm_node,
4307146b9756SMustafa Ismail 				       teardown_entry);
4308146b9756SMustafa Ismail 		attr.qp_state = IB_QPS_ERR;
4309146b9756SMustafa Ismail 		irdma_modify_qp(&cm_node->iwqp->ibqp, &attr, IB_QP_STATE, NULL);
43105b1e985fSSindhu Devale 		if (iwdev->rf->reset)
4311146b9756SMustafa Ismail 			irdma_cm_disconn(cm_node->iwqp);
4312146b9756SMustafa Ismail 		irdma_rem_ref_cm_node(cm_node);
4313146b9756SMustafa Ismail 	}
4314146b9756SMustafa Ismail }
4315146b9756SMustafa Ismail 
4316146b9756SMustafa Ismail /**
4317146b9756SMustafa Ismail  * irdma_qhash_ctrl - enable/disable qhash for list
4318146b9756SMustafa Ismail  * @iwdev: device pointer
4319146b9756SMustafa Ismail  * @parent_listen_node: parent listen node
4320146b9756SMustafa Ismail  * @nfo: cm info node
4321146b9756SMustafa Ismail  * @ipaddr: Pointer to IPv4 or IPv6 address
4322146b9756SMustafa Ismail  * @ipv4: flag indicating IPv4 when true
4323146b9756SMustafa Ismail  * @ifup: flag indicating interface up when true
4324146b9756SMustafa Ismail  *
4325146b9756SMustafa Ismail  * Enables or disables the qhash for the node in the child
4326146b9756SMustafa Ismail  * listen list that matches ipaddr. If no matching IP was found
4327146b9756SMustafa Ismail  * it will allocate and add a new child listen node to the
4328146b9756SMustafa Ismail  * parent listen node. The listen_list_lock is assumed to be
4329146b9756SMustafa Ismail  * held when called.
4330146b9756SMustafa Ismail  */
irdma_qhash_ctrl(struct irdma_device * iwdev,struct irdma_cm_listener * parent_listen_node,struct irdma_cm_info * nfo,u32 * ipaddr,bool ipv4,bool ifup)4331146b9756SMustafa Ismail static void irdma_qhash_ctrl(struct irdma_device *iwdev,
4332146b9756SMustafa Ismail 			     struct irdma_cm_listener *parent_listen_node,
4333146b9756SMustafa Ismail 			     struct irdma_cm_info *nfo, u32 *ipaddr, bool ipv4,
4334146b9756SMustafa Ismail 			     bool ifup)
4335146b9756SMustafa Ismail {
4336146b9756SMustafa Ismail 	struct list_head *child_listen_list = &parent_listen_node->child_listen_list;
4337146b9756SMustafa Ismail 	struct irdma_cm_listener *child_listen_node;
4338146b9756SMustafa Ismail 	struct list_head *pos, *tpos;
4339146b9756SMustafa Ismail 	bool node_allocated = false;
4340146b9756SMustafa Ismail 	enum irdma_quad_hash_manage_type op = ifup ?
4341146b9756SMustafa Ismail 					      IRDMA_QHASH_MANAGE_TYPE_ADD :
4342146b9756SMustafa Ismail 					      IRDMA_QHASH_MANAGE_TYPE_DELETE;
43432c4b14eaSShiraz Saleem 	int err;
4344146b9756SMustafa Ismail 
4345146b9756SMustafa Ismail 	list_for_each_safe (pos, tpos, child_listen_list) {
4346146b9756SMustafa Ismail 		child_listen_node = list_entry(pos, struct irdma_cm_listener,
4347146b9756SMustafa Ismail 					       child_listen_list);
4348146b9756SMustafa Ismail 		if (!memcmp(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16))
4349146b9756SMustafa Ismail 			goto set_qhash;
4350146b9756SMustafa Ismail 	}
4351146b9756SMustafa Ismail 
4352146b9756SMustafa Ismail 	/* if not found then add a child listener if interface is going up */
4353146b9756SMustafa Ismail 	if (!ifup)
4354146b9756SMustafa Ismail 		return;
4355146b9756SMustafa Ismail 	child_listen_node = kmemdup(parent_listen_node,
4356146b9756SMustafa Ismail 				    sizeof(*child_listen_node), GFP_ATOMIC);
4357146b9756SMustafa Ismail 	if (!child_listen_node)
4358146b9756SMustafa Ismail 		return;
4359146b9756SMustafa Ismail 
4360146b9756SMustafa Ismail 	node_allocated = true;
4361146b9756SMustafa Ismail 	memcpy(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16);
4362146b9756SMustafa Ismail 
4363146b9756SMustafa Ismail set_qhash:
4364146b9756SMustafa Ismail 	memcpy(nfo->loc_addr, child_listen_node->loc_addr,
4365146b9756SMustafa Ismail 	       sizeof(nfo->loc_addr));
4366146b9756SMustafa Ismail 	nfo->vlan_id = child_listen_node->vlan_id;
4367146b9756SMustafa Ismail 	err = irdma_manage_qhash(iwdev, nfo, IRDMA_QHASH_TYPE_TCP_SYN, op, NULL,
4368146b9756SMustafa Ismail 				 false);
4369146b9756SMustafa Ismail 	if (!err) {
4370146b9756SMustafa Ismail 		child_listen_node->qhash_set = ifup;
4371146b9756SMustafa Ismail 		if (node_allocated)
4372146b9756SMustafa Ismail 			list_add(&child_listen_node->child_listen_list,
4373146b9756SMustafa Ismail 				 &parent_listen_node->child_listen_list);
4374146b9756SMustafa Ismail 	} else if (node_allocated) {
4375146b9756SMustafa Ismail 		kfree(child_listen_node);
4376146b9756SMustafa Ismail 	}
4377146b9756SMustafa Ismail }
4378146b9756SMustafa Ismail 
4379146b9756SMustafa Ismail /**
4380146b9756SMustafa Ismail  * irdma_if_notify - process an ifdown on an interface
4381146b9756SMustafa Ismail  * @iwdev: device pointer
4382146b9756SMustafa Ismail  * @netdev: network device structure
4383146b9756SMustafa Ismail  * @ipaddr: Pointer to IPv4 or IPv6 address
4384146b9756SMustafa Ismail  * @ipv4: flag indicating IPv4 when true
4385146b9756SMustafa Ismail  * @ifup: flag indicating interface up when true
4386146b9756SMustafa Ismail  */
irdma_if_notify(struct irdma_device * iwdev,struct net_device * netdev,u32 * ipaddr,bool ipv4,bool ifup)4387146b9756SMustafa Ismail void irdma_if_notify(struct irdma_device *iwdev, struct net_device *netdev,
4388146b9756SMustafa Ismail 		     u32 *ipaddr, bool ipv4, bool ifup)
4389146b9756SMustafa Ismail {
4390146b9756SMustafa Ismail 	struct irdma_cm_core *cm_core = &iwdev->cm_core;
4391146b9756SMustafa Ismail 	unsigned long flags;
4392146b9756SMustafa Ismail 	struct irdma_cm_listener *listen_node;
4393146b9756SMustafa Ismail 	static const u32 ip_zero[4] = { 0, 0, 0, 0 };
4394146b9756SMustafa Ismail 	struct irdma_cm_info nfo = {};
4395146b9756SMustafa Ismail 	u16 vlan_id = rdma_vlan_dev_vlan_id(netdev);
4396146b9756SMustafa Ismail 	enum irdma_quad_hash_manage_type op = ifup ?
4397146b9756SMustafa Ismail 					      IRDMA_QHASH_MANAGE_TYPE_ADD :
4398146b9756SMustafa Ismail 					      IRDMA_QHASH_MANAGE_TYPE_DELETE;
4399146b9756SMustafa Ismail 
4400146b9756SMustafa Ismail 	nfo.vlan_id = vlan_id;
4401146b9756SMustafa Ismail 	nfo.ipv4 = ipv4;
4402146b9756SMustafa Ismail 	nfo.qh_qpid = 1;
4403146b9756SMustafa Ismail 
4404146b9756SMustafa Ismail 	/* Disable or enable qhash for listeners */
4405146b9756SMustafa Ismail 	spin_lock_irqsave(&cm_core->listen_list_lock, flags);
4406146b9756SMustafa Ismail 	list_for_each_entry (listen_node, &cm_core->listen_list, list) {
4407146b9756SMustafa Ismail 		if (vlan_id != listen_node->vlan_id ||
4408146b9756SMustafa Ismail 		    (memcmp(listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16) &&
4409146b9756SMustafa Ismail 		     memcmp(listen_node->loc_addr, ip_zero, ipv4 ? 4 : 16)))
4410146b9756SMustafa Ismail 			continue;
4411146b9756SMustafa Ismail 
4412146b9756SMustafa Ismail 		memcpy(nfo.loc_addr, listen_node->loc_addr,
4413146b9756SMustafa Ismail 		       sizeof(nfo.loc_addr));
4414146b9756SMustafa Ismail 		nfo.loc_port = listen_node->loc_port;
4415146b9756SMustafa Ismail 		nfo.user_pri = listen_node->user_pri;
4416146b9756SMustafa Ismail 		if (!list_empty(&listen_node->child_listen_list)) {
4417146b9756SMustafa Ismail 			irdma_qhash_ctrl(iwdev, listen_node, &nfo, ipaddr, ipv4,
4418146b9756SMustafa Ismail 					 ifup);
4419146b9756SMustafa Ismail 		} else if (memcmp(listen_node->loc_addr, ip_zero,
4420146b9756SMustafa Ismail 				  ipv4 ? 4 : 16)) {
4421146b9756SMustafa Ismail 			if (!irdma_manage_qhash(iwdev, &nfo,
4422146b9756SMustafa Ismail 						IRDMA_QHASH_TYPE_TCP_SYN, op,
4423146b9756SMustafa Ismail 						NULL, false))
4424146b9756SMustafa Ismail 				listen_node->qhash_set = ifup;
4425146b9756SMustafa Ismail 		}
4426146b9756SMustafa Ismail 	}
4427146b9756SMustafa Ismail 	spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
4428146b9756SMustafa Ismail 
4429146b9756SMustafa Ismail 	/* disconnect any connected qp's on ifdown */
4430146b9756SMustafa Ismail 	if (!ifup)
4431146b9756SMustafa Ismail 		irdma_cm_teardown_connections(iwdev, ipaddr, &nfo, false);
4432146b9756SMustafa Ismail }
4433