1174704Skmacy/*-
2237263Snp * Copyright (c) 2012 Chelsio Communications, Inc.
3174704Skmacy * All rights reserved.
4174704Skmacy *
5174704Skmacy * Redistribution and use in source and binary forms, with or without
6237263Snp * modification, are permitted provided that the following conditions
7237263Snp * are met:
8237263Snp * 1. Redistributions of source code must retain the above copyright
9237263Snp *    notice, this list of conditions and the following disclaimer.
10237263Snp * 2. Redistributions in binary form must reproduce the above copyright
11237263Snp *    notice, this list of conditions and the following disclaimer in the
12237263Snp *    documentation and/or other materials provided with the distribution.
13174704Skmacy *
14237263Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15237263Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16174704Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17237263Snp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18237263Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19237263Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20237263Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21237263Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22237263Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23237263Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24237263Snp * SUCH DAMAGE.
25174704Skmacy */
26174704Skmacy
27174704Skmacy#include <sys/cdefs.h>
28174704Skmacy__FBSDID("$FreeBSD: releng/10.3/sys/netinet/tcp_offload.c 237263 2012-06-19 07:34:13Z np $");
29174704Skmacy
30237263Snp#include "opt_inet.h"
31237263Snp
32174704Skmacy#include <sys/param.h>
33174704Skmacy#include <sys/systm.h>
34174704Skmacy#include <sys/types.h>
35174704Skmacy#include <sys/mbuf.h>
36174704Skmacy#include <sys/socket.h>
37174704Skmacy#include <sys/socketvar.h>
38237263Snp#include <sys/sockopt.h>
39174704Skmacy#include <net/if.h>
40194739Sbz#include <net/route.h>
41174704Skmacy#include <netinet/in.h>
42174704Skmacy#include <netinet/in_pcb.h>
43174704Skmacy#include <netinet/tcp.h>
44174704Skmacy#include <netinet/tcp_var.h>
45174704Skmacy#include <netinet/tcp_offload.h>
46237263Snp#define	TCPOUTFLAGS
47237263Snp#include <netinet/tcp_fsm.h>
48237263Snp#include <netinet/toecore.h>
49174704Skmacy
50237263Snpint registered_toedevs;
51182591Skmacy
52237263Snp/*
53237263Snp * Provide an opportunity for a TOE driver to offload.
54237263Snp */
55174704Skmacyint
56174704Skmacytcp_offload_connect(struct socket *so, struct sockaddr *nam)
57174704Skmacy{
58174704Skmacy	struct ifnet *ifp;
59237263Snp	struct toedev *tod;
60174704Skmacy	struct rtentry *rt;
61237263Snp	int error = EOPNOTSUPP;
62174704Skmacy
63237263Snp	INP_WLOCK_ASSERT(sotoinpcb(so));
64237263Snp	KASSERT(nam->sa_family == AF_INET || nam->sa_family == AF_INET6,
65237263Snp	    ("%s: called with sa_family %d", __func__, nam->sa_family));
66237263Snp
67237263Snp	if (registered_toedevs == 0)
68237263Snp		return (error);
69237263Snp
70237263Snp	rt = rtalloc1(nam, 0, 0);
71237263Snp	if (rt)
72174704Skmacy		RT_UNLOCK(rt);
73237263Snp	else
74174704Skmacy		return (EHOSTUNREACH);
75174704Skmacy
76174704Skmacy	ifp = rt->rt_ifp;
77237263Snp
78237263Snp	if (nam->sa_family == AF_INET && !(ifp->if_capenable & IFCAP_TOE4))
79237263Snp		goto done;
80237263Snp	if (nam->sa_family == AF_INET6 && !(ifp->if_capenable & IFCAP_TOE6))
81237263Snp		goto done;
82237263Snp
83237263Snp	tod = TOEDEV(ifp);
84237263Snp	if (tod != NULL)
85237263Snp		error = tod->tod_connect(tod, so, rt, nam);
86237263Snpdone:
87174704Skmacy	RTFREE(rt);
88174704Skmacy	return (error);
89174704Skmacy}
90180648Skmacy
91237263Snpvoid
92237263Snptcp_offload_listen_start(struct tcpcb *tp)
93237263Snp{
94180648Skmacy
95237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
96180648Skmacy
97237263Snp	EVENTHANDLER_INVOKE(tcp_offload_listen_start, tp);
98237263Snp}
99237263Snp
100180648Skmacyvoid
101237263Snptcp_offload_listen_stop(struct tcpcb *tp)
102180648Skmacy{
103180648Skmacy
104237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
105237263Snp
106237263Snp	EVENTHANDLER_INVOKE(tcp_offload_listen_stop, tp);
107180648Skmacy}
108180648Skmacy
109237263Snpvoid
110237263Snptcp_offload_input(struct tcpcb *tp, struct mbuf *m)
111180648Skmacy{
112237263Snp	struct toedev *tod = tp->tod;
113195699Srwatson
114237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
115237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
116180648Skmacy
117237263Snp	tod->tod_input(tod, tp, m);
118180648Skmacy}
119180648Skmacy
120237263Snpint
121237263Snptcp_offload_output(struct tcpcb *tp)
122180648Skmacy{
123237263Snp	struct toedev *tod = tp->tod;
124237263Snp	int error, flags;
125195699Srwatson
126237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
127237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
128180648Skmacy
129237263Snp	flags = tcp_outflags[tp->t_state];
130237263Snp
131237263Snp	if (flags & TH_RST) {
132237263Snp		/* XXX: avoid repeated calls like we do for FIN */
133237263Snp		error = tod->tod_send_rst(tod, tp);
134237263Snp	} else if ((flags & TH_FIN || tp->t_flags & TF_NEEDFIN) &&
135237263Snp	    (tp->t_flags & TF_SENTFIN) == 0) {
136237263Snp		error = tod->tod_send_fin(tod, tp);
137237263Snp		if (error == 0)
138237263Snp			tp->t_flags |= TF_SENTFIN;
139237263Snp	} else
140237263Snp		error = tod->tod_output(tod, tp);
141237263Snp
142237263Snp	return (error);
143180648Skmacy}
144180648Skmacy
145237263Snpvoid
146237263Snptcp_offload_rcvd(struct tcpcb *tp)
147237263Snp{
148237263Snp	struct toedev *tod = tp->tod;
149237263Snp
150237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
151237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
152237263Snp
153237263Snp	tod->tod_rcvd(tod, tp);
154237263Snp}
155237263Snp
156237263Snpvoid
157237263Snptcp_offload_ctloutput(struct tcpcb *tp, int sopt_dir, int sopt_name)
158237263Snp{
159237263Snp	struct toedev *tod = tp->tod;
160237263Snp
161237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
162237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
163237263Snp
164237263Snp	tod->tod_ctloutput(tod, tp, sopt_dir, sopt_name);
165237263Snp}
166237263Snp
167237263Snpvoid
168237263Snptcp_offload_detach(struct tcpcb *tp)
169237263Snp{
170237263Snp	struct toedev *tod = tp->tod;
171237263Snp
172237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
173237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
174237263Snp
175237263Snp	tod->tod_pcb_detach(tod, tp);
176237263Snp}
177