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