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/11.0/sys/netinet/tcp_offload.c 294869 2016-01-27 00:45:46Z glebius $");
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>
40257176Sglebius#include <net/if_var.h>
41194739Sbz#include <net/route.h>
42174704Skmacy#include <netinet/in.h>
43174704Skmacy#include <netinet/in_pcb.h>
44174704Skmacy#include <netinet/tcp.h>
45174704Skmacy#include <netinet/tcp_offload.h>
46237263Snp#define	TCPOUTFLAGS
47237263Snp#include <netinet/tcp_fsm.h>
48294869Sglebius#include <netinet/tcp_var.h>
49237263Snp#include <netinet/toecore.h>
50174704Skmacy
51237263Snpint registered_toedevs;
52182591Skmacy
53237263Snp/*
54237263Snp * Provide an opportunity for a TOE driver to offload.
55237263Snp */
56174704Skmacyint
57174704Skmacytcp_offload_connect(struct socket *so, struct sockaddr *nam)
58174704Skmacy{
59174704Skmacy	struct ifnet *ifp;
60237263Snp	struct toedev *tod;
61174704Skmacy	struct rtentry *rt;
62237263Snp	int error = EOPNOTSUPP;
63174704Skmacy
64237263Snp	INP_WLOCK_ASSERT(sotoinpcb(so));
65237263Snp	KASSERT(nam->sa_family == AF_INET || nam->sa_family == AF_INET6,
66237263Snp	    ("%s: called with sa_family %d", __func__, nam->sa_family));
67237263Snp
68237263Snp	if (registered_toedevs == 0)
69237263Snp		return (error);
70237263Snp
71237263Snp	rt = rtalloc1(nam, 0, 0);
72237263Snp	if (rt)
73174704Skmacy		RT_UNLOCK(rt);
74237263Snp	else
75174704Skmacy		return (EHOSTUNREACH);
76174704Skmacy
77174704Skmacy	ifp = rt->rt_ifp;
78237263Snp
79237263Snp	if (nam->sa_family == AF_INET && !(ifp->if_capenable & IFCAP_TOE4))
80237263Snp		goto done;
81237263Snp	if (nam->sa_family == AF_INET6 && !(ifp->if_capenable & IFCAP_TOE6))
82237263Snp		goto done;
83237263Snp
84237263Snp	tod = TOEDEV(ifp);
85237263Snp	if (tod != NULL)
86237263Snp		error = tod->tod_connect(tod, so, rt, nam);
87237263Snpdone:
88174704Skmacy	RTFREE(rt);
89174704Skmacy	return (error);
90174704Skmacy}
91180648Skmacy
92237263Snpvoid
93237263Snptcp_offload_listen_start(struct tcpcb *tp)
94237263Snp{
95180648Skmacy
96237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
97180648Skmacy
98237263Snp	EVENTHANDLER_INVOKE(tcp_offload_listen_start, tp);
99237263Snp}
100237263Snp
101180648Skmacyvoid
102237263Snptcp_offload_listen_stop(struct tcpcb *tp)
103180648Skmacy{
104180648Skmacy
105237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
106237263Snp
107237263Snp	EVENTHANDLER_INVOKE(tcp_offload_listen_stop, tp);
108180648Skmacy}
109180648Skmacy
110237263Snpvoid
111237263Snptcp_offload_input(struct tcpcb *tp, struct mbuf *m)
112180648Skmacy{
113237263Snp	struct toedev *tod = tp->tod;
114195699Srwatson
115237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
116237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
117180648Skmacy
118237263Snp	tod->tod_input(tod, tp, m);
119180648Skmacy}
120180648Skmacy
121237263Snpint
122237263Snptcp_offload_output(struct tcpcb *tp)
123180648Skmacy{
124237263Snp	struct toedev *tod = tp->tod;
125237263Snp	int error, flags;
126195699Srwatson
127237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
128237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
129180648Skmacy
130237263Snp	flags = tcp_outflags[tp->t_state];
131237263Snp
132237263Snp	if (flags & TH_RST) {
133237263Snp		/* XXX: avoid repeated calls like we do for FIN */
134237263Snp		error = tod->tod_send_rst(tod, tp);
135237263Snp	} else if ((flags & TH_FIN || tp->t_flags & TF_NEEDFIN) &&
136237263Snp	    (tp->t_flags & TF_SENTFIN) == 0) {
137237263Snp		error = tod->tod_send_fin(tod, tp);
138237263Snp		if (error == 0)
139237263Snp			tp->t_flags |= TF_SENTFIN;
140237263Snp	} else
141237263Snp		error = tod->tod_output(tod, tp);
142237263Snp
143237263Snp	return (error);
144180648Skmacy}
145180648Skmacy
146237263Snpvoid
147237263Snptcp_offload_rcvd(struct tcpcb *tp)
148237263Snp{
149237263Snp	struct toedev *tod = tp->tod;
150237263Snp
151237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
152237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
153237263Snp
154237263Snp	tod->tod_rcvd(tod, tp);
155237263Snp}
156237263Snp
157237263Snpvoid
158237263Snptcp_offload_ctloutput(struct tcpcb *tp, int sopt_dir, int sopt_name)
159237263Snp{
160237263Snp	struct toedev *tod = tp->tod;
161237263Snp
162237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
163237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
164237263Snp
165237263Snp	tod->tod_ctloutput(tod, tp, sopt_dir, sopt_name);
166237263Snp}
167237263Snp
168237263Snpvoid
169237263Snptcp_offload_detach(struct tcpcb *tp)
170237263Snp{
171237263Snp	struct toedev *tod = tp->tod;
172237263Snp
173237263Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
174237263Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
175237263Snp
176237263Snp	tod->tod_pcb_detach(tod, tp);
177237263Snp}
178