📄 tcp_usrreq.c
字号:
#ifndef lintstatic char *sccsid = "@(#)tcp_usrreq.c 4.3 ULTRIX 3/7/91";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * * * 07-Mar-91 Michael G. Mc Menemy * Fix OOB handling if SO_BUFFOOB is turned off * * 18-June-90 lp * Bump up send/receive buffers for TCP. May use more * memory on ethernet but should speed transfers. * * 2-Jan-90 U. Sinkewicz * Performance enhancements to uniprocessor kernel. * * 30-May-89 U. Sinkewicz * Added so->ref and SO_LOCK to fix the smp problem caused * by unlocking the socket and locking it again to * accommodate the lock hierarchy and sleeps. * * 05-May-89 Michael G. Mc Menemy * Add XTI support. * * 31-Mar-89 U. Sinkewicz * Change lock heirarchy so that lk_tcb is lower than * lk_socket. * * 27-Mar-89 U. Sinkewicz * Replaced tcpstatistics with a macro as per lp changes * from 3.16.89. * * 3-Mar-89 U. Sinkewicz * Pmax/smp merge. * * 15-Jan-88 lp * Merge of final 43BSD changes. * * Larry Cohen - 01/28/87 * Add tcp control output routine * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * ************************************************************************//* * Copyright (c) 1982 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * tcp_usrreq.c 6.6 (Berkeley) 6/8/85 */#include "../h/param.h"#include "../h/systm.h"#include "../h/mbuf.h"#include "../h/socket.h"#include "../h/socketvar.h"#include "../h/protosw.h"#include "../h/errno.h"#include "../h/stat.h"#include "../h/smp_lock.h"#include "../net/net/if.h"#include "../net/net/route.h"#ifdef XTI#include "../h/domain.h"#endif XTI#include "../net/netinet/in.h"#include "../net/netinet/in_pcb.h"#include "../net/netinet/in_systm.h"#include "../net/netinet/ip.h"#include "../net/netinet/ip_var.h"#include "../net/netinet/tcp.h"#include "../net/netinet/tcp_fsm.h"#include "../net/netinet/tcp_seq.h"#include "../net/netinet/tcp_timer.h"#include "../net/netinet/tcp_var.h"#include "../net/netinet/tcpip.h"#include "../net/netinet/tcp_debug.h"/* * TCP protocol interface to socket abstraction. */extern char *tcpstates[];struct tcpcb *tcp_newtcpcb();int tcpsenderrors;#ifdef XTIextern int xti_debug;#define PRINTXTID(level, msg) \ /* \ * level: \ * 0x01 = generate events; \ * 0x04 = acceptchk/abort support; \ * 0x08 = peek events; \ * 0x10 = tpdu T_MORE support; \ * 0x20 = oob mark; \ * 0x40 = options negot. \ * 0x80 = protocol; \ */ \ if (xti_debug & (level)) \ cprintf((msg))#else#define PRINTXTID(level, msg)#endif XTI/* * Process a TCP user request for TCP tb. If this is a send request * then m is the mbuf chain of send data. If this is a timer expiration * (called from the software clock routine), then timertype tells which timer. * SMP: Enter with socket lock set except for PRU_SENSE which is called from * file system. *//*ARGSUSED*/tcp_usrreq(so, req, m, nam, rights) struct socket *so; int req; struct mbuf *m, *nam, *rights;{ register struct inpcb *inp; register struct tcpcb *tp; int s; int error = 0; int ostate; struct socket *so_tmp = NULL; /* SMP */ struct socket *so_addr = NULL; /* SMP */ int status = 0; /* SMP */ struct inpcb *inp_tmp = NULL; /* SMP */ /* * For CONTROL, come in at splnet with socket locked. Path is from * ioctl (sys_generic.c) to soo_ioctl (sys_socket.c) to ifioctl (if.c) * to tcp_usrreq (pr->pr_usrreq). Locks are set in * soo_ioctl because it changes socket state fields. 3.26.87.us * */ if (req == PRU_CONTROL) return (in_control(so, (int)m, (caddr_t)nam, (struct ifnet *)rights)); if (rights && rights->m_len) return (EINVAL); s = splnet(); inp = sotoinpcb(so); /* * When a TCP is attached to a socket, then there will be * a (struct inpcb) pointed at by the socket, and this * structure will point at a subsidary (struct tcpcb). */ if (inp == 0 && req != PRU_ATTACH) { return (EINVAL); /* XXX */ } if (inp) { tp = intotcpcb(inp); /* WHAT IF TP IS 0? */#ifdef XTI if (tp == 0) { return(EBADF); }#endif XTI#ifdef KPROF tcp_acounts[tp->t_state][req]++;#endif ostate = tp->t_state; } else ostate = 0; switch (req) { /* * TCP attaches to socket via PRU_ATTACH, reserving space, * and an internet control block. */ case PRU_ATTACH: if (inp) { error = EISCONN; break; } error = tcp_attach(so); if (error) break; if ((so->so_options & SO_LINGER) && so->so_linger == 0) so->so_linger = TCP_LINGERTIME; tp = sototcpcb(so);#ifdef XTI so->so_xticb.xti_tpinfo = &xti_tcpinfo;#endif XTI break; /* * PRU_DETACH detaches the TCP protocol from the socket. * If the protocol state is non-embryonic, then can't * do this directly: have to initiate a PRU_DISCONNECT, * which may finish later; embryonic TCB's can just * be discarded here. */ case PRU_DETACH: if (tp->t_state > TCPS_LISTEN) tp = tcp_disconnect(tp); else tp = tcp_close(tp); break; /* * Give the socket an address. */ case PRU_BIND: if (smp){ so->ref = 11; smp_unlock(&so->lk_socket); smp_lock(&lk_tcb, LK_RETRY); smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; error = in_pcbbind(inp, nam); smp_unlock(&lk_tcb); } else error = in_pcbbind(inp, nam); if (error) break; break; /* * Prepare to accept connections. */ case PRU_LISTEN: if (inp->inp_lport == 0){ if(smp){ so->ref = 12; smp_unlock(&so->lk_socket); smp_lock(&lk_tcb, LK_RETRY); smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; error = in_pcbbind(inp, (struct mbuf *)0); smp_unlock(&lk_tcb); }else error = in_pcbbind(inp, (struct mbuf *)0); } if (error == 0) tp->t_state = TCPS_LISTEN; break; /* * Initiate connection to peer. * Create a template for use in transmissions on this connection. * Enter SYN_SENT state, and mark socket as connecting. * Start keep-alive timer, and seed output sequence space. * Send initial segment on connection. */ /* SMP: socket locked coming in. */ case PRU_CONNECT: if (inp->inp_lport == 0) { if (smp){ so->ref = 13; smp_unlock(&so->lk_socket); smp_lock(&lk_tcb, LK_RETRY); smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; error = in_pcbbind(inp, (struct mbuf *)0); smp_unlock(&lk_tcb); }else error = in_pcbbind(inp, (struct mbuf *)0); if (error) break; } if (smp){ so->ref = 13; smp_unlock(&so->lk_socket); smp_lock(&lk_tcb, LK_RETRY); smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; error = in_pcbconnect(inp, nam); smp_unlock(&lk_tcb); } else error = in_pcbconnect(inp, nam); if (error) break; tp->t_template = tcp_template(tp); if (tp->t_template == 0) { if (smp){ so->ref = 13; smp_unlock(&so->lk_socket); smp_lock(&lk_tcb, LK_RETRY); smp_lock(&so->lk_socket, LK_RETRY); so->ref = 0; in_pcbdisconnect(inp); smp_unlock(&lk_tcb); }else in_pcbdisconnect(inp); error = ENOBUFS; break; } soisconnecting(so); /* Does a wakeup */ TCPSTAT(tcps_connattempt++); tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; smp_lock(&lk_tcpiss, LK_RETRY); tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; smp_unlock(&lk_tcpiss); tcp_sendseqinit(tp); error = tcp_output(tp); break; /* * Create a TCP connection between two sockets. */ case PRU_CONNECT2: error = EOPNOTSUPP; break; /* * Initiate disconnect from peer. * If connection never passed embryonic stage, just drop; * else if don't need to let data drain, then can just drop anyways, * else have to begin TCP shutdown process: mark socket disconnecting, * drain unread data, state switch to reflect user close, and * send segment (e.g. FIN) to peer. Socket will be really disconnected * when peer sends FIN and acks ours. * * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. */ case PRU_DISCONNECT: tp = tcp_disconnect(tp); break; /* * Accept a connection. Essentially all the work is * done at higher levels; just return the address * of the peer, storing through addr. */ case PRU_ACCEPT: { struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); nam->m_len = sizeof (struct sockaddr_in); sin->sin_family = AF_INET; sin->sin_port = inp->inp_fport; sin->sin_addr = inp->inp_faddr; break; } /* * Mark the connection as being incapable of further output. */ case PRU_SHUTDOWN: socantsendmore(so); tp = tcp_usrclosed(tp); if (tp) error = tcp_output(tp); break; /* * After a receive, possibly send window update to peer. */ case PRU_RCVD: (void) tcp_output(tp); break; /* * Do a send by putting data in output queue and updating urgent * marker if URG set. Possibly send more data. * SMP: socket lock set coming in. */ case PRU_SEND: sbappend(&so->so_snd, m); error = tcp_output(tp); if (error) { /* XXX fix to use other path */ if (error == ENOBUFS) /* XXX */ error = 0; /* XXX */ tcpsenderrors++; } break; /* * Abort the TCP. */ case PRU_ABORT: tp = tcp_drop(tp, ECONNABORTED); break; case PRU_SENSE: ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; (void)splx(s); return (0); case PRU_RCVOOB: if ((so->so_oobmark == 0 && (so->so_state & SS_RCVATMARK) == 0) || so->so_options & SO_OOBINLINE || tp->t_oobflags & TCPOOB_HADDATA) { error = EINVAL; break; } if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { error = EWOULDBLOCK; break; } if (so->so_options & SO_BUFFOOB) { if (((int)nam & MSG_PEEK) == 0) if (!so->so_exrcv.sb_cc) tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA); } else { m->m_len = 1; *mtod(m, caddr_t) = tp->t_iobc; if (((int)nam & MSG_PEEK) == 0) tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA); } break; case PRU_SENDOOB: if (sbspace(&so->so_snd) < -512) { m_freem(m); error = ENOBUFS; break; } /* * According to RFC961 (Assigned Protocols), * the urgent pointer points to the last octet * of urgent data. We continue, however, * to consider it to indicate the first octet * of data past the urgent section. * Otherwise, snd_up should be one lower. */ sbappend(&so->so_snd, m); tp->snd_up = tp->snd_una + so->so_snd.sb_cc; tp->t_force = 1; error = tcp_output(tp); tp->t_force = 0; break; case PRU_SOCKADDR: in_setsockaddr(inp, nam); break; case PRU_PEERADDR: in_setpeeraddr(inp, nam); break; /* * TCP slow timer went off; going through this * routine for tracing's sake. */ /* SMP: Lock set in tcp_slowtimeo. 4.21.87.us. */ case PRU_SLOWTIMO: tp = tcp_timers(tp, (int)nam); req |= (int)nam << 8; /* for debug's sake */ break; default: error = EOPNOTSUPP; } if (tp && (so->so_options & SO_DEBUG)) tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); splx(s); return (error);}tcp_ctloutput(op, so, level, optname, mp) int op; struct socket *so; int level, optname; struct mbuf **mp;{#ifdef XTI int error = 0; struct inpcb *inp = 0; register struct tcpcb *tp = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -