tcp_offload.c revision 180648
1238384Sjkim/*- 2238384Sjkim * Copyright (c) 2007, Chelsio Inc. 3238384Sjkim * All rights reserved. 4238384Sjkim * 5238384Sjkim * Redistribution and use in source and binary forms, with or without 6238384Sjkim * modification, are permitted provided that the following conditions are met: 7238384Sjkim * 8238384Sjkim * 1. Redistributions of source code must retain the above copyright notice, 9238384Sjkim * this list of conditions and the following disclaimer. 10238384Sjkim * 11238384Sjkim * 2. Neither the name of the Chelsio Corporation nor the names of its 12238384Sjkim * contributors may be used to endorse or promote products derived from 13238384Sjkim * this software without specific prior written permission. 14238384Sjkim * 15238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16238384Sjkim * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18238384Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19238384Sjkim * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20238384Sjkim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21238384Sjkim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22238384Sjkim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23238384Sjkim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25238384Sjkim * POSSIBILITY OF SUCH DAMAGE. 26238384Sjkim */ 27238384Sjkim 28238384Sjkim#include <sys/cdefs.h> 29238384Sjkim__FBSDID("$FreeBSD: head/sys/netinet/tcp_offload.c 180648 2008-07-21 02:23:02Z kmacy $"); 30238384Sjkim 31238384Sjkim#include <sys/param.h> 32238384Sjkim#include <sys/systm.h> 33238384Sjkim#include <sys/types.h> 34238384Sjkim#include <sys/malloc.h> 35238384Sjkim#include <sys/kernel.h> 36238384Sjkim#include <sys/sysctl.h> 37238384Sjkim#include <sys/mbuf.h> 38238384Sjkim#include <sys/socket.h> 39238384Sjkim#include <sys/socketvar.h> 40238384Sjkim 41238384Sjkim#include <net/if.h> 42238384Sjkim#include <net/if_types.h> 43238384Sjkim#include <net/if_var.h> 44238384Sjkim 45238384Sjkim#include <netinet/in.h> 46238384Sjkim#include <netinet/in_systm.h> 47238384Sjkim#include <netinet/in_pcb.h> 48238384Sjkim#include <netinet/tcp.h> 49238384Sjkim#include <netinet/tcp_var.h> 50238384Sjkim#include <netinet/tcp_offload.h> 51238384Sjkim#include <netinet/toedev.h> 52238384Sjkim 53238384Sjkimint 54238384Sjkimtcp_offload_connect(struct socket *so, struct sockaddr *nam) 55238384Sjkim{ 56238384Sjkim struct ifnet *ifp; 57238384Sjkim struct toedev *tdev; 58238384Sjkim struct rtentry *rt; 59238384Sjkim int error; 60238384Sjkim 61238384Sjkim /* 62238384Sjkim * Look up the route used for the connection to 63238384Sjkim * determine if it uses an interface capable of 64238384Sjkim * offloading the connection. 65238384Sjkim */ 66238384Sjkim rt = rtalloc1(nam, 1 /*report*/, 0 /*ignflags*/); 67238384Sjkim if (rt) 68238384Sjkim RT_UNLOCK(rt); 69238384Sjkim else 70238384Sjkim return (EHOSTUNREACH); 71238384Sjkim 72238384Sjkim ifp = rt->rt_ifp; 73238384Sjkim if ((ifp->if_capenable & IFCAP_TOE) == 0) { 74238384Sjkim error = EINVAL; 75238384Sjkim goto fail; 76238384Sjkim } 77238384Sjkim 78238384Sjkim tdev = TOEDEV(ifp); 79238384Sjkim if (tdev == NULL) { 80238384Sjkim error = EPERM; 81238384Sjkim goto fail; 82238384Sjkim } 83238384Sjkim 84238384Sjkim if (tdev->tod_can_offload(tdev, so) == 0) { 85238384Sjkim error = EPERM; 86238384Sjkim goto fail; 87238384Sjkim } 88238384Sjkim 89238384Sjkim return (tdev->tod_connect(tdev, so, rt, nam)); 90238384Sjkimfail: 91238384Sjkim RTFREE(rt); 92238384Sjkim return (error); 93238384Sjkim} 94238384Sjkim 95238384Sjkim 96238384Sjkim/* 97238384Sjkim * This file contains code as a short-term staging area before it is moved in 98238384Sjkim * to sys/netinet/tcp_offload.c 99238384Sjkim */ 100238384Sjkim 101238384Sjkimvoid 102238384Sjkimtcp_offload_twstart(struct tcpcb *tp) 103238384Sjkim{ 104238384Sjkim 105238384Sjkim INP_INFO_WLOCK(&tcbinfo); 106238384Sjkim inp_wlock(tp->t_inpcb); 107238384Sjkim tcp_twstart(tp); 108238384Sjkim INP_INFO_WUNLOCK(&tcbinfo); 109238384Sjkim} 110238384Sjkim 111238384Sjkimvoid 112238384Sjkimtcp_offload_twstart_disconnect(struct tcpcb *tp) 113238384Sjkim{ 114238384Sjkim struct socket *so; 115238384Sjkim 116238384Sjkim INP_INFO_WLOCK(&tcbinfo); 117238384Sjkim inp_wlock(tp->t_inpcb); 118238384Sjkim so = tp->t_inpcb->inp_socket; 119238384Sjkim tcp_twstart(tp); 120238384Sjkim if (so) 121238384Sjkim soisdisconnected(so); 122238384Sjkim INP_INFO_WUNLOCK(&tcbinfo); 123238384Sjkim} 124238384Sjkim 125238384Sjkimstruct tcpcb * 126238384Sjkimtcp_offload_close(struct tcpcb *tp) 127238384Sjkim{ 128238384Sjkim 129238384Sjkim INP_INFO_WLOCK(&tcbinfo); 130238384Sjkim INP_WLOCK(tp->t_inpcb); 131238384Sjkim tp = tcp_close(tp); 132238384Sjkim INP_INFO_WUNLOCK(&tcbinfo); 133238384Sjkim if (tp) 134238384Sjkim INP_WUNLOCK(tp->t_inpcb); 135238384Sjkim 136238384Sjkim return (tp); 137238384Sjkim} 138238384Sjkim 139238384Sjkimstruct tcpcb * 140238384Sjkimtcp_offload_drop(struct tcpcb *tp, int error) 141238384Sjkim{ 142238384Sjkim 143238384Sjkim INP_INFO_WLOCK(&tcbinfo); 144238384Sjkim INP_WLOCK(tp->t_inpcb); 145238384Sjkim tp = tcp_drop(tp, error); 146238384Sjkim INP_INFO_WUNLOCK(&tcbinfo); 147238384Sjkim if (tp) 148238384Sjkim INP_WUNLOCK(tp->t_inpcb); 149238384Sjkim 150238384Sjkim return (tp); 151238384Sjkim} 152238384Sjkim 153238384Sjkim