# 2.11BSD#431 - /usr/src/sys/netinet/tcp_usrreq.c

##### Functions

    tcp_attach        X
    tcp_ctloutput     X
    tcp_disconnect    X
    tcp_usrclosed     X
    tcp_usrreq        X

##### Variables

    tcp_recvspace     X
    tcp_sendspace     X

       1: /*
       2:  * Copyright (c) 1982, 1986 Regents of the University of California.
       3:  * All rights reserved.
       4:  *
       5:  * Redistribution and use in source and binary forms are permitted
       6:  * provided that this notice is preserved and that due credit is given
       7:  * to the University of California at Berkeley. The name of the University
       8:  * may not be used to endorse or promote products derived from this
       9:  * software without specific prior written permission. This software
      10:  * is provided ``as is'' without express or implied warranty.
      11:  *
      12:  *	@(#)tcp_usrreq.c	7.7.1.2 (Berkeley) 3/16/88
      13:  */
      14:
      15: #include "param.h"
      16: #include "systm.h"
      17: #include "mbuf.h"
      18: #include "socket.h"
      19: #include "socketvar.h"
      20: #include "protosw.h"
      21: #include "errno.h"
      22: #include "stat.h"
      23:
      24: #include "../net/if.h"
      25: #include "../net/route.h"
      26:
      27: #include "domain.h"
      28: #include "in.h"
      29: #include "in_pcb.h"
      30: #include "in_systm.h"
      31: #include "ip.h"
      32: #include "ip_var.h"
      33: #include "tcp.h"
      34: #include "tcp_fsm.h"
      35: #include "tcp_seq.h"
      36: #include "tcp_timer.h"
      37: #include "tcp_var.h"
      38: #include "tcpip.h"
      39: #include "tcp_debug.h"
      40:
      41: /*
      42:  * TCP protocol interface to socket abstraction.
      43:  */
      44: extern  char *tcpstates[];
      45: struct  tcpcb *tcp_newtcpcb();
      46:
      47: /*
      48:  * Process a TCP user request for TCP tb.  If this is a send request
      49:  * then m is the mbuf chain of send data.  If this is a timer expiration
      50:  * (called from the software clock routine), then timertype tells which timer.
      51:  */
      52: /*ARGSUSED*/
      53: tcp_usrreq(so, req, m, nam, rights)
      54:     struct socket *so;
      55:     int req;
      56:     struct mbuf *m, *nam, *rights;
      57: {
      58:     register struct inpcb *inp;
      59:     register struct tcpcb *tp;
      60:     int s;
      61:     int error = 0;
      62:     int ostate;
      63:
      64: #if BSD>=43
      65:     if (req == PRU_CONTROL)
      66:         return (in_control(so, (int)m, (caddr_t)nam,
      67:             (struct ifnet *)rights));
      68: #else
      69:     if (req == PRU_CONTROL)
      70:         return(EOPNOTSUPP);
      71: #endif
      72:     if (rights && rights->m_len)
      73:         return (EINVAL);
      74:
      75:     s = splnet();
      76:     inp = sotoinpcb(so);
      77:     /*
      78: 	 * When a TCP is attached to a socket, then there will be
      79: 	 * a (struct inpcb) pointed at by the socket, and this
      80: 	 * structure will point at a subsidary (struct tcpcb).
      81: 	 */
      82:     if (inp == 0 && req != PRU_ATTACH) {
      83:         splx(s);
      84:         return (EINVAL);        /* XXX */
      85:     }
      86:     if (inp) {
      87:         tp = intotcpcb(inp);
      88:         /* WHAT IF TP IS 0? */
      89: #ifdef KPROF
      90:         tcp_acounts[tp->t_state][req]++;
      91: #endif
      92:         ostate = tp->t_state;
      93:     } else
      94:         ostate = 0;
      95:     switch (req) {
      96:
      97:     /*
      98: 	 * TCP attaches to socket via PRU_ATTACH, reserving space,
      99: 	 * and an internet control block.
     100: 	 */
     101:     case PRU_ATTACH:
     102:         if (inp) {
     103:             error = EISCONN;
     104:             break;
     105:         }
     106:         error = tcp_attach(so);
     107:         if (error)
     108:             break;
     109:         if ((so->so_options & SO_LINGER) && so->so_linger == 0)
     110:             so->so_linger = TCP_LINGERTIME;
     111:         tp = sototcpcb(so);
     112:         break;
     113:
     114:     /*
     115: 	 * PRU_DETACH detaches the TCP protocol from the socket.
     116: 	 * If the protocol state is non-embryonic, then can't
     117: 	 * do this directly: have to initiate a PRU_DISCONNECT,
     118: 	 * which may finish later; embryonic TCB's can just
     119: 	 * be discarded here.
     120: 	 */
     121:     case PRU_DETACH:
     122:         if (tp->t_state > TCPS_LISTEN)
     123:             tp = tcp_disconnect(tp);
     124:         else
     125:             tp = tcp_close(tp);
     126:         break;
     127:
     128:     /*
     129: 	 * Give the socket an address.
     130: 	 */
     131:     case PRU_BIND:
     132:         error = in_pcbbind(inp, nam);
     133:         if (error)
     134:             break;
     135:         break;
     136:
     137:     /*
     138: 	 * Prepare to accept connections.
     139: 	 */
     140:     case PRU_LISTEN:
     141:         if (inp->inp_lport == 0)
     142:             error = in_pcbbind(inp, (struct mbuf *)0);
     143:         if (error == 0)
     144:             tp->t_state = TCPS_LISTEN;
     145:         break;
     146:
     147:     /*
     148: 	 * Initiate connection to peer.
     149: 	 * Create a template for use in transmissions on this connection.
     150: 	 * Enter SYN_SENT state, and mark socket as connecting.
     151: 	 * Start keep-alive timer, and seed output sequence space.
     152: 	 * Send initial segment on connection.
     153: 	 */
     154:     case PRU_CONNECT:
     155:         if (inp->inp_lport == 0) {
     156:             error = in_pcbbind(inp, (struct mbuf *)0);
     157:             if (error)
     158:                 break;
     159:         }
     160:         error = in_pcbconnect(inp, nam);
     161:         if (error)
     162:             break;
     163:         tp->t_template = tcp_template(tp);
     164:         if (tp->t_template == 0) {
     165:             in_pcbdisconnect(inp);
     166:             error = ENOBUFS;
     167:             break;
     168:         }
     169:         soisconnecting(so);
     170:         tcpstat.tcps_connattempt++;
     171:         tp->t_state = TCPS_SYN_SENT;
     172:         tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
     173:         tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
     174:         tcp_sendseqinit(tp);
     175:         error = tcp_output(tp);
     176:         break;
     177:
     178:     /*
     179: 	 * Create a TCP connection between two sockets.
     180: 	 */
     181:     case PRU_CONNECT2:
     182:         error = EOPNOTSUPP;
     183:         break;
     184:
     185:     /*
     186: 	 * Initiate disconnect from peer.
     187: 	 * If connection never passed embryonic stage, just drop;
     188: 	 * else if don't need to let data drain, then can just drop anyways,
     189: 	 * else have to begin TCP shutdown process: mark socket disconnecting,
     190: 	 * drain unread data, state switch to reflect user close, and
     191: 	 * send segment (e.g. FIN) to peer.  Socket will be really disconnected
     192: 	 * when peer sends FIN and acks ours.
     193: 	 *
     194: 	 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
     195: 	 */
     196:     case PRU_DISCONNECT:
     197:         tp = tcp_disconnect(tp);
     198:         break;
     199:
     200:     /*
     201: 	 * Accept a connection.  Essentially all the work is
     202: 	 * done at higher levels; just return the address
     203: 	 * of the peer, storing through addr.
     204: 	 */
     205:     case PRU_ACCEPT: {
     206:         struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
     207:
     208:         nam->m_len = sizeof (struct sockaddr_in);
     209:         sin->sin_family = AF_INET;
     210:         sin->sin_port = inp->inp_fport;
     211:         sin->sin_addr = inp->inp_faddr;
     212:         break;
     213:         }
     214:
     215:     /*
     216: 	 * Mark the connection as being incapable of further output.
     217: 	 */
     218:     case PRU_SHUTDOWN:
     219:         socantsendmore(so);
     220:         tp = tcp_usrclosed(tp);
     221:         if (tp)
     222:             error = tcp_output(tp);
     223:         break;
     224:
     225:     /*
     226: 	 * After a receive, possibly send window update to peer.
     227: 	 */
     228:     case PRU_RCVD:
     229:         (void) tcp_output(tp);
     230:         break;
     231:
     232:     /*
     233: 	 * Do a send by putting data in output queue and updating urgent
     234: 	 * marker if URG set.  Possibly send more data.
     235: 	 */
     236:     case PRU_SEND:
     237:         sbappend(&so->so_snd, m);
     238:         error = tcp_output(tp);
     239:         break;
     240:
     241:     /*
     242: 	 * Abort the TCP.
     243: 	 */
     244:     case PRU_ABORT:
     245:         tp = tcp_drop(tp, ECONNABORTED);
     246:         break;
     247:
     248:     case PRU_SENSE:
     249:         ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
     250:         (void) splx(s);
     251:         return (0);
     252:
     253:     case PRU_RCVOOB:
     254:         if ((so->so_oobmark == 0 &&
     255:             (so->so_state & SS_RCVATMARK) == 0) ||
     256: #ifdef SO_OOBINLINE
     257:             so->so_options & SO_OOBINLINE ||
     258: #endif
     259:             tp->t_oobflags & TCPOOB_HADDATA) {
     260:             error = EINVAL;
     261:             break;
     262:         }
     263:         if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
     264:             error = EWOULDBLOCK;
     265:             break;
     266:         }
     267:         m->m_len = 1;
     268:         *mtod(m, caddr_t) = tp->t_iobc;
     269:         if (((int)nam & MSG_PEEK) == 0)
     270:             tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
     271:         break;
     272:
     273:     case PRU_SENDOOB:
     274:         if (sbspace(&so->so_snd) < -512) {
     275:             m_freem(m);
     276:             error = ENOBUFS;
     277:             break;
     278:         }
     279:         /*
     280: 		 * According to RFC961 (Assigned Protocols),
     281: 		 * the urgent pointer points to the last octet
     282: 		 * of urgent data.  We continue, however,
     283: 		 * to consider it to indicate the first octet
     284: 		 * of data past the urgent section.
     285: 		 * Otherwise, snd_up should be one lower.
     286: 		 */
     287:         sbappend(&so->so_snd, m);
     288:         tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
     289:         tp->t_force = 1;
     290:         error = tcp_output(tp);
     291:         tp->t_force = 0;
     292:         break;
     293:
     294:     case PRU_SOCKADDR:
     295:         in_setsockaddr(inp, nam);
     296:         break;
     297:
     298:     case PRU_PEERADDR:
     299:         in_setpeeraddr(inp, nam);
     300:         break;
     301:
     302:     /*
     303: 	 * TCP slow timer went off; going through this
     304: 	 * routine for tracing's sake.
     305: 	 */
     306:     case PRU_SLOWTIMO:
     307:         tp = tcp_timers(tp, (int)nam);
     308:         req |= (int)nam << 8;       /* for debug's sake */
     309:         break;
     310:
     311:     default:
     312:         panic("tcp_usrreq");
     313:     }
     314:     if (tp && (so->so_options & SO_DEBUG))
     315:         tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
     316:     splx(s);
     317:     return (error);
     318: }
     319:
     320: #if BSD>=43
     321: tcp_ctloutput(op, so, level, optname, mp)
     322:     int op;
     323:     struct socket *so;
     324:     int level, optname;
     325:     struct mbuf **mp;
     326: {
     327:     int error = 0;
     328:     struct inpcb *inp = sotoinpcb(so);
     329:     register struct tcpcb *tp = intotcpcb(inp);
     330:     register struct mbuf *m;
     331:
     332:     if (level != IPPROTO_TCP)
     333:         return (ip_ctloutput(op, so, level, optname, mp));
     334:
     335:     switch (op) {
     336:
     337:     case PRCO_SETOPT:
     338:         m = *mp;
     339:         switch (optname) {
     340:
     341:         case TCP_NODELAY:
     342:             if (m == NULL || m->m_len < sizeof (int))
     343:                 error = EINVAL;
     344:             else if (*mtod(m, int *))
     345:                 tp->t_flags |= TF_NODELAY;
     346:             else
     347:                 tp->t_flags &= ~TF_NODELAY;
     348:             break;
     349:
     350:         case TCP_MAXSEG:    /* not yet */
     351:         default:
     352:             error = EINVAL;
     353:             break;
     354:         }
     355:         if (m)
     356:             (void) m_free(m);
     357:         break;
     358:
     359:     case PRCO_GETOPT:
     360:         *mp = m = m_get(M_WAIT, MT_SOOPTS);
     361:         m->m_len = sizeof(int);
     362:
     363:         switch (optname) {
     364:         case TCP_NODELAY:
     365:             *mtod(m, int *) = tp->t_flags & TF_NODELAY;
     366:             break;
     367:         case TCP_MAXSEG:
     368:             *mtod(m, int *) = tp->t_maxseg;
     369:             break;
     370:         default:
     371:             error = EINVAL;
     372:             break;
     373:         }
     374:         break;
     375:     }
     376:     return (error);
     377: }
     378: #endif
     379:
     380: int tcp_sendspace = 1024*4;
     381: int tcp_recvspace = 1024*4;
     382: /*
     383:  * Attach TCP protocol to socket, allocating
     384:  * internet protocol control block, tcp control block,
     385:  * bufer space, and entering LISTEN state if to accept connections.
     386:  */
     387: tcp_attach(so)
     388:     struct socket *so;
     389: {
     390:     register struct tcpcb *tp;
     391:     struct inpcb *inp;
     392:     int error;
     393:
     394:     error = soreserve(so, tcp_sendspace, tcp_recvspace);
     395:     if (error)
     396:         return (error);
     397:     error = in_pcballoc(so, &tcb);
     398:     if (error)
     399:         return (error);
     400:     inp = sotoinpcb(so);
     401:     tp = tcp_newtcpcb(inp);
     402:     if (tp == 0) {
     403:         int nofd = so->so_state & SS_NOFDREF;   /* XXX */
     404:
     405:         so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
     406:         in_pcbdetach(inp);
     407:         so->so_state |= nofd;
     408:         return (ENOBUFS);
     409:     }
     410:     tp->t_state = TCPS_CLOSED;
     411:     return (0);
     412: }
     413:
     414: /*
     415:  * Initiate (or continue) disconnect.
     416:  * If embryonic state, just send reset (once).
     417:  * If in ``let data drain'' option and linger null, just drop.
     418:  * Otherwise (hard), mark socket disconnecting and drop
     419:  * current input data; switch states based on user close, and
     420:  * send segment to peer (with FIN).
     421:  */
     422: struct tcpcb *
     423: tcp_disconnect(tp)
     424:     register struct tcpcb *tp;
     425: {
     426:     struct socket *so = tp->t_inpcb->inp_socket;
     427:
     428:     if (tp->t_state < TCPS_ESTABLISHED)
     429:         tp = tcp_close(tp);
     430:     else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
     431:         tp = tcp_drop(tp, 0);
     432:     else {
     433:         soisdisconnecting(so);
     434:         sbflush(&so->so_rcv);
     435:         tp = tcp_usrclosed(tp);
     436:         if (tp)
     437:             (void) tcp_output(tp);
     438:     }
     439:     return (tp);
     440: }
     441:
     442: /*
     443:  * User issued close, and wish to trail through shutdown states:
     444:  * if never received SYN, just forget it.  If got a SYN from peer,
     445:  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
     446:  * If already got a FIN from peer, then almost done; go to LAST_ACK
     447:  * state.  In all other cases, have already sent FIN to peer (e.g.
     448:  * after PRU_SHUTDOWN), and just have to play tedious game waiting
     449:  * for peer to send FIN or not respond to keep-alives, etc.
     450:  * We can let the user exit from the close as soon as the FIN is acked.
     451:  */
     452: struct tcpcb *
     453: tcp_usrclosed(tp)
     454:     register struct tcpcb *tp;
     455: {
     456:
     457:     switch (tp->t_state) {
     458:
     459:     case TCPS_CLOSED:
     460:     case TCPS_LISTEN:
     461:     case TCPS_SYN_SENT:
     462:         tp->t_state = TCPS_CLOSED;
     463:         tp = tcp_close(tp);
     464:         break;
     465:
     466:     case TCPS_SYN_RECEIVED:
     467:     case TCPS_ESTABLISHED:
     468:         tp->t_state = TCPS_FIN_WAIT_1;
     469:         break;
     470:
     471:     case TCPS_CLOSE_WAIT:
     472:         tp->t_state = TCPS_LAST_ACK;
     473:         break;
     474:     }
     475:     if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
     476:         soisdisconnected(tp->t_inpcb->inp_socket);
     477:     return (tp);
     478: }

#### Defined functions

tcp_attach defined in line 387; used 1 times

- in line 106

tcp_ctloutput defined in line 321; never used
tcp_disconnect defined in line 422; used 2 times

- in line 123, 197

tcp_usrclosed defined in line 452; used 2 times

- in line 220, 435

tcp_usrreq defined in line 53; never used

#### Defined variables

tcp_recvspace defined in line 381; used 1 times

- in line 394

tcp_sendspace defined in line 380; used 1 times

- in line 394

Last modified: 1988-04-29 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1784 |