1210753Srpaulo/*- 2210753Srpaulo * Copyright (c) 2012 Chelsio Communications, Inc. 3210753Srpaulo * All rights reserved. 4210753Srpaulo * 5210753Srpaulo * Redistribution and use in source and binary forms, with or without 6210753Srpaulo * modification, are permitted provided that the following conditions 7210753Srpaulo * are met: 8210753Srpaulo * 1. Redistributions of source code must retain the above copyright 9210753Srpaulo * notice, this list of conditions and the following disclaimer. 10210753Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11210753Srpaulo * notice, this list of conditions and the following disclaimer in the 12210753Srpaulo * documentation and/or other materials provided with the distribution. 13210753Srpaulo * 14210753Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15210753Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16210753Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17210753Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18210753Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19210753Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20210753Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21210753Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22210753Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23210753Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24210753Srpaulo * SUCH DAMAGE. 25210753Srpaulo */ 26210753Srpaulo 27210753Srpaulo#include <sys/cdefs.h> 28210753Srpaulo__FBSDID("$FreeBSD$"); 29210753Srpaulo 30210753Srpaulo#include "opt_inet.h" 31210753Srpaulo 32210753Srpaulo#include <sys/param.h> 33210753Srpaulo#include <sys/systm.h> 34210753Srpaulo#include <sys/types.h> 35210753Srpaulo#include <sys/mbuf.h> 36210753Srpaulo#include <sys/socket.h> 37210753Srpaulo#include <sys/socketvar.h> 38210753Srpaulo#include <sys/sockopt.h> 39210753Srpaulo#include <net/if.h> 40210753Srpaulo#include <net/if_var.h> 41210753Srpaulo#include <net/route.h> 42210753Srpaulo#include <netinet/in.h> 43210753Srpaulo#include <netinet/in_pcb.h> 44210753Srpaulo#include <netinet/tcp.h> 45210753Srpaulo#include <netinet/tcp_offload.h> 46210753Srpaulo#define TCPOUTFLAGS 47210753Srpaulo#include <netinet/tcp_fsm.h> 48210753Srpaulo#include <netinet/tcp_var.h> 49210753Srpaulo#include <netinet/toecore.h> 50210753Srpaulo 51210753Srpauloint registered_toedevs; 52210753Srpaulo 53210753Srpaulo/* 54210753Srpaulo * Provide an opportunity for a TOE driver to offload. 55210753Srpaulo */ 56210753Srpauloint 57210753Srpaulotcp_offload_connect(struct socket *so, struct sockaddr *nam) 58210753Srpaulo{ 59210753Srpaulo struct ifnet *ifp; 60210753Srpaulo struct toedev *tod; 61210753Srpaulo struct rtentry *rt; 62210753Srpaulo int error = EOPNOTSUPP; 63210753Srpaulo 64210753Srpaulo INP_WLOCK_ASSERT(sotoinpcb(so)); 65210753Srpaulo KASSERT(nam->sa_family == AF_INET || nam->sa_family == AF_INET6, 66210753Srpaulo ("%s: called with sa_family %d", __func__, nam->sa_family)); 67210753Srpaulo 68210753Srpaulo if (registered_toedevs == 0) 69210753Srpaulo return (error); 70210753Srpaulo 71210753Srpaulo rt = rtalloc1(nam, 0, 0); 72210753Srpaulo if (rt) 73210753Srpaulo RT_UNLOCK(rt); 74210753Srpaulo else 75210753Srpaulo return (EHOSTUNREACH); 76210753Srpaulo 77210753Srpaulo ifp = rt->rt_ifp; 78210753Srpaulo 79280773Smarkj if (nam->sa_family == AF_INET && !(ifp->if_capenable & IFCAP_TOE4)) 80210753Srpaulo goto done; 81210753Srpaulo if (nam->sa_family == AF_INET6 && !(ifp->if_capenable & IFCAP_TOE6)) 82286171Smarkj goto done; 83210753Srpaulo 84210753Srpaulo tod = TOEDEV(ifp); 85210753Srpaulo if (tod != NULL) 86210753Srpaulo error = tod->tod_connect(tod, so, rt, nam); 87210753Srpaulodone: 88210753Srpaulo RTFREE(rt); 89210753Srpaulo return (error); 90210753Srpaulo} 91210753Srpaulo 92210753Srpaulovoid 93210753Srpaulotcp_offload_listen_start(struct tcpcb *tp) 94210753Srpaulo{ 95210753Srpaulo 96210753Srpaulo INP_WLOCK_ASSERT(tp->t_inpcb); 97210753Srpaulo 98210753Srpaulo EVENTHANDLER_INVOKE(tcp_offload_listen_start, tp); 99210753Srpaulo} 100210753Srpaulo 101210753Srpaulovoid 102210753Srpaulotcp_offload_listen_stop(struct tcpcb *tp) 103210753Srpaulo{ 104210753Srpaulo 105210753Srpaulo INP_WLOCK_ASSERT(tp->t_inpcb); 106210753Srpaulo 107210753Srpaulo EVENTHANDLER_INVOKE(tcp_offload_listen_stop, tp); 108210753Srpaulo} 109210753Srpaulo 110210753Srpaulovoid 111210753Srpaulotcp_offload_input(struct tcpcb *tp, struct mbuf *m) 112210753Srpaulo{ 113210753Srpaulo struct toedev *tod = tp->tod; 114210753Srpaulo 115210753Srpaulo KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 116210753Srpaulo INP_WLOCK_ASSERT(tp->t_inpcb); 117210753Srpaulo 118210753Srpaulo tod->tod_input(tod, tp, m); 119210753Srpaulo} 120210753Srpaulo 121210753Srpauloint 122210753Srpaulotcp_offload_output(struct tcpcb *tp) 123210753Srpaulo{ 124210753Srpaulo struct toedev *tod = tp->tod; 125210753Srpaulo int error, flags; 126210753Srpaulo 127211545Srpaulo KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 128210753Srpaulo INP_WLOCK_ASSERT(tp->t_inpcb); 129210753Srpaulo 130 flags = tcp_outflags[tp->t_state]; 131 132 if (flags & TH_RST) { 133 /* XXX: avoid repeated calls like we do for FIN */ 134 error = tod->tod_send_rst(tod, tp); 135 } else if ((flags & TH_FIN || tp->t_flags & TF_NEEDFIN) && 136 (tp->t_flags & TF_SENTFIN) == 0) { 137 error = tod->tod_send_fin(tod, tp); 138 if (error == 0) 139 tp->t_flags |= TF_SENTFIN; 140 } else 141 error = tod->tod_output(tod, tp); 142 143 return (error); 144} 145 146void 147tcp_offload_rcvd(struct tcpcb *tp) 148{ 149 struct toedev *tod = tp->tod; 150 151 KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 152 INP_WLOCK_ASSERT(tp->t_inpcb); 153 154 tod->tod_rcvd(tod, tp); 155} 156 157void 158tcp_offload_ctloutput(struct tcpcb *tp, int sopt_dir, int sopt_name) 159{ 160 struct toedev *tod = tp->tod; 161 162 KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 163 INP_WLOCK_ASSERT(tp->t_inpcb); 164 165 tod->tod_ctloutput(tod, tp, sopt_dir, sopt_name); 166} 167 168void 169tcp_offload_detach(struct tcpcb *tp) 170{ 171 struct toedev *tod = tp->tod; 172 173 KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 174 INP_WLOCK_ASSERT(tp->t_inpcb); 175 176 tod->tod_pcb_detach(tod, tp); 177} 178