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

Defined functions

tcp_attach defined in line 377; used 1 times
  • in line 94
tcp_ctloutput defined in line 313; used 2 times
tcp_disconnect defined in line 412; used 3 times
tcp_usrclosed defined in line 442; used 3 times
tcp_usrreq defined in line 47; used 3 times

Defined variables

tcp_recvspace defined in line 371; used 1 times
tcp_sendspace defined in line 370; used 1 times
tcpsenderrors defined in line 39; used 1 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1641
Valid CSS Valid XHTML 1.0 Strict