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