tcp_offload.c revision 237263
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: head/sys/netinet/tcp_offload.c 237263 2012-06-19 07:34:13Z np $"); 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> 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> 46237263Snp#define TCPOUTFLAGS 47237263Snp#include <netinet/tcp_fsm.h> 48237263Snp#include <netinet/toecore.h> 49174704Skmacy 50237263Snpint registered_toedevs; 51182591Skmacy 52237263Snp/* 53237263Snp * Provide an opportunity for a TOE driver to offload. 54237263Snp */ 55174704Skmacyint 56174704Skmacytcp_offload_connect(struct socket *so, struct sockaddr *nam) 57174704Skmacy{ 58174704Skmacy struct ifnet *ifp; 59237263Snp struct toedev *tod; 60174704Skmacy struct rtentry *rt; 61237263Snp int error = EOPNOTSUPP; 62174704Skmacy 63237263Snp INP_WLOCK_ASSERT(sotoinpcb(so)); 64237263Snp KASSERT(nam->sa_family == AF_INET || nam->sa_family == AF_INET6, 65237263Snp ("%s: called with sa_family %d", __func__, nam->sa_family)); 66237263Snp 67237263Snp if (registered_toedevs == 0) 68237263Snp return (error); 69237263Snp 70237263Snp rt = rtalloc1(nam, 0, 0); 71237263Snp if (rt) 72174704Skmacy RT_UNLOCK(rt); 73237263Snp else 74174704Skmacy return (EHOSTUNREACH); 75174704Skmacy 76174704Skmacy ifp = rt->rt_ifp; 77237263Snp 78237263Snp if (nam->sa_family == AF_INET && !(ifp->if_capenable & IFCAP_TOE4)) 79237263Snp goto done; 80237263Snp if (nam->sa_family == AF_INET6 && !(ifp->if_capenable & IFCAP_TOE6)) 81237263Snp goto done; 82237263Snp 83237263Snp tod = TOEDEV(ifp); 84237263Snp if (tod != NULL) 85237263Snp error = tod->tod_connect(tod, so, rt, nam); 86237263Snpdone: 87174704Skmacy RTFREE(rt); 88174704Skmacy return (error); 89174704Skmacy} 90180648Skmacy 91237263Snpvoid 92237263Snptcp_offload_listen_start(struct tcpcb *tp) 93237263Snp{ 94180648Skmacy 95237263Snp INP_WLOCK_ASSERT(tp->t_inpcb); 96180648Skmacy 97237263Snp EVENTHANDLER_INVOKE(tcp_offload_listen_start, tp); 98237263Snp} 99237263Snp 100180648Skmacyvoid 101237263Snptcp_offload_listen_stop(struct tcpcb *tp) 102180648Skmacy{ 103180648Skmacy 104237263Snp INP_WLOCK_ASSERT(tp->t_inpcb); 105237263Snp 106237263Snp EVENTHANDLER_INVOKE(tcp_offload_listen_stop, tp); 107180648Skmacy} 108180648Skmacy 109237263Snpvoid 110237263Snptcp_offload_input(struct tcpcb *tp, struct mbuf *m) 111180648Skmacy{ 112237263Snp struct toedev *tod = tp->tod; 113195699Srwatson 114237263Snp KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 115237263Snp INP_WLOCK_ASSERT(tp->t_inpcb); 116180648Skmacy 117237263Snp tod->tod_input(tod, tp, m); 118180648Skmacy} 119180648Skmacy 120237263Snpint 121237263Snptcp_offload_output(struct tcpcb *tp) 122180648Skmacy{ 123237263Snp struct toedev *tod = tp->tod; 124237263Snp int error, flags; 125195699Srwatson 126237263Snp KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 127237263Snp INP_WLOCK_ASSERT(tp->t_inpcb); 128180648Skmacy 129237263Snp flags = tcp_outflags[tp->t_state]; 130237263Snp 131237263Snp if (flags & TH_RST) { 132237263Snp /* XXX: avoid repeated calls like we do for FIN */ 133237263Snp error = tod->tod_send_rst(tod, tp); 134237263Snp } else if ((flags & TH_FIN || tp->t_flags & TF_NEEDFIN) && 135237263Snp (tp->t_flags & TF_SENTFIN) == 0) { 136237263Snp error = tod->tod_send_fin(tod, tp); 137237263Snp if (error == 0) 138237263Snp tp->t_flags |= TF_SENTFIN; 139237263Snp } else 140237263Snp error = tod->tod_output(tod, tp); 141237263Snp 142237263Snp return (error); 143180648Skmacy} 144180648Skmacy 145237263Snpvoid 146237263Snptcp_offload_rcvd(struct tcpcb *tp) 147237263Snp{ 148237263Snp struct toedev *tod = tp->tod; 149237263Snp 150237263Snp KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 151237263Snp INP_WLOCK_ASSERT(tp->t_inpcb); 152237263Snp 153237263Snp tod->tod_rcvd(tod, tp); 154237263Snp} 155237263Snp 156237263Snpvoid 157237263Snptcp_offload_ctloutput(struct tcpcb *tp, int sopt_dir, int sopt_name) 158237263Snp{ 159237263Snp struct toedev *tod = tp->tod; 160237263Snp 161237263Snp KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 162237263Snp INP_WLOCK_ASSERT(tp->t_inpcb); 163237263Snp 164237263Snp tod->tod_ctloutput(tod, tp, sopt_dir, sopt_name); 165237263Snp} 166237263Snp 167237263Snpvoid 168237263Snptcp_offload_detach(struct tcpcb *tp) 169237263Snp{ 170237263Snp struct toedev *tod = tp->tod; 171237263Snp 172237263Snp KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); 173237263Snp INP_WLOCK_ASSERT(tp->t_inpcb); 174237263Snp 175237263Snp tod->tod_pcb_detach(tod, tp); 176237263Snp} 177