c283b2068fb86bcfa38c6fb2e93670bc88f1057f
[reactos.git] / reactos / drivers / lib / oskittcp / oskittcp / tcp_usrreq.c
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/protosw.h>
44 #include <sys/errno.h>
45 #include <sys/stat.h>
46 #include <vm/vm.h>
47 #include <sys/sysctl.h>
48
49 #include <net/if.h>
50 #include <net/route.h>
51
52 #include <netinet/in.h>
53 #include <netinet/in_systm.h>
54 #include <netinet/ip.h>
55 #include <netinet/in_pcb.h>
56 #include <netinet/in_var.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/tcp.h>
59 #include <netinet/tcp_fsm.h>
60 #include <netinet/tcp_seq.h>
61 #include <netinet/tcp_timer.h>
62 #include <netinet/tcp_var.h>
63 #include <netinet/tcpip.h>
64 #ifdef TCPDEBUG
65 #include <netinet/tcp_debug.h>
66 #endif
67
68 /*
69 * TCP protocol interface to socket abstraction.
70 */
71 extern char *tcpstates[];
72
73 /*
74 * Process a TCP user request for TCP tb. If this is a send request
75 * then m is the mbuf chain of send data. If this is a timer expiration
76 * (called from the software clock routine), then timertype tells which timer.
77 */
78 /*ARGSUSED*/
79 int
80 tcp_usrreq(so, req, m, nam, control)
81 struct socket *so;
82 int req;
83 struct mbuf *m, *nam, *control;
84 {
85 register struct inpcb *inp;
86 register struct tcpcb *tp = 0;
87 struct sockaddr_in *sinp;
88 int s;
89 int error = 0;
90 #ifdef TCPDEBUG
91 int ostate;
92 #endif
93
94 if (req == PRU_CONTROL)
95 return (in_control(so, (u_long)m, (caddr_t)nam,
96 (struct ifnet *)control));
97 if (control && control->m_len) {
98 m_freem(control);
99 if (m)
100 m_freem(m);
101 return (EINVAL);
102 }
103
104 s = splnet();
105 inp = sotoinpcb(so);
106 /*
107 * When a TCP is attached to a socket, then there will be
108 * a (struct inpcb) pointed at by the socket, and this
109 * structure will point at a subsidary (struct tcpcb).
110 */
111 if (inp == 0 && req != PRU_ATTACH) {
112 splx(s);
113 #if 0
114 /*
115 * The following corrects an mbuf leak under rare
116 * circumstances, but has not been fully tested.
117 */
118 if (m && req != PRU_SENSE)
119 m_freem(m);
120 #else
121 /* safer version of fix for mbuf leak */
122 if (m && (req == PRU_SEND || req == PRU_SENDOOB))
123 m_freem(m);
124 #endif
125 return (EINVAL); /* XXX */
126 }
127 if (inp) {
128 tp = intotcpcb(inp);
129 /* WHAT IF TP IS 0? */
130 #ifdef KPROF
131 tcp_acounts[tp->t_state][req]++;
132 #endif
133 #ifdef TCPDEBUG
134 ostate = tp->t_state;
135 } else
136 ostate = 0;
137 #else /* TCPDEBUG */
138 }
139 #endif /* TCPDEBUG */
140
141 switch (req) {
142
143 /*
144 * TCP attaches to socket via PRU_ATTACH, reserving space,
145 * and an internet control block.
146 */
147 case PRU_ATTACH:
148 if (inp) {
149 error = EISCONN;
150 break;
151 }
152 error = tcp_attach(so);
153 if (error)
154 break;
155 if ((so->so_options & SO_LINGER) && so->so_linger == 0)
156 so->so_linger = TCP_LINGERTIME * hz;
157 tp = sototcpcb(so);
158 break;
159
160 /*
161 * PRU_DETACH detaches the TCP protocol from the socket.
162 * If the protocol state is non-embryonic, then can't
163 * do this directly: have to initiate a PRU_DISCONNECT,
164 * which may finish later; embryonic TCB's can just
165 * be discarded here.
166 */
167 case PRU_DETACH:
168 if (tp->t_state > TCPS_LISTEN)
169 tp = tcp_disconnect(tp);
170 else
171 tp = tcp_close(tp);
172 break;
173
174 /*
175 * Give the socket an address.
176 */
177 case PRU_BIND:
178 /*
179 * Must check for multicast addresses and disallow binding
180 * to them.
181 */
182 sinp = mtod(nam, struct sockaddr_in *);
183 if (sinp->sin_family == AF_INET &&
184 IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
185 error = EAFNOSUPPORT;
186 break;
187 }
188 error = in_pcbbind(inp, nam);
189 if (error)
190 break;
191 break;
192
193 /*
194 * Prepare to accept connections.
195 */
196 case PRU_LISTEN:
197 if (inp->inp_lport == 0)
198 error = in_pcbbind(inp, NULL);
199 if (error == 0)
200 tp->t_state = TCPS_LISTEN;
201 break;
202
203 /*
204 * Initiate connection to peer.
205 * Create a template for use in transmissions on this connection.
206 * Enter SYN_SENT state, and mark socket as connecting.
207 * Start keep-alive timer, and seed output sequence space.
208 * Send initial segment on connection.
209 */
210 case PRU_CONNECT:
211 /*
212 * Must disallow TCP ``connections'' to multicast addresses.
213 */
214 sinp = mtod(nam, struct sockaddr_in *);
215 if (sinp->sin_family == AF_INET
216 && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
217 error = EAFNOSUPPORT;
218 break;
219 }
220
221 if ((error = tcp_connect(tp, nam)) != 0)
222 break;
223 error = tcp_output(tp);
224 break;
225
226 /*
227 * Create a TCP connection between two sockets.
228 */
229 case PRU_CONNECT2:
230 error = EOPNOTSUPP;
231 break;
232
233 /*
234 * Initiate disconnect from peer.
235 * If connection never passed embryonic stage, just drop;
236 * else if don't need to let data drain, then can just drop anyways,
237 * else have to begin TCP shutdown process: mark socket disconnecting,
238 * drain unread data, state switch to reflect user close, and
239 * send segment (e.g. FIN) to peer. Socket will be really disconnected
240 * when peer sends FIN and acks ours.
241 *
242 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
243 */
244 case PRU_DISCONNECT:
245 tp = tcp_disconnect(tp);
246 break;
247
248 /*
249 * Accept a connection. Essentially all the work is
250 * done at higher levels; just return the address
251 * of the peer, storing through addr.
252 */
253 case PRU_ACCEPT:
254 in_setpeeraddr(inp, nam);
255 break;
256
257 /*
258 * Mark the connection as being incapable of further output.
259 */
260 case PRU_SHUTDOWN:
261 socantsendmore(so);
262 tp = tcp_usrclosed(tp);
263 if (tp)
264 error = tcp_output(tp);
265 break;
266
267 /*
268 * After a receive, possibly send window update to peer.
269 */
270 case PRU_RCVD:
271 (void) tcp_output(tp);
272 break;
273
274 /*
275 * Do a send by putting data in output queue and updating urgent
276 * marker if URG set. Possibly send more data.
277 */
278 case PRU_SEND_EOF:
279 case PRU_SEND:
280 sbappend(&so->so_snd, m);
281 if (nam && tp->t_state < TCPS_SYN_SENT) {
282 /*
283 * Do implied connect if not yet connected,
284 * initialize window to default value, and
285 * initialize maxseg/maxopd using peer's cached
286 * MSS.
287 */
288 error = tcp_connect(tp, nam);
289 if (error)
290 break;
291 tp->snd_wnd = TTCP_CLIENT_SND_WND;
292 tcp_mss(tp, -1);
293 }
294
295 if (req == PRU_SEND_EOF) {
296 /*
297 * Close the send side of the connection after
298 * the data is sent.
299 */
300 socantsendmore(so);
301 tp = tcp_usrclosed(tp);
302 }
303 if (tp != NULL)
304 error = tcp_output(tp);
305 break;
306
307 /*
308 * Abort the TCP.
309 */
310 case PRU_ABORT:
311 tp = tcp_drop(tp, ECONNABORTED);
312 break;
313
314 case PRU_SENSE:
315 ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
316 (void) splx(s);
317 return (0);
318
319 case PRU_RCVOOB:
320 if ((so->so_oobmark == 0 &&
321 (so->so_state & SS_RCVATMARK) == 0) ||
322 so->so_options & SO_OOBINLINE ||
323 tp->t_oobflags & TCPOOB_HADDATA) {
324 error = EINVAL;
325 break;
326 }
327 if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
328 error = EWOULDBLOCK;
329 break;
330 }
331 m->m_len = 1;
332 *mtod(m, caddr_t) = tp->t_iobc;
333 if (((int)nam & MSG_PEEK) == 0)
334 tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
335 break;
336
337 case PRU_SENDOOB:
338 if (sbspace(&so->so_snd) < -512) {
339 m_freem(m);
340 error = ENOBUFS;
341 break;
342 }
343 /*
344 * According to RFC961 (Assigned Protocols),
345 * the urgent pointer points to the last octet
346 * of urgent data. We continue, however,
347 * to consider it to indicate the first octet
348 * of data past the urgent section.
349 * Otherwise, snd_up should be one lower.
350 */
351 sbappend(&so->so_snd, m);
352 if (nam && tp->t_state < TCPS_SYN_SENT) {
353 /*
354 * Do implied connect if not yet connected,
355 * initialize window to default value, and
356 * initialize maxseg/maxopd using peer's cached
357 * MSS.
358 */
359 error = tcp_connect(tp, nam);
360 if (error)
361 break;
362 tp->snd_wnd = TTCP_CLIENT_SND_WND;
363 tcp_mss(tp, -1);
364 }
365 tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
366 tp->t_force = 1;
367 error = tcp_output(tp);
368 tp->t_force = 0;
369 break;
370
371 case PRU_SOCKADDR:
372 in_setsockaddr(inp, nam);
373 break;
374
375 case PRU_PEERADDR:
376 in_setpeeraddr(inp, nam);
377 break;
378
379 /*
380 * TCP slow timer went off; going through this
381 * routine for tracing's sake.
382 */
383 case PRU_SLOWTIMO:
384 tp = tcp_timers(tp, (int)nam);
385 #ifdef TCPDEBUG
386 req |= (int)nam << 8; /* for debug's sake */
387 #endif
388 break;
389
390 default:
391 panic("tcp_usrreq");
392 }
393 #ifdef TCPDEBUG
394 if (tp && (so->so_options & SO_DEBUG))
395 tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
396 #endif
397 splx(s);
398 return (error);
399 }
400
401 /*
402 * Common subroutine to open a TCP connection to remote host specified
403 * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local
404 * port number if needed. Call in_pcbladdr to do the routing and to choose
405 * a local host address (interface). If there is an existing incarnation
406 * of the same connection in TIME-WAIT state and if the remote host was
407 * sending CC options and if the connection duration was < MSL, then
408 * truncate the previous TIME-WAIT state and proceed.
409 * Initialize connection parameters and enter SYN-SENT state.
410 */
411 int
412 tcp_connect(tp, nam)
413 register struct tcpcb *tp;
414 struct mbuf *nam;
415 {
416 struct inpcb *inp = tp->t_inpcb, *oinp;
417 struct socket *so = inp->inp_socket;
418 struct tcpcb *otp;
419 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
420 struct sockaddr_in *ifaddr;
421 int error;
422 struct rmxp_tao *taop;
423 struct rmxp_tao tao_noncached;
424
425 OS_DbgPrint(OSK_MID_TRACE,("Called\n"));
426
427 if (inp->inp_lport == 0) {
428 error = in_pcbbind(inp, NULL);
429 if (error)
430 return error;
431 }
432
433 /*
434 * Cannot simply call in_pcbconnect, because there might be an
435 * earlier incarnation of this same connection still in
436 * TIME_WAIT state, creating an ADDRINUSE error.
437 */
438 error = in_pcbladdr(inp, nam, &ifaddr);
439 if (error) {
440 OS_DbgPrint(OSK_MID_TRACE,("leaving %d\n", error));
441 return error;
442 }
443 oinp = in_pcblookup(inp->inp_pcbinfo->listhead,
444 sin->sin_addr, sin->sin_port,
445 inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
446 : ifaddr->sin_addr,
447 inp->inp_lport, 0);
448 if (oinp) {
449 if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
450 otp->t_state == TCPS_TIME_WAIT &&
451 otp->t_duration < TCPTV_MSL &&
452 (otp->t_flags & TF_RCVD_CC))
453 otp = tcp_close(otp);
454 else {
455 OS_DbgPrint(OSK_MID_TRACE,("leaving EADDRINUSE\n"));
456 return EADDRINUSE;
457 }
458 }
459 if (inp->inp_laddr.s_addr == INADDR_ANY)
460 inp->inp_laddr = ifaddr->sin_addr;
461 inp->inp_faddr = sin->sin_addr;
462 inp->inp_fport = sin->sin_port;
463 in_pcbrehash(inp);
464
465 tp->t_template = tcp_template(tp);
466 if (tp->t_template == 0) {
467 in_pcbdisconnect(inp);
468 OS_DbgPrint(OSK_MID_TRACE,("Leaving ENOBUFS\n"));
469 return ENOBUFS;
470 }
471
472 /* Compute window scaling to request. */
473 while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
474 (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
475 tp->request_r_scale++;
476
477 soisconnecting(so);
478 tcpstat.tcps_connattempt++;
479 tp->t_state = TCPS_SYN_SENT;
480 tp->t_timer[TCPT_KEEP] = tcp_keepinit;
481 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
482 tcp_sendseqinit(tp);
483
484 /*
485 * Generate a CC value for this connection and
486 * check whether CC or CCnew should be used.
487 */
488 if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
489 taop = &tao_noncached;
490 bzero(taop, sizeof(*taop));
491 }
492
493 tp->cc_send = CC_INC(tcp_ccgen);
494 if (taop->tao_ccsent != 0 &&
495 CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
496 taop->tao_ccsent = tp->cc_send;
497 } else {
498 taop->tao_ccsent = 0;
499 tp->t_flags |= TF_SENDCCNEW;
500 }
501
502 OS_DbgPrint(OSK_MID_TRACE,("Leaving 0\n"));
503 return 0;
504 }
505
506 int
507 tcp_ctloutput(op, so, level, optname, mp)
508 int op;
509 struct socket *so;
510 int level, optname;
511 struct mbuf **mp;
512 {
513 int error = 0, s;
514 struct inpcb *inp;
515 register struct tcpcb *tp;
516 register struct mbuf *m;
517 register int i;
518
519 s = splnet();
520 inp = sotoinpcb(so);
521 if (inp == NULL) {
522 splx(s);
523 if (op == PRCO_SETOPT && *mp)
524 (void) m_free(*mp);
525 return (ECONNRESET);
526 }
527 if (level != IPPROTO_TCP) {
528 error = ip_ctloutput(op, so, level, optname, mp);
529 splx(s);
530 return (error);
531 }
532 tp = intotcpcb(inp);
533
534 switch (op) {
535
536 case PRCO_SETOPT:
537 m = *mp;
538 switch (optname) {
539
540 case TCP_NODELAY:
541 if (m == NULL || m->m_len < sizeof (int))
542 error = EINVAL;
543 else if (*mtod(m, int *))
544 tp->t_flags |= TF_NODELAY;
545 else
546 tp->t_flags &= ~TF_NODELAY;
547 break;
548
549 case TCP_MAXSEG:
550 if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg)
551 tp->t_maxseg = i;
552 else
553 error = EINVAL;
554 break;
555
556 case TCP_NOOPT:
557 if (m == NULL || m->m_len < sizeof (int))
558 error = EINVAL;
559 else if (*mtod(m, int *))
560 tp->t_flags |= TF_NOOPT;
561 else
562 tp->t_flags &= ~TF_NOOPT;
563 break;
564
565 case TCP_NOPUSH:
566 if (m == NULL || m->m_len < sizeof (int))
567 error = EINVAL;
568 else if (*mtod(m, int *))
569 tp->t_flags |= TF_NOPUSH;
570 else
571 tp->t_flags &= ~TF_NOPUSH;
572 break;
573
574 default:
575 error = ENOPROTOOPT;
576 break;
577 }
578 if (m)
579 (void) m_free(m);
580 break;
581
582 case PRCO_GETOPT:
583 *mp = m = m_get(M_WAIT, MT_SOOPTS);
584 m->m_len = sizeof(int);
585
586 switch (optname) {
587 case TCP_NODELAY:
588 *mtod(m, int *) = tp->t_flags & TF_NODELAY;
589 break;
590 case TCP_MAXSEG:
591 *mtod(m, int *) = tp->t_maxseg;
592 break;
593 case TCP_NOOPT:
594 *mtod(m, int *) = tp->t_flags & TF_NOOPT;
595 break;
596 case TCP_NOPUSH:
597 *mtod(m, int *) = tp->t_flags & TF_NOPUSH;
598 break;
599 default:
600 error = ENOPROTOOPT;
601 break;
602 }
603 break;
604 }
605 splx(s);
606 return (error);
607 }
608
609 /*
610 * tcp_sendspace and tcp_recvspace are the default send and receive window
611 * sizes, respectively. These are obsolescent (this information should
612 * be set by the route).
613 */
614 u_long tcp_sendspace = 1024*16;
615 u_long tcp_recvspace = 1024*16;
616
617 /*
618 * Attach TCP protocol to socket, allocating
619 * internet protocol control block, tcp control block,
620 * bufer space, and entering LISTEN state if to accept connections.
621 */
622 int
623 tcp_attach(so)
624 struct socket *so;
625 {
626 register struct tcpcb *tp;
627 struct inpcb *inp;
628 int error;
629
630 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
631 error = soreserve(so, tcp_sendspace, tcp_recvspace);
632 if (error)
633 return (error);
634 }
635 error = in_pcballoc(so, &tcbinfo);
636 if (error)
637 return (error);
638 inp = sotoinpcb(so);
639 tp = tcp_newtcpcb(inp);
640 if (tp == 0) {
641 int nofd = so->so_state & SS_NOFDREF; /* XXX */
642
643 so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */
644 in_pcbdetach(inp);
645 so->so_state |= nofd;
646 return (ENOBUFS);
647 }
648 tp->t_state = TCPS_CLOSED;
649 return (0);
650 }
651
652 /*
653 * Initiate (or continue) disconnect.
654 * If embryonic state, just send reset (once).
655 * If in ``let data drain'' option and linger null, just drop.
656 * Otherwise (hard), mark socket disconnecting and drop
657 * current input data; switch states based on user close, and
658 * send segment to peer (with FIN).
659 */
660 struct tcpcb *
661 tcp_disconnect(tp)
662 register struct tcpcb *tp;
663 {
664 struct socket *so = tp->t_inpcb->inp_socket;
665
666 if (tp->t_state < TCPS_ESTABLISHED)
667 tp = tcp_close(tp);
668 else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
669 tp = tcp_drop(tp, 0);
670 else {
671 soisdisconnecting(so);
672 sbflush(&so->so_rcv);
673 tp = tcp_usrclosed(tp);
674 if (tp)
675 (void) tcp_output(tp);
676 }
677 return (tp);
678 }
679
680 /*
681 * User issued close, and wish to trail through shutdown states:
682 * if never received SYN, just forget it. If got a SYN from peer,
683 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
684 * If already got a FIN from peer, then almost done; go to LAST_ACK
685 * state. In all other cases, have already sent FIN to peer (e.g.
686 * after PRU_SHUTDOWN), and just have to play tedious game waiting
687 * for peer to send FIN or not respond to keep-alives, etc.
688 * We can let the user exit from the close as soon as the FIN is acked.
689 */
690 struct tcpcb *
691 tcp_usrclosed(tp)
692 register struct tcpcb *tp;
693 {
694
695 switch (tp->t_state) {
696
697 case TCPS_CLOSED:
698 case TCPS_LISTEN:
699 tp->t_state = TCPS_CLOSED;
700 tp = tcp_close(tp);
701 break;
702
703 case TCPS_SYN_SENT:
704 case TCPS_SYN_RECEIVED:
705 tp->t_flags |= TF_NEEDFIN;
706 break;
707
708 case TCPS_ESTABLISHED:
709 tp->t_state = TCPS_FIN_WAIT_1;
710 break;
711
712 case TCPS_CLOSE_WAIT:
713 tp->t_state = TCPS_LAST_ACK;
714 break;
715 }
716 if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
717 soisdisconnected(tp->t_inpcb->inp_socket);
718 /* To prevent the connection hanging in FIN_WAIT_2 forever. */
719 if (tp->t_state == TCPS_FIN_WAIT_2)
720 tp->t_timer[TCPT_2MSL] = tcp_maxidle;
721 }
722 return (tp);
723 }
724
725 /*
726 * Sysctl for tcp variables.
727 */
728 int
729 tcp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
730 int *name;
731 u_int namelen;
732 void *oldp;
733 size_t *oldlenp;
734 void *newp;
735 size_t newlen;
736 {
737 /* All sysctl names at this level are terminal. */
738 if (namelen != 1)
739 return (ENOTDIR);
740
741 switch (name[0]) {
742 case TCPCTL_DO_RFC1323:
743 return (sysctl_int(oldp, oldlenp, newp, newlen,
744 &tcp_do_rfc1323));
745 case TCPCTL_DO_RFC1644:
746 return (sysctl_int(oldp, oldlenp, newp, newlen,
747 &tcp_do_rfc1644));
748 case TCPCTL_MSSDFLT:
749 return (sysctl_int(oldp, oldlenp, newp, newlen,
750 &tcp_mssdflt));
751 case TCPCTL_STATS:
752 return (sysctl_rdstruct(oldp, oldlenp, newp, &tcpstat,
753 sizeof tcpstat));
754 case TCPCTL_RTTDFLT:
755 return (sysctl_int(oldp, oldlenp, newp, newlen, &tcp_rttdflt));
756 case TCPCTL_KEEPIDLE:
757 return (sysctl_int(oldp, oldlenp, newp, newlen,
758 &tcp_keepidle));
759 case TCPCTL_KEEPINTVL:
760 return (sysctl_int(oldp, oldlenp, newp, newlen,
761 &tcp_keepintvl));
762 case TCPCTL_SENDSPACE:
763 return (sysctl_int(oldp, oldlenp, newp, newlen,
764 (int *)&tcp_sendspace)); /* XXX */
765 case TCPCTL_RECVSPACE:
766 return (sysctl_int(oldp, oldlenp, newp, newlen,
767 (int *)&tcp_recvspace)); /* XXX */
768 case TCPCTL_KEEPINIT:
769 return (sysctl_int(oldp, oldlenp, newp, newlen,
770 &tcp_keepinit));
771 default:
772 return (ENOPROTOOPT);
773 }
774 /* NOTREACHED */
775 }