* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)tcp_subr.c 7.2 (Berkeley) %G%
#include "../net/route.h"
tcb
.inp_next
= tcb
.inp_prev
= &tcb
;
* Create template to be used to send tcp packets on a connection.
* Call after host entry created, allocates an mbuf and fills
* in a skeletal tcp/ip header, minimizing the amount of work
* necessary when the connection is used.
register struct inpcb
*inp
= tp
->t_inpcb
;
register struct tcpiphdr
*n
;
if ((n
= tp
->t_template
) == 0) {
m
= m_get(M_WAIT
, MT_HEADER
);
m
->m_off
= MMAXOFF
- sizeof (struct tcpiphdr
);
m
->m_len
= sizeof (struct tcpiphdr
);
n
= mtod(m
, struct tcpiphdr
*);
n
->ti_next
= n
->ti_prev
= 0;
n
->ti_len
= htons(sizeof (struct tcpiphdr
) - sizeof (struct ip
));
n
->ti_src
= inp
->inp_laddr
;
n
->ti_dst
= inp
->inp_faddr
;
n
->ti_sport
= inp
->inp_lport
;
n
->ti_dport
= inp
->inp_fport
;
* Send a single message to the TCP at address specified by
* the given TCP/IP header. If flags==0, then we make a copy
* of the tcpiphdr at ti and send directly to the addressed host.
* This is used to force keep alive messages out using the TCP
* template for a connection tp->t_template. If flags are given
* then we send a message back to the TCP which originated the
* segment ti, and discard the mbuf containing it and any other
* In any case the ack and sequence number of the transmitted
* segment are as specified by the parameters.
tcp_respond(tp
, ti
, ack
, seq
, flags
)
register struct tcpiphdr
*ti
;
win
= sbspace(&tp
->t_inpcb
->inp_socket
->so_rcv
);
ro
= &tp
->t_inpcb
->inp_route
;
m
= m_get(M_DONTWAIT
, MT_HEADER
);
m
->m_len
= sizeof (struct tcpiphdr
) + 1;
*mtod(m
, struct tcpiphdr
*) = *ti
;
ti
= mtod(m
, struct tcpiphdr
*);
m
->m_off
= (int)ti
- (int)m
;
m
->m_len
= sizeof (struct tcpiphdr
);
#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
xchg(ti
->ti_dst
.s_addr
, ti
->ti_src
.s_addr
, u_long
);
xchg(ti
->ti_dport
, ti
->ti_sport
, u_short
);
ti
->ti_next
= ti
->ti_prev
= 0;
ti
->ti_len
= htons((u_short
)(sizeof (struct tcphdr
) + tlen
));
ti
->ti_off
= sizeof (struct tcphdr
) >> 2;
ti
->ti_win
= htons((u_short
)win
);
ti
->ti_sum
= in_cksum(m
, sizeof (struct tcpiphdr
) + tlen
);
((struct ip
*)ti
)->ip_len
= sizeof (struct tcpiphdr
) + tlen
;
((struct ip
*)ti
)->ip_ttl
= TCP_TTL
;
(void) ip_output(m
, (struct mbuf
*)0, ro
, 0);
* Create a new TCP control block, making an
* empty reassembly queue and hooking it to the argument
* protocol control block.
struct mbuf
*m
= m_getclr(M_DONTWAIT
, MT_PCB
);
register struct tcpcb
*tp
;
return ((struct tcpcb
*)0);
tp
= mtod(m
, struct tcpcb
*);
tp
->seg_next
= tp
->seg_prev
= (struct tcpiphdr
*)tp
;
tp
->t_flags
= 0; /* sends options! */
tp
->t_srtt
= TCPTV_SRTTBASE
;
tp
->snd_cwnd
= sbspace(&inp
->inp_socket
->so_snd
);
inp
->inp_ppcb
= (caddr_t
)tp
;
* Drop a TCP connection, reporting
* the specified error. If connection is synchronized,
* then send a RST to peer.
register struct tcpcb
*tp
;
struct socket
*so
= tp
->t_inpcb
->inp_socket
;
if (TCPS_HAVERCVDSYN(tp
->t_state
)) {
tp
->t_state
= TCPS_CLOSED
;
* Close a TCP control block:
* discard all space held by the tcp
* discard internet protocol block
register struct tcpcb
*tp
;
register struct tcpiphdr
*t
;
struct inpcb
*inp
= tp
->t_inpcb
;
struct socket
*so
= inp
->inp_socket
;
while (t
!= (struct tcpiphdr
*)tp
) {
t
= (struct tcpiphdr
*)t
->ti_next
;
(void) m_free(dtom(tp
->t_template
));
(void) m_free(dtom(tp
->t_tcpopt
));
return ((struct tcpcb
*)0);
* Notify a tcp user of an asynchronous error;
* just wake up so that he can collect error status.
register struct inpcb
*inp
;
wakeup((caddr_t
) &inp
->inp_socket
->so_timeo
);
sorwakeup(inp
->inp_socket
);
sowwakeup(inp
->inp_socket
);
extern u_char inetctlerrmap
[];
int tcp_quench(), in_rtchange();
if ((unsigned)cmd
> PRC_NCMDS
)
if (sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_IMPLINK
)
sin
= (struct sockaddr_in
*)sa
;
if (sin
->sin_addr
.s_addr
== INADDR_ANY
)
in_pcbnotify(&tcb
, &sin
->sin_addr
, 0, tcp_quench
);
case PRC_REDIRECT_TOSNET
:
case PRC_REDIRECT_TOSHOST
:
in_pcbnotify(&tcb
, &sin
->sin_addr
, 0, in_rtchange
);
if (inetctlerrmap
[cmd
] == 0)
in_pcbnotify(&tcb
, &sin
->sin_addr
, (int)inetctlerrmap
[cmd
],
* When a source quench is received, close congestion window
* to 80% of the outstanding data (but not less than one segment).
struct tcpcb
*tp
= intotcpcb(inp
);
tp
->snd_cwnd
= MAX(8 * (tp
->snd_nxt
- tp
->snd_una
) / 10,