SCCS-vsn: sys/netinet/tcp_output.c 4.19
SCCS-vsn: sys/netinet/tcp_subr.c 4.3
SCCS-vsn: sys/netinet/tcp_timer.c 4.3
SCCS-vsn: sys/netinet/tcp_usrreq.c 1.36
-/* tcp_output.c 4.18 81/11/25 */
+/* tcp_output.c 4.19 81/11/26 */
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/mbuf.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/mbuf.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
-#include "../net/inet.h"
-#include "../net/inet_pcb.h"
-#include "../net/inet_systm.h"
-#include "../net/imp.h"
+#include "../net/in.h"
+#include "../net/in_pcb.h"
+#include "../net/in_systm.h"
#include "../net/ip.h"
#include "../net/ip_var.h"
#include "../net/tcp.h"
#include "../net/ip.h"
#include "../net/ip_var.h"
#include "../net/tcp.h"
-#include "../net/tcp_var.h"
#include "../net/tcp_fsm.h"
#include "../net/tcp_fsm.h"
+#include "../net/tcp_seq.h"
+#include "../net/tcp_timer.h"
+#include "../net/tcp_var.h"
+#include "../net/tcpip.h"
#include "/usr/include/errno.h"
/*
#include "/usr/include/errno.h"
/*
- * Determine length of data that can be transmitted.
- * If will transmit to end of data and no more data
- * is coming, then send FIN also.
- * Make a copy of the data (if any). If no data
- * and not forced to transmit, just return.
+ * Determine length of data that can be transmitted,
+ * and flags that will be used.
+ * If there is some data or critical controls (SYN, RST)
+ * to send, then transmit; otherwise, investigate further.
*/
off = tp->snd_nxt - tp->snd_una;
len = MIN(so->so_snd.sb_cc, tp->snd_wnd) - off;
*/
off = tp->snd_nxt - tp->snd_una;
len = MIN(so->so_snd.sb_cc, tp->snd_wnd) - off;
- if (len > tp->mtu)
- len = tp->mtu;
- if (len == so->so_snd.sb_cc && (so->so_state & SS_CANTSNDMORE))
- flags = TH_FIN;
- else
- flags = 0;
- if (len)
+ if (len > tp->t_maxseg)
+ len = tp->t_maxseg;
+ flags = tcp_outflags[tp->t_state];
+ if (len || (flags & (TH_SYN|TH_RST)))
- * No data to send: see if something else makes us want to send.
- * First check if we owe peer and ack or have a unacked FIN to send.
+ * See if we owe peer an ACK or have a unacked FIN to send.
- if (tp->t_flags & TF_OWEACK)
+ if (tp->t_flags & TF_ACKNOW)
- if ((so->so_state & SS_CANTSNDMORE) &&
- TCPS_OURFINISACKED(tp->t_state) == 0)
- goto send;
- if (tp->t_state == TCPS_SYN_SENT) {
- flags = TH_SYN;
- goto send;
- }
- if (tp->t_state == TCPS_CLOSED) {
- flags = TH_RST;
+ if ((so->so_state & SS_CANTSENDMORE) &&
+ TCPS_OURFINNOTACKED(tp->t_state))
/*
* Calculate available window in i, and also amount
/*
* Calculate available window in i, and also amount
* next expected input.) If this is 35% or more of the
* maximum possible window, then want to send a segment to peer.
*/
* next expected input.) If this is 35% or more of the
* maximum possible window, then want to send a segment to peer.
*/
- i = sbspace(&so->so_rcv) - tp->seqcnt;
- if (i > 0 &&
- ((100*(i-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35))
+ win = sbspace(&so->so_rcv);
+ if (win > 0 &&
+ ((100*(win-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35))
* window for use in delaying messages about window sizes.
*/
ti->ti_seq = htonl(tp->snd_nxt);
* window for use in delaying messages about window sizes.
*/
ti->ti_seq = htonl(tp->snd_nxt);
- ti->ti_ackno = htonl(tp->rcv_nxt);
- /* OPTIONS */
- if (flags & TH_SYN)
- ti->ti_flags = flags;
- else
- ti->ti_flags = flags | TH_ACK;
+ ti->ti_ack = htonl(tp->rcv_nxt);
+ if (tp->t_tcpopt) {
+ m->m_next = m_get(0);
+ if (m->m_next == 0) {
+ (void) m_free(m);
+ return (0);
+ }
+ m->m_next->m_next = m0;
+ m->m_off = MMINOFF;
+ m->m_len = tp->t_tcpopt->m_len;
+ bcopy(mtod(tp->t_tcpopt, caddr_t), mtod(m, caddr_t),
+ tp->t_tcpopt->m_len);
+ ti->ti_off = (sizeof (struct tcphdr)+tp->t_tcpopt->m_len) >> 2;
+ }
+ ti->ti_flags = flags;
win = sbspace(&so->so_rcv);
if (win > 0)
ti->ti_win = htons(win);
win = sbspace(&so->so_rcv);
if (win > 0)
ti->ti_win = htons(win);
- if (SEQ_GT(tp->snd_urp, tp->snd_nxt))
- ti->ti_urp = htons((u_short)(tp->snd_urp - tp->snd_nxt));
+ if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
+ ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));
ti->ti_flags |= TH_URG;
} else
/*
ti->ti_flags |= TH_URG;
} else
/*
* so that it doesn't drift into the send window on sequence
* number wraparound.
*/
* so that it doesn't drift into the send window on sequence
* number wraparound.
*/
- tp->snd_urp = tp->snd_una; /* drag it along */
+ tp->snd_up = tp->snd_una; /* drag it along */
+ /* PUSH */
/*
* Put TCP length in extended header, and then
/*
* Put TCP length in extended header, and then
*/
if (len)
ti->ti_len = htons((u_short)(len + sizeof (struct tcphdr)));
*/
if (len)
ti->ti_len = htons((u_short)(len + sizeof (struct tcphdr)));
- ti->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len);
+ ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + len);
+
+ /*
+ * Advance snd_nxt over sequence space of this segment
+ */
+ if (flags & (TH_SYN|TH_FIN))
+ len++;
+ tp->snd_nxt += len;
+
+ /*
+ * Arrange for retransmit and time this transmit if
+ * not already a retransmit and sending either data,
+ * SYN or FIN.
+ */
+ if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
+ tp->rxt_seq = tp->snd_nxt - len;
+ tp->rxt_time = 0;
+ tp->rxt_cnt = 0;
+ tp->t_timer[TCPT_REXMT] = 0; /* XXX */
+ }
/*
* Fill in IP length and desired time to live and
/*
* Fill in IP length and desired time to live and
*/
((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr);
((struct ip *)ti)->ip_ttl = TCP_TTL;
*/
((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr);
((struct ip *)ti)->ip_ttl = TCP_TTL;
- if (ip_output(m) == 0)
- return;
+ if (ip_output(m, tp->t_ipopt) == 0)
+ return (0);
/*
* Data sent (as far as we can tell).
* If this advertises a larger window than any other segment,
* then record its sequence to be used in suppressing messages.
/*
* Data sent (as far as we can tell).
* If this advertises a larger window than any other segment,
* then record its sequence to be used in suppressing messages.
- * Advance snd_nxt to reflect transmitted sequence space,
- * drop send for purpose of ACK requirements,
- * and time transmission if not a retransmit.
+ * Drop send for purpose of ACK requirements.
*/
if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
tp->rcv_adv = tp->rcv_nxt + win;
*/
if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
tp->rcv_adv = tp->rcv_nxt + win;
- tp->snd_nxt += len;
- tp->t_flags &= ~(TF_OWEACK|TF_DELACK);
- if (flags & TH_FIN)
- tp->snd_nxt++;
- if (SEQ_GT(tp->snd_nxt, tp->snd_hi)) {
- tp->snd_hi = tp->snd_nxt;
- /* TIME TRANSMIT */
- }
- return;
+ tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
+ tp->snd_max = tp->snd_nxt;
+ return (1);
-/* tcp_subr.c 4.2 81/11/25 */
+/* tcp_subr.c 4.3 81/11/26 */
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/protosw.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/protosw.h"
-#include "../net/inet.h"
-#include "../net/inet_pcb.h"
-#include "../net/inet_systm.h"
+#include "../net/in.h"
+#include "../net/in_pcb.h"
+#include "../net/in_systm.h"
#include "../net/ip.h"
#include "../net/ip_var.h"
#include "../net/tcp.h"
#define TCPFSTAB
#include "../net/tcp_fsm.h"
#include "../net/ip.h"
#include "../net/ip_var.h"
#include "../net/tcp.h"
#define TCPFSTAB
#include "../net/tcp_fsm.h"
+#include "../net/tcp_seq.h"
+#include "../net/tcp_timer.h"
#include "../net/tcp_var.h"
#include "../net/tcp_var.h"
+#include "../net/tcpip.h"
#include "/usr/include/errno.h"
/*
#include "/usr/include/errno.h"
/*
tcp_iss = 1; /* wrong */
tcb.inp_next = tcb.inp_prev = &tcb;
}
tcp_iss = 1; /* wrong */
tcb.inp_next = tcb.inp_prev = &tcb;
}
n->ti_sport = inp->inp_lport;
n->ti_dport = inp->inp_fport;
n->ti_seq = 0;
n->ti_sport = inp->inp_lport;
n->ti_dport = inp->inp_fport;
n->ti_seq = 0;
n->ti_x2 = 0;
n->ti_off = 5;
n->ti_flags = 0;
n->ti_x2 = 0;
n->ti_off = 5;
n->ti_flags = 0;
- * Reflect a control message back to sender of tcp segment ti,
+ * Send a reset message back to send of TCP segment ti,
* with ack, seq and flags fields as specified by parameters.
*/
* with ack, seq and flags fields as specified by parameters.
*/
-tcp_reflect(ti, ack, seq, flags)
+tcp_respond(ti, ack, seq, flags)
register struct tcpiphdr *ti;
register struct tcpiphdr *ti;
+ struct mbuf *m = dtom(ti);
m_freem(m->m_next);
m->m_next = 0;
m->m_len = sizeof(struct tcpiphdr);
m_freem(m->m_next);
m->m_next = 0;
m->m_len = sizeof(struct tcpiphdr);
-#define xchg(a,b) j=a; a=b; b=j
- xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr);
- xchg(ti->ti_dport, ti->ti_sport);
+#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_ack = htonl(ack);
+ ti->ti_next = ti->ti_prev = 0;
+ ti->ti_x1 = 0;
+ ti->ti_len = htons(sizeof (struct tcphdr));
+ ti->ti_ack = htonl(ack);
+ ti->ti_x2 = 0;
+ ti->ti_off = sizeof (struct tcphdr) >> 2;
-
- ti->ti_len = htons(sizeof (struct tcphdr));
- ti->ti_off = 5;
- ti->ti_sum = inet_cksum(m, sizeof(struct tcpiphdr));
+ ti->ti_win = ti->ti_urp = 0;
+ ti->ti_sum = in_cksum(m, sizeof(struct tcpiphdr));
((struct ip *)ti)->ip_len = sizeof(struct tcpiphdr);
((struct ip *)ti)->ip_len = sizeof(struct tcpiphdr);
- ((struct ip *)ti)->ip_ttl = MAXTTL;
- ip_output(m);
+ ((struct ip *)ti)->ip_ttl = TCP_TTL;
+ ip_output(m, (struct mbuf *)0);
+/*
+ * Create a new TCP control block, making an
+ * empty reassembly queue and hooking it to the argument
+ * protocol control block.
+ */
struct tcpcb *
tcp_newtcpcb(inp)
struct inpcb *inp;
struct tcpcb *
tcp_newtcpcb(inp)
struct inpcb *inp;
if (m == 0)
return (0);
tp = mtod(m, struct tcpcb *);
if (m == 0)
return (0);
tp = mtod(m, struct tcpcb *);
-
- /*
- * Make empty reassembly queue.
- */
tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
-
- /*
- * Initialize sequence numbers and round trip retransmit timer.
- */
- tp->t_xmtime = T_REXMT;
- tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
- tp->iss = tcp_iss;
- tp->snd_off = tp->iss + 1;
- tcp_iss += (ISSINCR >> 1) + 1;
-
- /*
- * Hook to inpcb.
- */
tp->t_inpcb = inp;
inp->inp_ppcb = (caddr_t)tp;
return (tp);
}
tp->t_inpcb = inp;
inp->inp_ppcb = (caddr_t)tp;
return (tp);
}
+/*
+ * Drop a TCP connection, reporting
+ * the specified error. If connection is synchronized,
+ * then send a RST to peer.
+ */
tcp_drop(tp, errno)
struct tcpcb *tp;
int errno;
tcp_drop(tp, errno)
struct tcpcb *tp;
int errno;
COUNT(TCP_DROP);
if (TCPS_HAVERCVDSYN(tp->t_state) &&
COUNT(TCP_DROP);
if (TCPS_HAVERCVDSYN(tp->t_state) &&
- TCPS_OURFINISACKED(tp->t_state) == 0) {
+ TCPS_OURFINNOTACKED(tp->t_state)) {
tp->t_state = TCPS_CLOSED;
tcp_output(tp);
}
so->so_error = errno;
tp->t_state = TCPS_CLOSED;
tcp_output(tp);
}
so->so_error = errno;
- socantrcvmore(so);
- socantsndmore(so);
+/*
+ * Close a TCP control block:
+ * discard all space held by the tcp
+ * discard internet protocol block
+ * wake up any sleepers
+ */
tcp_close(tp)
register struct tcpcb *tp;
{
register struct tcpiphdr *t;
tcp_close(tp)
register struct tcpcb *tp;
{
register struct tcpiphdr *t;
+ struct socket *so = tp->t_inpcb->inp_socket;
t = tp->seg_next;
for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next)
m_freem(dtom(t));
t = tp->seg_next;
for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next)
m_freem(dtom(t));
(void) m_free(dtom(tp->t_template));
(void) m_free(dtom(tp->t_template));
- tp->t_template = 0;
- }
+ if (tp->t_tcpopt)
+ (void) m_free(dtom(tp->t_tcpopt));
+ if (tp->t_ipopt)
+ (void) m_free(dtom(tp->t_ipopt));
in_pcbfree(tp->t_inpcb);
(void) m_free(dtom(tp));
in_pcbfree(tp->t_inpcb);
(void) m_free(dtom(tp));
+ socantrcvmore(so);
+ socantsendmore(so);
-/* tcp_timer.c 4.2 81/11/25 */
+/* tcp_timer.c 4.3 81/11/26 */
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/protosw.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/protosw.h"
-#include "../net/inet.h"
-#include "../net/inet_pcb.h"
-#include "../net/inet_systm.h"
+#include "../net/in.h"
+#include "../net/in_pcb.h"
+#include "../net/in_systm.h"
#include "../net/ip.h"
#include "../net/ip_var.h"
#include "../net/tcp.h"
#include "../net/tcp_fsm.h"
#include "../net/ip.h"
#include "../net/ip_var.h"
#include "../net/tcp.h"
#include "../net/tcp_fsm.h"
+#include "../net/tcp_seq.h"
+#include "../net/tcp_timer.h"
#include "../net/tcp_var.h"
#include "../net/tcp_var.h"
+#include "../net/tcpip.h"
#include "/usr/include/errno.h"
/*
#include "/usr/include/errno.h"
/*
int s = splnet();
register short *tmp;
register int i;
int s = splnet();
register short *tmp;
register int i;
/*
* Search through tcb's and update active timers.
*/
for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) {
tp = intotcpcb(ip);
/*
* Search through tcb's and update active timers.
*/
for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) {
tp = intotcpcb(ip);
for (i = 0; i < TCPT_NTIMERS; i++) {
for (i = 0; i < TCPT_NTIMERS; i++) {
- if (*tmp && --*tmp == 0)
+ if (tp->t_timer[i] && --tp->t_timer[i] == 0)
(void) tcp_usrreq(tp->t_inpcb->inp_socket,
PRU_SLOWTIMO, (struct mbuf *)0,
(caddr_t)i);
tmp++;
}
(void) tcp_usrreq(tp->t_inpcb->inp_socket,
PRU_SLOWTIMO, (struct mbuf *)0,
(caddr_t)i);
tmp++;
}
}
tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */
splx(s);
}
tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */
splx(s);
/*
* Cancel all timers for TCP tp.
*/
/*
* Cancel all timers for TCP tp.
*/
struct tcpcb *tp;
{
register int i;
struct tcpcb *tp;
{
register int i;
+COUNT(TCP_CANCELTIMERS);
for (i = 0; i < TCPT_NTIMERS; i++)
tp->t_timer[i] = 0;
}
for (i = 0; i < TCPT_NTIMERS; i++)
tp->t_timer[i] = 0;
}
case TCPT_2MSL:
tcp_close(tp);
return;
case TCPT_REXMT:
case TCPT_2MSL:
tcp_close(tp);
return;
case TCPT_REXMT:
- if (tp->t_xmtime > TCPT_TOOLONG) {
+ if (tp->t_xmtime > TCPSC_TOOLONG) {
tcp_drop(tp, ETIMEDOUT);
return;
}
tcp_drop(tp, ETIMEDOUT);
return;
}
tcp_output(tp);
return;
case TCPT_PERSIST:
if (tcp_output(tp) == 0)
tp->snd_wnd++, (void) tcp_output(tp), tp->snd_wnd--;
tcp_output(tp);
return;
case TCPT_PERSIST:
if (tcp_output(tp) == 0)
tp->snd_wnd++, (void) tcp_output(tp), tp->snd_wnd--;
-/* tcp_usrreq.c 1.35 81/11/25 */
+/* tcp_usrreq.c 1.36 81/11/26 */
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/protosw.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/protosw.h"
-#include "../net/inet.h"
-#include "../net/inet_pcb.h"
-#include "../net/inet_systm.h"
+#include "../net/in.h"
+#include "../net/in_pcb.h"
+#include "../net/in_systm.h"
#include "../net/ip.h"
#include "../net/ip_var.h"
#include "../net/tcp.h"
#include "../net/tcp_fsm.h"
#include "../net/ip.h"
#include "../net/ip_var.h"
#include "../net/tcp.h"
#include "../net/tcp_fsm.h"
+#include "../net/tcp_seq.h"
+#include "../net/tcp_timer.h"
#include "../net/tcp_var.h"
#include "../net/tcp_var.h"
+#include "../net/tcpip.h"
#include "/usr/include/errno.h"
struct tcpcb *tcp_newtcpcb();
#include "/usr/include/errno.h"
struct tcpcb *tcp_newtcpcb();
* Make sure attached. If not,
* only PRU_ATTACH is valid.
*/
* Make sure attached. If not,
* only PRU_ATTACH is valid.
*/
- if (inp == 0 && req != PRU_ATTACH)
+ if (inp == 0 && req != PRU_ATTACH) {
splx(s);
return (EINVAL);
}
splx(s);
return (EINVAL);
}
break;
case PRU_SHUTDOWN:
break;
case PRU_SHUTDOWN:
switch (tp->t_state) {
case TCPS_LISTEN:
switch (tp->t_state) {
case TCPS_LISTEN:
tp->t_state = TCPS_CLOSED;
break;
tp->t_state = TCPS_CLOSED;
break;
- case TCPS_SYN_RCVD:
- case TCPS_ESTAB:
+ case TCPS_SYN_RECEIVED:
+ case TCPS_ESTABLISHED:
tp->t_state = TCPS_FIN_WAIT_1;
tcp_output(tp);
break;
tp->t_state = TCPS_FIN_WAIT_1;
tcp_output(tp);
break;
- if (tp->t_state < TCPS_ESTABLISHED) {
- error = ENOTCONN;
- break;
- }
tcp_output(tp);
break;
case PRU_SEND:
tcp_output(tp);
break;
case PRU_SEND:
- if (tp->t_state < TCPS_ESTABLISHED) {
- error = ENOTCONN;
- break;
- }
- if (tp->t_state > TCPS_CLOSE_WAIT) {
- error = EISDISCONN;
- m_freem(m);
- break;
- }
sbappend(&so->so_snd, m);
sbappend(&so->so_snd, m);
- if (tp->t_options & TO_EOL)
+/*
+ if (tp->t_flags & TF_PUSH)
tp->snd_end = tp->snd_una + so->so_snd.sb_cc;
tp->snd_end = tp->snd_una + so->so_snd.sb_cc;
- if (tp->t_options & TO_URG)
- tp->snd_urp = tp->snd_una + so->so_snd.sb_cc + 1;
+ */
+ if (tp->t_flags & TF_URG)
+ tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1;