tcp_usrreq.c revision 11928
1121054Semax/* 2121054Semax * Copyright (c) 1982, 1986, 1988, 1993 3121054Semax * The Regents of the University of California. All rights reserved. 4121054Semax * 5121054Semax * Redistribution and use in source and binary forms, with or without 6121054Semax * modification, are permitted provided that the following conditions 7121054Semax * are met: 8121054Semax * 1. Redistributions of source code must retain the above copyright 9121054Semax * notice, this list of conditions and the following disclaimer. 10121054Semax * 2. Redistributions in binary form must reproduce the above copyright 11121054Semax * notice, this list of conditions and the following disclaimer in the 12121054Semax * documentation and/or other materials provided with the distribution. 13121054Semax * 3. All advertising materials mentioning features or use of this software 14121054Semax * must display the following acknowledgement: 15121054Semax * This product includes software developed by the University of 16121054Semax * California, Berkeley and its contributors. 17121054Semax * 4. Neither the name of the University nor the names of its contributors 18121054Semax * may be used to endorse or promote products derived from this software 19121054Semax * without specific prior written permission. 20121054Semax * 21121054Semax * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24121054Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31121054Semax * SUCH DAMAGE. 32121054Semax * 33121054Semax * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94 34121054Semax * $Id: tcp_usrreq.c,v 1.16 1995/09/13 17:54:03 wollman Exp $ 35121054Semax */ 36121054Semax 37121054Semax#include <sys/param.h> 38121054Semax#include <sys/systm.h> 39121054Semax#include <sys/kernel.h> 40121054Semax#include <sys/malloc.h> 41121054Semax#include <sys/mbuf.h> 42121054Semax#include <sys/socket.h> 43121054Semax#include <sys/socketvar.h> 44121054Semax#include <sys/protosw.h> 45121054Semax#include <sys/errno.h> 46121054Semax#include <sys/stat.h> 47121054Semax#include <vm/vm.h> 48121054Semax#include <sys/sysctl.h> 49121054Semax 50121054Semax#include <net/if.h> 51121054Semax#include <net/route.h> 52121054Semax 53121054Semax#include <netinet/in.h> 54121054Semax#include <netinet/in_systm.h> 55121054Semax#include <netinet/ip.h> 56121054Semax#include <netinet/in_pcb.h> 57121054Semax#include <netinet/in_var.h> 58121054Semax#include <netinet/ip_var.h> 59121054Semax#include <netinet/tcp.h> 60121054Semax#include <netinet/tcp_fsm.h> 61121054Semax#include <netinet/tcp_seq.h> 62121054Semax#include <netinet/tcp_timer.h> 63121054Semax#include <netinet/tcp_var.h> 64121054Semax#include <netinet/tcpip.h> 65121054Semax#ifdef TCPDEBUG 66121054Semax#include <netinet/tcp_debug.h> 67121054Semax#endif 68121054Semax 69121054Semax/* 70121054Semax * TCP protocol interface to socket abstraction. 71121054Semax */ 72121054Semaxextern char *tcpstates[]; 73121054Semax 74121054Semax/* 75121054Semax * Process a TCP user request for TCP tb. If this is a send request 76121054Semax * then m is the mbuf chain of send data. If this is a timer expiration 77121054Semax * (called from the software clock routine), then timertype tells which timer. 78121054Semax */ 79121054Semax/*ARGSUSED*/ 80121054Semaxint 81121054Semaxtcp_usrreq(so, req, m, nam, control) 82121054Semax struct socket *so; 83121054Semax int req; 84121054Semax struct mbuf *m, *nam, *control; 85121054Semax{ 86121054Semax register struct inpcb *inp; 87121054Semax register struct tcpcb *tp = 0; 88121054Semax struct sockaddr_in *sinp; 89121054Semax int s; 90121054Semax int error = 0; 91121054Semax#ifdef TCPDEBUG 92121054Semax int ostate; 93121054Semax#endif 94121054Semax 95121054Semax if (req == PRU_CONTROL) 96121054Semax return (in_control(so, (u_long)m, (caddr_t)nam, 97121054Semax (struct ifnet *)control)); 98121054Semax if (control && control->m_len) { 99121054Semax m_freem(control); 100121054Semax if (m) 101121054Semax m_freem(m); 102121054Semax return (EINVAL); 103121054Semax } 104121054Semax 105121054Semax s = splnet(); 106121054Semax inp = sotoinpcb(so); 107121054Semax /* 108121054Semax * When a TCP is attached to a socket, then there will be 109121054Semax * a (struct inpcb) pointed at by the socket, and this 110121054Semax * structure will point at a subsidary (struct tcpcb). 111121054Semax */ 112121054Semax if (inp == 0 && req != PRU_ATTACH) { 113121054Semax splx(s); 114121054Semax#if 0 115121054Semax /* 116121054Semax * The following corrects an mbuf leak under rare 117121054Semax * circumstances, but has not been fully tested. 118121054Semax */ 119121054Semax if (m && req != PRU_SENSE) 120121054Semax m_freem(m); 121121054Semax#else 122121054Semax /* safer version of fix for mbuf leak */ 123121054Semax if (m && (req == PRU_SEND || req == PRU_SENDOOB)) 124121054Semax m_freem(m); 125121054Semax#endif 126121054Semax return (EINVAL); /* XXX */ 127121054Semax } 128121054Semax if (inp) { 129121054Semax tp = intotcpcb(inp); 130121054Semax /* WHAT IF TP IS 0? */ 131121054Semax#ifdef KPROF 132121054Semax tcp_acounts[tp->t_state][req]++; 133121054Semax#endif 134121054Semax#ifdef TCPDEBUG 135121054Semax ostate = tp->t_state; 136121054Semax } else 137121054Semax ostate = 0; 138121054Semax#else /* TCPDEBUG */ 139121054Semax } 140121054Semax#endif /* TCPDEBUG */ 141121054Semax 142121054Semax switch (req) { 143 144 /* 145 * TCP attaches to socket via PRU_ATTACH, reserving space, 146 * and an internet control block. 147 */ 148 case PRU_ATTACH: 149 if (inp) { 150 error = EISCONN; 151 break; 152 } 153 error = tcp_attach(so); 154 if (error) 155 break; 156 if ((so->so_options & SO_LINGER) && so->so_linger == 0) 157 so->so_linger = TCP_LINGERTIME * hz; 158 tp = sototcpcb(so); 159 break; 160 161 /* 162 * PRU_DETACH detaches the TCP protocol from the socket. 163 * If the protocol state is non-embryonic, then can't 164 * do this directly: have to initiate a PRU_DISCONNECT, 165 * which may finish later; embryonic TCB's can just 166 * be discarded here. 167 */ 168 case PRU_DETACH: 169 if (tp->t_state > TCPS_LISTEN) 170 tp = tcp_disconnect(tp); 171 else 172 tp = tcp_close(tp); 173 break; 174 175 /* 176 * Give the socket an address. 177 */ 178 case PRU_BIND: 179 /* 180 * Must check for multicast addresses and disallow binding 181 * to them. 182 */ 183 sinp = mtod(nam, struct sockaddr_in *); 184 if (sinp->sin_family == AF_INET && 185 IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { 186 error = EAFNOSUPPORT; 187 break; 188 } 189 error = in_pcbbind(inp, nam); 190 if (error) 191 break; 192 break; 193 194 /* 195 * Prepare to accept connections. 196 */ 197 case PRU_LISTEN: 198 if (inp->inp_lport == 0) 199 error = in_pcbbind(inp, NULL); 200 if (error == 0) 201 tp->t_state = TCPS_LISTEN; 202 break; 203 204 /* 205 * Initiate connection to peer. 206 * Create a template for use in transmissions on this connection. 207 * Enter SYN_SENT state, and mark socket as connecting. 208 * Start keep-alive timer, and seed output sequence space. 209 * Send initial segment on connection. 210 */ 211 case PRU_CONNECT: 212 /* 213 * Must disallow TCP ``connections'' to multicast addresses. 214 */ 215 sinp = mtod(nam, struct sockaddr_in *); 216 if (sinp->sin_family == AF_INET 217 && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { 218 error = EAFNOSUPPORT; 219 break; 220 } 221 222 if ((error = tcp_connect(tp, nam)) != 0) 223 break; 224 error = tcp_output(tp); 225 break; 226 227 /* 228 * Create a TCP connection between two sockets. 229 */ 230 case PRU_CONNECT2: 231 error = EOPNOTSUPP; 232 break; 233 234 /* 235 * Initiate disconnect from peer. 236 * If connection never passed embryonic stage, just drop; 237 * else if don't need to let data drain, then can just drop anyways, 238 * else have to begin TCP shutdown process: mark socket disconnecting, 239 * drain unread data, state switch to reflect user close, and 240 * send segment (e.g. FIN) to peer. Socket will be really disconnected 241 * when peer sends FIN and acks ours. 242 * 243 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 244 */ 245 case PRU_DISCONNECT: 246 tp = tcp_disconnect(tp); 247 break; 248 249 /* 250 * Accept a connection. Essentially all the work is 251 * done at higher levels; just return the address 252 * of the peer, storing through addr. 253 */ 254 case PRU_ACCEPT: 255 in_setpeeraddr(inp, nam); 256 break; 257 258 /* 259 * Mark the connection as being incapable of further output. 260 */ 261 case PRU_SHUTDOWN: 262 socantsendmore(so); 263 tp = tcp_usrclosed(tp); 264 if (tp) 265 error = tcp_output(tp); 266 break; 267 268 /* 269 * After a receive, possibly send window update to peer. 270 */ 271 case PRU_RCVD: 272 (void) tcp_output(tp); 273 break; 274 275 /* 276 * Do a send by putting data in output queue and updating urgent 277 * marker if URG set. Possibly send more data. 278 */ 279 case PRU_SEND_EOF: 280 case PRU_SEND: 281 sbappend(&so->so_snd, m); 282 if (nam && tp->t_state < TCPS_SYN_SENT) { 283 /* 284 * Do implied connect if not yet connected, 285 * initialize window to default value, and 286 * initialize maxseg/maxopd using peer's cached 287 * MSS. 288 */ 289 error = tcp_connect(tp, nam); 290 if (error) 291 break; 292 tp->snd_wnd = TTCP_CLIENT_SND_WND; 293 tcp_mss(tp, -1); 294 } 295 296 if (req == PRU_SEND_EOF) { 297 /* 298 * Close the send side of the connection after 299 * the data is sent. 300 */ 301 socantsendmore(so); 302 tp = tcp_usrclosed(tp); 303 } 304 if (tp != NULL) 305 error = tcp_output(tp); 306 break; 307 308 /* 309 * Abort the TCP. 310 */ 311 case PRU_ABORT: 312 tp = tcp_drop(tp, ECONNABORTED); 313 break; 314 315 case PRU_SENSE: 316 ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 317 (void) splx(s); 318 return (0); 319 320 case PRU_RCVOOB: 321 if ((so->so_oobmark == 0 && 322 (so->so_state & SS_RCVATMARK) == 0) || 323 so->so_options & SO_OOBINLINE || 324 tp->t_oobflags & TCPOOB_HADDATA) { 325 error = EINVAL; 326 break; 327 } 328 if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { 329 error = EWOULDBLOCK; 330 break; 331 } 332 m->m_len = 1; 333 *mtod(m, caddr_t) = tp->t_iobc; 334 if (((int)nam & MSG_PEEK) == 0) 335 tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA); 336 break; 337 338 case PRU_SENDOOB: 339 if (sbspace(&so->so_snd) < -512) { 340 m_freem(m); 341 error = ENOBUFS; 342 break; 343 } 344 /* 345 * According to RFC961 (Assigned Protocols), 346 * the urgent pointer points to the last octet 347 * of urgent data. We continue, however, 348 * to consider it to indicate the first octet 349 * of data past the urgent section. 350 * Otherwise, snd_up should be one lower. 351 */ 352 sbappend(&so->so_snd, m); 353 tp->snd_up = tp->snd_una + so->so_snd.sb_cc; 354 tp->t_force = 1; 355 error = tcp_output(tp); 356 tp->t_force = 0; 357 break; 358 359 case PRU_SOCKADDR: 360 in_setsockaddr(inp, nam); 361 break; 362 363 case PRU_PEERADDR: 364 in_setpeeraddr(inp, nam); 365 break; 366 367 /* 368 * TCP slow timer went off; going through this 369 * routine for tracing's sake. 370 */ 371 case PRU_SLOWTIMO: 372 tp = tcp_timers(tp, (int)nam); 373#ifdef TCPDEBUG 374 req |= (int)nam << 8; /* for debug's sake */ 375#endif 376 break; 377 378 default: 379 panic("tcp_usrreq"); 380 } 381#ifdef TCPDEBUG 382 if (tp && (so->so_options & SO_DEBUG)) 383 tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 384#endif 385 splx(s); 386 return (error); 387} 388 389/* 390 * Common subroutine to open a TCP connection to remote host specified 391 * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local 392 * port number if needed. Call in_pcbladdr to do the routing and to choose 393 * a local host address (interface). If there is an existing incarnation 394 * of the same connection in TIME-WAIT state and if the remote host was 395 * sending CC options and if the connection duration was < MSL, then 396 * truncate the previous TIME-WAIT state and proceed. 397 * Initialize connection parameters and enter SYN-SENT state. 398 */ 399int 400tcp_connect(tp, nam) 401 register struct tcpcb *tp; 402 struct mbuf *nam; 403{ 404 struct inpcb *inp = tp->t_inpcb, *oinp; 405 struct socket *so = inp->inp_socket; 406 struct tcpcb *otp; 407 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 408 struct sockaddr_in *ifaddr; 409 int error; 410 411 if (inp->inp_lport == 0) { 412 error = in_pcbbind(inp, NULL); 413 if (error) 414 return error; 415 } 416 417 /* 418 * Cannot simply call in_pcbconnect, because there might be an 419 * earlier incarnation of this same connection still in 420 * TIME_WAIT state, creating an ADDRINUSE error. 421 */ 422 error = in_pcbladdr(inp, nam, &ifaddr); 423 if (error) 424 return error; 425 oinp = in_pcblookup(inp->inp_pcbinfo->listhead, 426 sin->sin_addr, sin->sin_port, 427 inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr 428 : ifaddr->sin_addr, 429 inp->inp_lport, 0); 430 if (oinp) { 431 if (oinp != inp && (otp = intotcpcb(oinp)) != NULL && 432 otp->t_state == TCPS_TIME_WAIT && 433 otp->t_duration < TCPTV_MSL && 434 (otp->t_flags & TF_RCVD_CC)) 435 otp = tcp_close(otp); 436 else 437 return EADDRINUSE; 438 } 439 if (inp->inp_laddr.s_addr == INADDR_ANY) 440 inp->inp_laddr = ifaddr->sin_addr; 441 inp->inp_faddr = sin->sin_addr; 442 inp->inp_fport = sin->sin_port; 443 in_pcbrehash(inp); 444 445 tp->t_template = tcp_template(tp); 446 if (tp->t_template == 0) { 447 in_pcbdisconnect(inp); 448 return ENOBUFS; 449 } 450 451 /* Compute window scaling to request. */ 452 while (tp->request_r_scale < TCP_MAX_WINSHIFT && 453 (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) 454 tp->request_r_scale++; 455 456 soisconnecting(so); 457 tcpstat.tcps_connattempt++; 458 tp->t_state = TCPS_SYN_SENT; 459 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; 460 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 461 tcp_sendseqinit(tp); 462 tp->cc_send = CC_INC(tcp_ccgen); 463 464 return 0; 465} 466 467int 468tcp_ctloutput(op, so, level, optname, mp) 469 int op; 470 struct socket *so; 471 int level, optname; 472 struct mbuf **mp; 473{ 474 int error = 0, s; 475 struct inpcb *inp; 476 register struct tcpcb *tp; 477 register struct mbuf *m; 478 register int i; 479 480 s = splnet(); 481 inp = sotoinpcb(so); 482 if (inp == NULL) { 483 splx(s); 484 if (op == PRCO_SETOPT && *mp) 485 (void) m_free(*mp); 486 return (ECONNRESET); 487 } 488 if (level != IPPROTO_TCP) { 489 error = ip_ctloutput(op, so, level, optname, mp); 490 splx(s); 491 return (error); 492 } 493 tp = intotcpcb(inp); 494 495 switch (op) { 496 497 case PRCO_SETOPT: 498 m = *mp; 499 switch (optname) { 500 501 case TCP_NODELAY: 502 if (m == NULL || m->m_len < sizeof (int)) 503 error = EINVAL; 504 else if (*mtod(m, int *)) 505 tp->t_flags |= TF_NODELAY; 506 else 507 tp->t_flags &= ~TF_NODELAY; 508 break; 509 510 case TCP_MAXSEG: 511 if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg) 512 tp->t_maxseg = i; 513 else 514 error = EINVAL; 515 break; 516 517 case TCP_NOOPT: 518 if (m == NULL || m->m_len < sizeof (int)) 519 error = EINVAL; 520 else if (*mtod(m, int *)) 521 tp->t_flags |= TF_NOOPT; 522 else 523 tp->t_flags &= ~TF_NOOPT; 524 break; 525 526 case TCP_NOPUSH: 527 if (m == NULL || m->m_len < sizeof (int)) 528 error = EINVAL; 529 else if (*mtod(m, int *)) 530 tp->t_flags |= TF_NOPUSH; 531 else 532 tp->t_flags &= ~TF_NOPUSH; 533 break; 534 535 default: 536 error = ENOPROTOOPT; 537 break; 538 } 539 if (m) 540 (void) m_free(m); 541 break; 542 543 case PRCO_GETOPT: 544 *mp = m = m_get(M_WAIT, MT_SOOPTS); 545 m->m_len = sizeof(int); 546 547 switch (optname) { 548 case TCP_NODELAY: 549 *mtod(m, int *) = tp->t_flags & TF_NODELAY; 550 break; 551 case TCP_MAXSEG: 552 *mtod(m, int *) = tp->t_maxseg; 553 break; 554 case TCP_NOOPT: 555 *mtod(m, int *) = tp->t_flags & TF_NOOPT; 556 break; 557 case TCP_NOPUSH: 558 *mtod(m, int *) = tp->t_flags & TF_NOPUSH; 559 break; 560 default: 561 error = ENOPROTOOPT; 562 break; 563 } 564 break; 565 } 566 splx(s); 567 return (error); 568} 569 570/* 571 * tcp_sendspace and tcp_recvspace are the default send and receive window 572 * sizes, respectively. These are obsolescent (this information should 573 * be set by the route). 574 */ 575u_long tcp_sendspace = 1024*16; 576u_long tcp_recvspace = 1024*16; 577 578/* 579 * Attach TCP protocol to socket, allocating 580 * internet protocol control block, tcp control block, 581 * bufer space, and entering LISTEN state if to accept connections. 582 */ 583int 584tcp_attach(so) 585 struct socket *so; 586{ 587 register struct tcpcb *tp; 588 struct inpcb *inp; 589 int error; 590 591 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 592 error = soreserve(so, tcp_sendspace, tcp_recvspace); 593 if (error) 594 return (error); 595 } 596 error = in_pcballoc(so, &tcbinfo); 597 if (error) 598 return (error); 599 inp = sotoinpcb(so); 600 tp = tcp_newtcpcb(inp); 601 if (tp == 0) { 602 int nofd = so->so_state & SS_NOFDREF; /* XXX */ 603 604 so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */ 605 in_pcbdetach(inp); 606 so->so_state |= nofd; 607 return (ENOBUFS); 608 } 609 tp->t_state = TCPS_CLOSED; 610 return (0); 611} 612 613/* 614 * Initiate (or continue) disconnect. 615 * If embryonic state, just send reset (once). 616 * If in ``let data drain'' option and linger null, just drop. 617 * Otherwise (hard), mark socket disconnecting and drop 618 * current input data; switch states based on user close, and 619 * send segment to peer (with FIN). 620 */ 621struct tcpcb * 622tcp_disconnect(tp) 623 register struct tcpcb *tp; 624{ 625 struct socket *so = tp->t_inpcb->inp_socket; 626 627 if (tp->t_state < TCPS_ESTABLISHED) 628 tp = tcp_close(tp); 629 else if ((so->so_options & SO_LINGER) && so->so_linger == 0) 630 tp = tcp_drop(tp, 0); 631 else { 632 soisdisconnecting(so); 633 sbflush(&so->so_rcv); 634 tp = tcp_usrclosed(tp); 635 if (tp) 636 (void) tcp_output(tp); 637 } 638 return (tp); 639} 640 641/* 642 * User issued close, and wish to trail through shutdown states: 643 * if never received SYN, just forget it. If got a SYN from peer, 644 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. 645 * If already got a FIN from peer, then almost done; go to LAST_ACK 646 * state. In all other cases, have already sent FIN to peer (e.g. 647 * after PRU_SHUTDOWN), and just have to play tedious game waiting 648 * for peer to send FIN or not respond to keep-alives, etc. 649 * We can let the user exit from the close as soon as the FIN is acked. 650 */ 651struct tcpcb * 652tcp_usrclosed(tp) 653 register struct tcpcb *tp; 654{ 655 656 switch (tp->t_state) { 657 658 case TCPS_CLOSED: 659 case TCPS_LISTEN: 660 tp->t_state = TCPS_CLOSED; 661 tp = tcp_close(tp); 662 break; 663 664 case TCPS_SYN_SENT: 665 case TCPS_SYN_RECEIVED: 666 tp->t_flags |= TF_NEEDFIN; 667 break; 668 669 case TCPS_ESTABLISHED: 670 tp->t_state = TCPS_FIN_WAIT_1; 671 break; 672 673 case TCPS_CLOSE_WAIT: 674 tp->t_state = TCPS_LAST_ACK; 675 break; 676 } 677 if (tp && tp->t_state >= TCPS_FIN_WAIT_2) { 678 soisdisconnected(tp->t_inpcb->inp_socket); 679 /* To prevent the connection hanging in FIN_WAIT_2 forever. */ 680 if (tp->t_state == TCPS_FIN_WAIT_2) 681 tp->t_timer[TCPT_2MSL] = tcp_maxidle; 682 } 683 return (tp); 684} 685 686/* 687 * Sysctl for tcp variables. 688 */ 689int 690tcp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 691 int *name; 692 u_int namelen; 693 void *oldp; 694 size_t *oldlenp; 695 void *newp; 696 size_t newlen; 697{ 698 /* All sysctl names at this level are terminal. */ 699 if (namelen != 1) 700 return (ENOTDIR); 701 702 switch (name[0]) { 703 case TCPCTL_DO_RFC1323: 704 return (sysctl_int(oldp, oldlenp, newp, newlen, 705 &tcp_do_rfc1323)); 706 case TCPCTL_DO_RFC1644: 707 return (sysctl_int(oldp, oldlenp, newp, newlen, 708 &tcp_do_rfc1644)); 709 case TCPCTL_MSSDFLT: 710 return (sysctl_int(oldp, oldlenp, newp, newlen, 711 &tcp_mssdflt)); 712 case TCPCTL_STATS: 713 return (sysctl_rdstruct(oldp, oldlenp, newp, &tcpstat, 714 sizeof tcpstat)); 715 case TCPCTL_RTTDFLT: 716 return (sysctl_int(oldp, oldlenp, newp, newlen, &tcp_rttdflt)); 717 case TCPCTL_KEEPIDLE: 718 return (sysctl_int(oldp, oldlenp, newp, newlen, 719 &tcp_keepidle)); 720 case TCPCTL_KEEPINTVL: 721 return (sysctl_int(oldp, oldlenp, newp, newlen, 722 &tcp_keepintvl)); 723 case TCPCTL_SENDSPACE: 724 return (sysctl_int(oldp, oldlenp, newp, newlen, 725 (int *)&tcp_sendspace)); /* XXX */ 726 case TCPCTL_RECVSPACE: 727 return (sysctl_int(oldp, oldlenp, newp, newlen, 728 (int *)&tcp_recvspace)); /* XXX */ 729 default: 730 return (ENOPROTOOPT); 731 } 732 /* NOTREACHED */ 733} 734