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