]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/tcp_timewait.c
Fix ARP in bridging scenarios where the bridge shares its
[FreeBSD/FreeBSD.git] / sys / netinet / tcp_timewait.c
1 /*-
2  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      @(#)tcp_subr.c  8.2 (Berkeley) 5/24/95
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include "opt_inet.h"
36 #include "opt_inet6.h"
37 #include "opt_mac.h"
38 #include "opt_tcpdebug.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/callout.h>
43 #include <sys/kernel.h>
44 #include <sys/sysctl.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/priv.h>
48 #include <sys/proc.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/protosw.h>
52 #include <sys/random.h>
53 #include <sys/vimage.h>
54
55 #include <vm/uma.h>
56
57 #include <net/route.h>
58 #include <net/if.h>
59
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/ip.h>
63 #ifdef INET6
64 #include <netinet/ip6.h>
65 #endif
66 #include <netinet/in_pcb.h>
67 #ifdef INET6
68 #include <netinet6/in6_pcb.h>
69 #endif
70 #include <netinet/in_var.h>
71 #include <netinet/ip_var.h>
72 #ifdef INET6
73 #include <netinet6/ip6_var.h>
74 #include <netinet6/scope6_var.h>
75 #include <netinet6/nd6.h>
76 #endif
77 #include <netinet/ip_icmp.h>
78 #include <netinet/tcp.h>
79 #include <netinet/tcp_fsm.h>
80 #include <netinet/tcp_seq.h>
81 #include <netinet/tcp_timer.h>
82 #include <netinet/tcp_var.h>
83 #ifdef INET6
84 #include <netinet6/tcp6_var.h>
85 #endif
86 #include <netinet/tcpip.h>
87 #ifdef TCPDEBUG
88 #include <netinet/tcp_debug.h>
89 #endif
90 #include <netinet6/ip6protosw.h>
91
92 #include <machine/in_cksum.h>
93
94 #include <security/mac/mac_framework.h>
95
96 static uma_zone_t tcptw_zone;
97 static int      maxtcptw;
98
99 /*
100  * The timed wait queue contains references to each of the TCP sessions
101  * currently in the TIME_WAIT state.  The queue pointers, including the
102  * queue pointers in each tcptw structure, are protected using the global
103  * tcbinfo lock, which must be held over queue iteration and modification.
104  */
105 static TAILQ_HEAD(, tcptw)      twq_2msl;
106
107 static void     tcp_tw_2msl_reset(struct tcptw *, int);
108 static void     tcp_tw_2msl_stop(struct tcptw *);
109
110 static int
111 tcptw_auto_size(void)
112 {
113         int halfrange;
114
115         /*
116          * Max out at half the ephemeral port range so that TIME_WAIT
117          * sockets don't tie up too many ephemeral ports.
118          */
119         if (V_ipport_lastauto > V_ipport_firstauto)
120                 halfrange = (V_ipport_lastauto - V_ipport_firstauto) / 2;
121         else
122                 halfrange = (V_ipport_firstauto - V_ipport_lastauto) / 2;
123         /* Protect against goofy port ranges smaller than 32. */
124         return (imin(imax(halfrange, 32), maxsockets / 5));
125 }
126
127 static int
128 sysctl_maxtcptw(SYSCTL_HANDLER_ARGS)
129 {
130         int error, new;
131
132         if (maxtcptw == 0)
133                 new = tcptw_auto_size();
134         else
135                 new = maxtcptw;
136         error = sysctl_handle_int(oidp, &new, 0, req);
137         if (error == 0 && req->newptr)
138                 if (new >= 32) {
139                         maxtcptw = new;
140                         uma_zone_set_max(tcptw_zone, maxtcptw);
141                 }
142         return (error);
143 }
144
145 SYSCTL_PROC(_net_inet_tcp, OID_AUTO, maxtcptw, CTLTYPE_INT|CTLFLAG_RW,
146     &maxtcptw, 0, sysctl_maxtcptw, "IU",
147     "Maximum number of compressed TCP TIME_WAIT entries");
148
149 static int      nolocaltimewait = 0;
150 SYSCTL_INT(_net_inet_tcp, OID_AUTO, nolocaltimewait, CTLFLAG_RW,
151     &nolocaltimewait, 0,
152     "Do not create compressed TCP TIME_WAIT entries for local connections");
153
154 void
155 tcp_tw_zone_change(void)
156 {
157
158         if (maxtcptw == 0)
159                 uma_zone_set_max(tcptw_zone, tcptw_auto_size());
160 }
161
162 void
163 tcp_tw_init(void)
164 {
165
166         tcptw_zone = uma_zcreate("tcptw", sizeof(struct tcptw),
167             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
168         TUNABLE_INT_FETCH("net.inet.tcp.maxtcptw", &maxtcptw);
169         if (maxtcptw == 0)
170                 uma_zone_set_max(tcptw_zone, tcptw_auto_size());
171         else
172                 uma_zone_set_max(tcptw_zone, maxtcptw);
173         TAILQ_INIT(&V_twq_2msl);
174 }
175
176 /*
177  * Move a TCP connection into TIME_WAIT state.
178  *    tcbinfo is locked.
179  *    inp is locked, and is unlocked before returning.
180  */
181 void
182 tcp_twstart(struct tcpcb *tp)
183 {
184         struct tcptw *tw;
185         struct inpcb *inp = tp->t_inpcb;
186         int acknow;
187         struct socket *so;
188
189         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);      /* tcp_tw_2msl_reset(). */
190         INP_WLOCK_ASSERT(inp);
191
192         if (V_nolocaltimewait && in_localip(inp->inp_faddr)) {
193                 tp = tcp_close(tp);
194                 if (tp != NULL)
195                         INP_WUNLOCK(inp);
196                 return;
197         }
198
199         tw = uma_zalloc(tcptw_zone, M_NOWAIT);
200         if (tw == NULL) {
201                 tw = tcp_tw_2msl_scan(1);
202                 if (tw == NULL) {
203                         tp = tcp_close(tp);
204                         if (tp != NULL)
205                                 INP_WUNLOCK(inp);
206                         return;
207                 }
208         }
209         tw->tw_inpcb = inp;
210
211         /*
212          * Recover last window size sent.
213          */
214         tw->last_win = (tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale;
215
216         /*
217          * Set t_recent if timestamps are used on the connection.
218          */
219         if ((tp->t_flags & (TF_REQ_TSTMP|TF_RCVD_TSTMP|TF_NOOPT)) ==
220             (TF_REQ_TSTMP|TF_RCVD_TSTMP)) {
221                 tw->t_recent = tp->ts_recent;
222                 tw->ts_offset = tp->ts_offset;
223         } else {
224                 tw->t_recent = 0;
225                 tw->ts_offset = 0;
226         }
227
228         tw->snd_nxt = tp->snd_nxt;
229         tw->rcv_nxt = tp->rcv_nxt;
230         tw->iss     = tp->iss;
231         tw->irs     = tp->irs;
232         tw->t_starttime = tp->t_starttime;
233         tw->tw_time = 0;
234
235 /* XXX
236  * If this code will
237  * be used for fin-wait-2 state also, then we may need
238  * a ts_recent from the last segment.
239  */
240         acknow = tp->t_flags & TF_ACKNOW;
241
242         /*
243          * First, discard tcpcb state, which includes stopping its timers and
244          * freeing it.  tcp_discardcb() used to also release the inpcb, but
245          * that work is now done in the caller.
246          *
247          * Note: soisdisconnected() call used to be made in tcp_discardcb(),
248          * and might not be needed here any longer.
249          */
250         tcp_discardcb(tp);
251         so = inp->inp_socket;
252         soisdisconnected(so);
253         tw->tw_cred = crhold(so->so_cred);
254         SOCK_LOCK(so);
255         tw->tw_so_options = so->so_options;
256         SOCK_UNLOCK(so);
257         if (acknow)
258                 tcp_twrespond(tw, TH_ACK);
259         inp->inp_ppcb = tw;
260         inp->inp_vflag |= INP_TIMEWAIT;
261         tcp_tw_2msl_reset(tw, 0);
262
263         /*
264          * If the inpcb owns the sole reference to the socket, then we can
265          * detach and free the socket as it is not needed in time wait.
266          */
267         if (inp->inp_vflag & INP_SOCKREF) {
268                 KASSERT(so->so_state & SS_PROTOREF,
269                     ("tcp_twstart: !SS_PROTOREF"));
270                 inp->inp_vflag &= ~INP_SOCKREF;
271                 INP_WUNLOCK(inp);
272                 ACCEPT_LOCK();
273                 SOCK_LOCK(so);
274                 so->so_state &= ~SS_PROTOREF;
275                 sofree(so);
276         } else
277                 INP_WUNLOCK(inp);
278 }
279
280 #if 0
281 /*
282  * The appromixate rate of ISN increase of Microsoft TCP stacks;
283  * the actual rate is slightly higher due to the addition of
284  * random positive increments.
285  *
286  * Most other new OSes use semi-randomized ISN values, so we
287  * do not need to worry about them.
288  */
289 #define MS_ISN_BYTES_PER_SECOND         250000
290
291 /*
292  * Determine if the ISN we will generate has advanced beyond the last
293  * sequence number used by the previous connection.  If so, indicate
294  * that it is safe to recycle this tw socket by returning 1.
295  */
296 int
297 tcp_twrecycleable(struct tcptw *tw)
298 {
299         tcp_seq new_iss = tw->iss;
300         tcp_seq new_irs = tw->irs;
301
302         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
303         new_iss += (ticks - tw->t_starttime) * (ISN_BYTES_PER_SECOND / hz);
304         new_irs += (ticks - tw->t_starttime) * (MS_ISN_BYTES_PER_SECOND / hz);
305
306         if (SEQ_GT(new_iss, tw->snd_nxt) && SEQ_GT(new_irs, tw->rcv_nxt))
307                 return (1);
308         else
309                 return (0);
310 }
311 #endif
312
313 /*
314  * Returns 1 if the TIME_WAIT state was killed and we should start over,
315  * looking for a pcb in the listen state.  Returns 0 otherwise.
316  */
317 int
318 tcp_twcheck(struct inpcb *inp, struct tcpopt *to, struct tcphdr *th,
319     struct mbuf *m, int tlen)
320 {
321         struct tcptw *tw;
322         int thflags;
323         tcp_seq seq;
324 #ifdef INET6
325         int isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
326 #else
327         const int isipv6 = 0;
328 #endif
329
330         /* tcbinfo lock required for tcp_twclose(), tcp_tw_2msl_reset(). */
331         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
332         INP_WLOCK_ASSERT(inp);
333
334         /*
335          * XXXRW: Time wait state for inpcb has been recycled, but inpcb is
336          * still present.  This is undesirable, but temporarily necessary
337          * until we work out how to handle inpcb's who's timewait state has
338          * been removed.
339          */
340         tw = intotw(inp);
341         if (tw == NULL)
342                 goto drop;
343
344         thflags = th->th_flags;
345
346         /*
347          * NOTE: for FIN_WAIT_2 (to be added later),
348          * must validate sequence number before accepting RST
349          */
350
351         /*
352          * If the segment contains RST:
353          *      Drop the segment - see Stevens, vol. 2, p. 964 and
354          *      RFC 1337.
355          */
356         if (thflags & TH_RST)
357                 goto drop;
358
359 #if 0
360 /* PAWS not needed at the moment */
361         /*
362          * RFC 1323 PAWS: If we have a timestamp reply on this segment
363          * and it's less than ts_recent, drop it.
364          */
365         if ((to.to_flags & TOF_TS) != 0 && tp->ts_recent &&
366             TSTMP_LT(to.to_tsval, tp->ts_recent)) {
367                 if ((thflags & TH_ACK) == 0)
368                         goto drop;
369                 goto ack;
370         }
371         /*
372          * ts_recent is never updated because we never accept new segments.
373          */
374 #endif
375
376         /*
377          * If a new connection request is received
378          * while in TIME_WAIT, drop the old connection
379          * and start over if the sequence numbers
380          * are above the previous ones.
381          */
382         if ((thflags & TH_SYN) && SEQ_GT(th->th_seq, tw->rcv_nxt)) {
383                 tcp_twclose(tw, 0);
384                 return (1);
385         }
386
387         /*
388          * Drop the the segment if it does not contain an ACK.
389          */
390         if ((thflags & TH_ACK) == 0)
391                 goto drop;
392
393         /*
394          * Reset the 2MSL timer if this is a duplicate FIN.
395          */
396         if (thflags & TH_FIN) {
397                 seq = th->th_seq + tlen + (thflags & TH_SYN ? 1 : 0);
398                 if (seq + 1 == tw->rcv_nxt)
399                         tcp_tw_2msl_reset(tw, 1);
400         }
401
402         /*
403          * Acknowledge the segment if it has data or is not a duplicate ACK.
404          */
405         if (thflags != TH_ACK || tlen != 0 ||
406             th->th_seq != tw->rcv_nxt || th->th_ack != tw->snd_nxt)
407                 tcp_twrespond(tw, TH_ACK);
408         goto drop;
409
410         /*
411          * Generate a RST, dropping incoming segment.
412          * Make ACK acceptable to originator of segment.
413          * Don't bother to respond if destination was broadcast/multicast.
414          */
415         if (m->m_flags & (M_BCAST|M_MCAST))
416                 goto drop;
417         if (isipv6) {
418 #ifdef INET6
419                 struct ip6_hdr *ip6;
420
421                 /* IPv6 anycast check is done at tcp6_input() */
422                 ip6 = mtod(m, struct ip6_hdr *);
423                 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
424                     IN6_IS_ADDR_MULTICAST(&ip6->ip6_src))
425                         goto drop;
426 #endif
427         } else {
428                 struct ip *ip;
429
430                 ip = mtod(m, struct ip *);
431                 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
432                     IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
433                     ip->ip_src.s_addr == htonl(INADDR_BROADCAST) ||
434                     in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))
435                         goto drop;
436         }
437         if (thflags & TH_ACK) {
438                 tcp_respond(NULL,
439                     mtod(m, void *), th, m, 0, th->th_ack, TH_RST);
440         } else {
441                 seq = th->th_seq + (thflags & TH_SYN ? 1 : 0);
442                 tcp_respond(NULL,
443                     mtod(m, void *), th, m, seq, 0, TH_RST|TH_ACK);
444         }
445         INP_WUNLOCK(inp);
446         return (0);
447
448 drop:
449         INP_WUNLOCK(inp);
450         m_freem(m);
451         return (0);
452 }
453
454 void
455 tcp_twclose(struct tcptw *tw, int reuse)
456 {
457         struct socket *so;
458         struct inpcb *inp;
459
460         /*
461          * At this point, we are in one of two situations:
462          *
463          * (1) We have no socket, just an inpcb<->twtcp pair.  We can free
464          *     all state.
465          *
466          * (2) We have a socket -- if we own a reference, release it and
467          *     notify the socket layer.
468          */
469         inp = tw->tw_inpcb;
470         KASSERT((inp->inp_vflag & INP_TIMEWAIT), ("tcp_twclose: !timewait"));
471         KASSERT(intotw(inp) == tw, ("tcp_twclose: inp_ppcb != tw"));
472         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);      /* tcp_tw_2msl_stop(). */
473         INP_WLOCK_ASSERT(inp);
474
475         tw->tw_inpcb = NULL;
476         tcp_tw_2msl_stop(tw);
477         inp->inp_ppcb = NULL;
478         in_pcbdrop(inp);
479
480         so = inp->inp_socket;
481         if (so != NULL) {
482                 /*
483                  * If there's a socket, handle two cases: first, we own a
484                  * strong reference, which we will now release, or we don't
485                  * in which case another reference exists (XXXRW: think
486                  * about this more), and we don't need to take action.
487                  */
488                 if (inp->inp_vflag & INP_SOCKREF) {
489                         inp->inp_vflag &= ~INP_SOCKREF;
490                         INP_WUNLOCK(inp);
491                         ACCEPT_LOCK();
492                         SOCK_LOCK(so);
493                         KASSERT(so->so_state & SS_PROTOREF,
494                             ("tcp_twclose: INP_SOCKREF && !SS_PROTOREF"));
495                         so->so_state &= ~SS_PROTOREF;
496                         sofree(so);
497                 } else {
498                         /*
499                          * If we don't own the only reference, the socket and
500                          * inpcb need to be left around to be handled by
501                          * tcp_usr_detach() later.
502                          */
503                         INP_WUNLOCK(inp);
504                 }
505         } else {
506 #ifdef INET6
507                 if (inp->inp_vflag & INP_IPV6PROTO)
508                         in6_pcbfree(inp);
509                 else
510 #endif
511                         in_pcbfree(inp);
512         }
513         V_tcpstat.tcps_closed++;
514         crfree(tw->tw_cred);
515         tw->tw_cred = NULL;
516         if (reuse)
517                 return;
518         uma_zfree(tcptw_zone, tw);
519 }
520
521 int
522 tcp_twrespond(struct tcptw *tw, int flags)
523 {
524         struct inpcb *inp = tw->tw_inpcb;
525         struct tcphdr *th;
526         struct mbuf *m;
527         struct ip *ip = NULL;
528         u_int hdrlen, optlen;
529         int error;
530         struct tcpopt to;
531 #ifdef INET6
532         struct ip6_hdr *ip6 = NULL;
533         int isipv6 = inp->inp_inc.inc_isipv6;
534 #endif
535
536         INP_WLOCK_ASSERT(inp);
537
538         m = m_gethdr(M_DONTWAIT, MT_DATA);
539         if (m == NULL)
540                 return (ENOBUFS);
541         m->m_data += max_linkhdr;
542
543 #ifdef MAC
544         mac_inpcb_create_mbuf(inp, m);
545 #endif
546
547 #ifdef INET6
548         if (isipv6) {
549                 hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
550                 ip6 = mtod(m, struct ip6_hdr *);
551                 th = (struct tcphdr *)(ip6 + 1);
552                 tcpip_fillheaders(inp, ip6, th);
553         } else
554 #endif
555         {
556                 hdrlen = sizeof(struct tcpiphdr);
557                 ip = mtod(m, struct ip *);
558                 th = (struct tcphdr *)(ip + 1);
559                 tcpip_fillheaders(inp, ip, th);
560         }
561         to.to_flags = 0;
562
563         /*
564          * Send a timestamp and echo-reply if both our side and our peer
565          * have sent timestamps in our SYN's and this is not a RST.
566          */
567         if (tw->t_recent && flags == TH_ACK) {
568                 to.to_flags |= TOF_TS;
569                 to.to_tsval = ticks + tw->ts_offset;
570                 to.to_tsecr = tw->t_recent;
571         }
572         optlen = tcp_addoptions(&to, (u_char *)(th + 1));
573
574         m->m_len = hdrlen + optlen;
575         m->m_pkthdr.len = m->m_len;
576
577         KASSERT(max_linkhdr + m->m_len <= MHLEN, ("tcptw: mbuf too small"));
578
579         th->th_seq = htonl(tw->snd_nxt);
580         th->th_ack = htonl(tw->rcv_nxt);
581         th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
582         th->th_flags = flags;
583         th->th_win = htons(tw->last_win);
584
585 #ifdef INET6
586         if (isipv6) {
587                 th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr),
588                     sizeof(struct tcphdr) + optlen);
589                 ip6->ip6_hlim = in6_selecthlim(inp, NULL);
590                 error = ip6_output(m, inp->in6p_outputopts, NULL,
591                     (tw->tw_so_options & SO_DONTROUTE), NULL, NULL, inp);
592         } else
593 #endif
594         {
595                 th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
596                     htons(sizeof(struct tcphdr) + optlen + IPPROTO_TCP));
597                 m->m_pkthdr.csum_flags = CSUM_TCP;
598                 m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
599                 ip->ip_len = m->m_pkthdr.len;
600                 if (V_path_mtu_discovery)
601                         ip->ip_off |= IP_DF;
602                 error = ip_output(m, inp->inp_options, NULL,
603                     ((tw->tw_so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0),
604                     NULL, inp);
605         }
606         if (flags & TH_ACK)
607                 V_tcpstat.tcps_sndacks++;
608         else
609                 V_tcpstat.tcps_sndctrl++;
610         V_tcpstat.tcps_sndtotal++;
611         return (error);
612 }
613
614 static void
615 tcp_tw_2msl_reset(struct tcptw *tw, int rearm)
616 {
617
618         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
619         INP_WLOCK_ASSERT(tw->tw_inpcb);
620         if (rearm)
621                 TAILQ_REMOVE(&V_twq_2msl, tw, tw_2msl);
622         tw->tw_time = ticks + 2 * tcp_msl;
623         TAILQ_INSERT_TAIL(&V_twq_2msl, tw, tw_2msl);
624 }
625
626 static void
627 tcp_tw_2msl_stop(struct tcptw *tw)
628 {
629
630         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
631         TAILQ_REMOVE(&V_twq_2msl, tw, tw_2msl);
632 }
633
634 struct tcptw *
635 tcp_tw_2msl_scan(int reuse)
636 {
637         struct tcptw *tw;
638
639         INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
640         for (;;) {
641                 tw = TAILQ_FIRST(&V_twq_2msl);
642                 if (tw == NULL || (!reuse && tw->tw_time > ticks))
643                         break;
644                 INP_WLOCK(tw->tw_inpcb);
645                 tcp_twclose(tw, reuse);
646                 if (reuse)
647                         return (tw);
648         }
649         return (NULL);
650 }