1 /**************************************************************************
3 Copyright (c) 2007, Chelsio Inc.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
12 2. Neither the name of the Chelsio Corporation nor the names of its
13 contributors may be used to endorse or promote products derived from
14 this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 POSSIBILITY OF SUCH DAMAGE.
28 ***************************************************************************/
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/fcntl.h>
36 #include <sys/limits.h>
39 #include <sys/mutex.h>
41 #include <sys/sockopt.h>
42 #include <sys/sockstate.h>
43 #include <sys/sockbuf.h>
45 #include <sys/socket.h>
46 #include <sys/syslog.h>
49 #include <net/route.h>
51 #include <netinet/in.h>
52 #include <netinet/in_pcb.h>
53 #include <netinet/in_systm.h>
54 #include <netinet/in_var.h>
57 #include <cxgb_osdep.h>
58 #include <sys/mbufq.h>
60 #include <netinet/tcp.h>
61 #include <netinet/tcp_var.h>
62 #include <netinet/tcp_fsm.h>
64 #include <netinet/tcp_offload.h>
65 #include <net/route.h>
68 #include <common/cxgb_firmware_exports.h>
69 #include <common/cxgb_t3_cpl.h>
70 #include <common/cxgb_tcb.h>
71 #include <common/cxgb_ctl_defs.h>
72 #include <cxgb_offload.h>
73 #include <ulp/toecore/cxgb_toedev.h>
74 #include <ulp/tom/cxgb_l2t.h>
75 #include <ulp/tom/cxgb_defs.h>
76 #include <ulp/tom/cxgb_tom.h>
77 #include <ulp/tom/cxgb_t3_ddp.h>
78 #include <ulp/tom/cxgb_toepcb.h>
81 static struct listen_info *listen_hash_add(struct tom_data *d, struct socket *so, unsigned int stid);
82 static int listen_hash_del(struct tom_data *d, struct socket *so);
85 * Process a CPL_CLOSE_LISTSRV_RPL message. If the status is good we release
89 do_close_server_rpl(struct t3cdev *cdev, struct mbuf *m, void *ctx)
91 struct cpl_close_listserv_rpl *rpl = cplhdr(m);
92 unsigned int stid = GET_TID(rpl);
94 if (rpl->status != CPL_ERR_NONE)
95 log(LOG_ERR, "Unexpected CLOSE_LISTSRV_RPL status %u for "
96 "STID %u\n", rpl->status, stid);
98 struct listen_ctx *listen_ctx = (struct listen_ctx *)ctx;
100 cxgb_free_stid(cdev, stid);
101 free(listen_ctx, M_CXGB);
104 return (CPL_RET_BUF_DONE);
108 * Process a CPL_PASS_OPEN_RPL message. Remove the socket from the listen hash
109 * table and free the STID if there was any error, otherwise nothing to do.
112 do_pass_open_rpl(struct t3cdev *cdev, struct mbuf *m, void *ctx)
114 struct cpl_pass_open_rpl *rpl = cplhdr(m);
116 if (rpl->status != CPL_ERR_NONE) {
117 int stid = GET_TID(rpl);
118 struct listen_ctx *listen_ctx = (struct listen_ctx *)ctx;
119 struct tom_data *d = listen_ctx->tom_data;
120 struct socket *lso = listen_ctx->lso;
124 return (CPL_RET_UNKNOWN_TID | CPL_RET_BUF_DONE);
127 * Note: It is safe to unconditionally call listen_hash_del()
128 * at this point without risking unhashing a reincarnation of
129 * an already closed socket (i.e., there is no listen, close,
130 * listen, free the sock for the second listen while processing
131 * a message for the first race) because we are still holding
132 * a reference on the socket. It is possible that the unhash
133 * will fail because the socket is already closed, but we can't
134 * unhash the wrong socket because it is impossible for the
135 * socket to which this message refers to have reincarnated.
137 listen_hash_del(d, lso);
138 cxgb_free_stid(cdev, stid);
141 * XXX need to unreference the inpcb
142 * but we have no way of knowing that other TOMs aren't referencing it
146 free(listen_ctx, M_CXGB);
148 return CPL_RET_BUF_DONE;
152 t3_init_listen_cpl_handlers(void)
154 t3tom_register_cpl_handler(CPL_PASS_OPEN_RPL, do_pass_open_rpl);
155 t3tom_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_close_server_rpl);
159 listen_hashfn(const struct socket *so)
161 return ((unsigned long)so >> 10) & (LISTEN_INFO_HASH_SIZE - 1);
165 * Create and add a listen_info entry to the listen hash table. This and the
166 * listen hash table functions below cannot be called from softirqs.
168 static struct listen_info *
169 listen_hash_add(struct tom_data *d, struct socket *so, unsigned int stid)
171 struct listen_info *p;
173 p = malloc(sizeof(*p), M_CXGB, M_NOWAIT|M_ZERO);
175 int bucket = listen_hashfn(so);
177 p->so = so; /* just a key, no need to take a reference */
179 mtx_lock(&d->listen_lock);
180 p->next = d->listen_hash_tab[bucket];
181 d->listen_hash_tab[bucket] = p;
182 mtx_unlock(&d->listen_lock);
188 * Given a pointer to a listening socket return its server TID by consulting
189 * the socket->stid map. Returns -1 if the socket is not in the map.
192 listen_hash_find(struct tom_data *d, struct socket *so)
194 int stid = -1, bucket = listen_hashfn(so);
195 struct listen_info *p;
197 mtx_lock(&d->listen_lock);
198 for (p = d->listen_hash_tab[bucket]; p; p = p->next)
203 mtx_unlock(&d->listen_lock);
208 * Delete the listen_info structure for a listening socket. Returns the server
209 * TID for the socket if it is present in the socket->stid map, or -1.
212 listen_hash_del(struct tom_data *d, struct socket *so)
214 int bucket, stid = -1;
215 struct listen_info *p, **prev;
217 bucket = listen_hashfn(so);
218 prev = &d->listen_hash_tab[bucket];
220 mtx_lock(&d->listen_lock);
221 for (p = *prev; p; prev = &p->next, p = p->next)
228 mtx_unlock(&d->listen_lock);
234 * Start a listening server by sending a passive open request to HW.
237 t3_listen_start(struct toedev *dev, struct socket *so, struct t3cdev *cdev)
241 struct cpl_pass_open_req *req;
242 struct tom_data *d = TOM_DATA(dev);
243 struct inpcb *inp = so_sotoinpcb(so);
244 struct listen_ctx *ctx;
246 if (!TOM_TUNABLE(dev, activated))
249 if (listen_hash_find(d, so) != -1)
252 CTR1(KTR_TOM, "start listen on port %u", ntohs(inp->inp_lport));
253 ctx = malloc(sizeof(*ctx), M_CXGB, M_NOWAIT|M_ZERO);
260 ctx->ulp_mode = TOM_TUNABLE(dev, ddp) && !(so_options_get(so) & SO_NO_DDP) ? ULP_MODE_TCPDDP : 0;
261 LIST_INIT(&ctx->synq_head);
263 stid = cxgb_alloc_stid(d->cdev, d->client, ctx);
267 m = m_gethdr(M_NOWAIT, MT_DATA);
270 m->m_pkthdr.len = m->m_len = sizeof(*req);
272 if (!listen_hash_add(d, so, stid))
275 req = mtod(m, struct cpl_pass_open_req *);
276 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
277 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid));
278 req->local_port = inp->inp_lport;
279 memcpy(&req->local_ip, &inp->inp_laddr, 4);
282 req->peer_netmask = 0;
283 req->opt0h = htonl(F_DELACK | F_TCAM_BYPASS);
284 req->opt0l = htonl(V_RCV_BUFSIZ(16));
285 req->opt1 = htonl(V_CONN_POLICY(CPL_CONN_POLICY_ASK));
287 m_set_priority(m, CPL_PRIORITY_LISTEN);
288 cxgb_ofld_send(cdev, m);
294 cxgb_free_stid(cdev, stid);
303 * Stop a listening server by sending a close_listsvr request to HW.
304 * The server TID is freed when we get the reply.
307 t3_listen_stop(struct toedev *dev, struct socket *so, struct t3cdev *cdev)
310 struct cpl_close_listserv_req *req;
311 struct listen_ctx *lctx;
312 int stid = listen_hash_del(TOM_DATA(dev), so);
317 lctx = cxgb_get_lctx(cdev, stid);
319 * Do this early so embryonic connections are marked as being aborted
320 * while the stid is still open. This ensures pass_establish messages
321 * that arrive while we are closing the server will be able to locate
322 * the listening socket.
326 /* Send the close ASAP to stop further passive opens */
327 m = m_gethdr(M_NOWAIT, MT_DATA);
330 * XXX allocate from lowmem cache
333 m->m_pkthdr.len = m->m_len = sizeof(*req);
335 req = mtod(m, struct cpl_close_listserv_req *);
336 req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
337 OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid));
339 m_set_priority(m, CPL_PRIORITY_LISTEN);
340 cxgb_ofld_send(cdev, m);
342 t3_disconnect_acceptq(so);