1174704Skmacy/*-
2252555Snp * Copyright (c) 2012 Chelsio Communications, Inc.
3174704Skmacy * All rights reserved.
4174704Skmacy *
5174704Skmacy * Redistribution and use in source and binary forms, with or without
6252555Snp * modification, are permitted provided that the following conditions
7252555Snp * are met:
8252555Snp * 1. Redistributions of source code must retain the above copyright
9252555Snp *    notice, this list of conditions and the following disclaimer.
10252555Snp * 2. Redistributions in binary form must reproduce the above copyright
11252555Snp *    notice, this list of conditions and the following disclaimer in the
12252555Snp *    documentation and/or other materials provided with the distribution.
13174704Skmacy *
14252555Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15252555Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16174704Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17252555Snp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18252555Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19252555Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20252555Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21252555Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22252555Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23252555Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24252555Snp * SUCH DAMAGE.
25174704Skmacy */
26174704Skmacy
27174704Skmacy#include <sys/cdefs.h>
28174704Skmacy__FBSDID("$FreeBSD$");
29174704Skmacy
30252555Snp#include "opt_inet.h"
31252555Snp
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>
38252555Snp#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>
46252555Snp#define	TCPOUTFLAGS
47252555Snp#include <netinet/tcp_fsm.h>
48252555Snp#include <netinet/toecore.h>
49174704Skmacy
50252555Snpint registered_toedevs;
51182591Skmacy
52252555Snp/*
53252555Snp * Provide an opportunity for a TOE driver to offload.
54252555Snp */
55174704Skmacyint
56174704Skmacytcp_offload_connect(struct socket *so, struct sockaddr *nam)
57174704Skmacy{
58174704Skmacy	struct ifnet *ifp;
59252555Snp	struct toedev *tod;
60174704Skmacy	struct rtentry *rt;
61252555Snp	int error = EOPNOTSUPP;
62174704Skmacy
63252555Snp	INP_WLOCK_ASSERT(sotoinpcb(so));
64252555Snp	KASSERT(nam->sa_family == AF_INET || nam->sa_family == AF_INET6,
65252555Snp	    ("%s: called with sa_family %d", __func__, nam->sa_family));
66252555Snp
67252555Snp	if (registered_toedevs == 0)
68252555Snp		return (error);
69252555Snp
70252555Snp	rt = rtalloc1(nam, 0, 0);
71252555Snp	if (rt)
72174704Skmacy		RT_UNLOCK(rt);
73252555Snp	else
74174704Skmacy		return (EHOSTUNREACH);
75174704Skmacy
76174704Skmacy	ifp = rt->rt_ifp;
77252555Snp
78252555Snp	if (nam->sa_family == AF_INET && !(ifp->if_capenable & IFCAP_TOE4))
79252555Snp		goto done;
80252555Snp	if (nam->sa_family == AF_INET6 && !(ifp->if_capenable & IFCAP_TOE6))
81252555Snp		goto done;
82252555Snp
83252555Snp	tod = TOEDEV(ifp);
84252555Snp	if (tod != NULL)
85252555Snp		error = tod->tod_connect(tod, so, rt, nam);
86252555Snpdone:
87174704Skmacy	RTFREE(rt);
88174704Skmacy	return (error);
89174704Skmacy}
90180648Skmacy
91252555Snpvoid
92252555Snptcp_offload_listen_start(struct tcpcb *tp)
93252555Snp{
94180648Skmacy
95252555Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
96180648Skmacy
97252555Snp	EVENTHANDLER_INVOKE(tcp_offload_listen_start, tp);
98252555Snp}
99252555Snp
100180648Skmacyvoid
101252555Snptcp_offload_listen_stop(struct tcpcb *tp)
102180648Skmacy{
103180648Skmacy
104252555Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
105252555Snp
106252555Snp	EVENTHANDLER_INVOKE(tcp_offload_listen_stop, tp);
107180648Skmacy}
108180648Skmacy
109252555Snpvoid
110252555Snptcp_offload_input(struct tcpcb *tp, struct mbuf *m)
111180648Skmacy{
112252555Snp	struct toedev *tod = tp->tod;
113195699Srwatson
114252555Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
115252555Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
116180648Skmacy
117252555Snp	tod->tod_input(tod, tp, m);
118180648Skmacy}
119180648Skmacy
120252555Snpint
121252555Snptcp_offload_output(struct tcpcb *tp)
122180648Skmacy{
123252555Snp	struct toedev *tod = tp->tod;
124252555Snp	int error, flags;
125195699Srwatson
126252555Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
127252555Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
128180648Skmacy
129252555Snp	flags = tcp_outflags[tp->t_state];
130252555Snp
131252555Snp	if (flags & TH_RST) {
132252555Snp		/* XXX: avoid repeated calls like we do for FIN */
133252555Snp		error = tod->tod_send_rst(tod, tp);
134252555Snp	} else if ((flags & TH_FIN || tp->t_flags & TF_NEEDFIN) &&
135252555Snp	    (tp->t_flags & TF_SENTFIN) == 0) {
136252555Snp		error = tod->tod_send_fin(tod, tp);
137252555Snp		if (error == 0)
138252555Snp			tp->t_flags |= TF_SENTFIN;
139252555Snp	} else
140252555Snp		error = tod->tod_output(tod, tp);
141252555Snp
142252555Snp	return (error);
143180648Skmacy}
144180648Skmacy
145252555Snpvoid
146252555Snptcp_offload_rcvd(struct tcpcb *tp)
147252555Snp{
148252555Snp	struct toedev *tod = tp->tod;
149252555Snp
150252555Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
151252555Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
152252555Snp
153252555Snp	tod->tod_rcvd(tod, tp);
154252555Snp}
155252555Snp
156252555Snpvoid
157252555Snptcp_offload_ctloutput(struct tcpcb *tp, int sopt_dir, int sopt_name)
158252555Snp{
159252555Snp	struct toedev *tod = tp->tod;
160252555Snp
161252555Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
162252555Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
163252555Snp
164252555Snp	tod->tod_ctloutput(tod, tp, sopt_dir, sopt_name);
165252555Snp}
166252555Snp
167252555Snpvoid
168252555Snptcp_offload_detach(struct tcpcb *tp)
169252555Snp{
170252555Snp	struct toedev *tod = tp->tod;
171252555Snp
172252555Snp	KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
173252555Snp	INP_WLOCK_ASSERT(tp->t_inpcb);
174252555Snp
175252555Snp	tod->tod_pcb_detach(tod, tp);
176252555Snp}
177