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
tcp_ctloutput defined in line 321; never used
tcp_disconnect defined in line 422; used 2 times
tcp_usrclosed defined in line 452; used 2 times
tcp_usrreq defined in line 53; never used

Defined variables

tcp_recvspace defined in line 381; used 1 times
tcp_sendspace defined in line 380; used 1 times
Last modified: 1988-04-29
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4521
Valid CSS Valid XHTML 1.0 Strict