Commit | Line | Data |
---|---|---|
2ff61f9d | 1 | /* tcp_output.c 4.17 81/11/24 */ |
76ee76df BJ |
2 | |
3 | #include "../h/param.h" | |
4 | #include "../h/systm.h" | |
5 | #include "../h/mbuf.h" | |
6 | #include "../h/socket.h" | |
d52566dd | 7 | #include "../h/socketvar.h" |
d52566dd | 8 | #include "../net/inet.h" |
53a5409e | 9 | #include "../net/inet_pcb.h" |
d52566dd BJ |
10 | #include "../net/inet_systm.h" |
11 | #include "../net/imp.h" | |
12 | #include "../net/ip.h" | |
eb44bfb2 | 13 | #include "../net/ip_var.h" |
d52566dd BJ |
14 | #include "../net/tcp.h" |
15 | #include "../net/tcp_var.h" | |
16 | #include "../net/tcp_fsm.h" | |
17 | #include "/usr/include/errno.h" | |
76ee76df | 18 | |
ea727f86 BJ |
19 | /* |
20 | * Special routines to send control messages. | |
21 | */ | |
22 | tcp_sndctl(tp) | |
53a5409e | 23 | struct tcpcb *tp; |
ea727f86 BJ |
24 | { |
25 | COUNT(TCP_SNDCTL); | |
26 | ||
27 | if (tcp_send(tp)) | |
28 | return (1); | |
29 | tcp_sndnull(tp); | |
d52566dd | 30 | return (0); |
ea727f86 BJ |
31 | } |
32 | ||
33 | tcp_sndwin(tp) | |
53a5409e | 34 | struct tcpcb *tp; |
ea727f86 BJ |
35 | { |
36 | int ihave, hehas; | |
37 | COUNT(TCP_SNDWIN); | |
38 | ||
39 | if (tp->rcv_adv) { | |
53a5409e BJ |
40 | register struct socket *so = tp->t_inpcb->inp_socket; |
41 | ||
d52566dd BJ |
42 | ihave = so->so_rcv.sb_hiwat - |
43 | (so->so_rcv.sb_cc + tp->seqcnt); | |
ea727f86 | 44 | hehas = tp->rcv_adv - tp->rcv_nxt; |
d52566dd | 45 | if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35) |
ea727f86 BJ |
46 | return; |
47 | } | |
48 | if (tcp_send(tp)) | |
cdad2eb1 | 49 | return; |
ea727f86 | 50 | tcp_sndnull(tp); |
ea727f86 BJ |
51 | } |
52 | ||
53 | tcp_sndnull(tp) | |
53a5409e | 54 | register struct tcpcb *tp; |
ea727f86 BJ |
55 | { |
56 | COUNT(TCP_SNDNULL); | |
57 | ||
cdad2eb1 | 58 | (void) tcp_output(tp, 0, 0, (struct mbuf *)0); |
ea727f86 BJ |
59 | tp->tc_flags &= ~TC_ACK_DUE; |
60 | } | |
61 | ||
ea727f86 BJ |
62 | /* |
63 | * Tcp segment output routine. | |
64 | */ | |
65 | tcp_send(tp) | |
53a5409e | 66 | register struct tcpcb *tp; |
76ee76df | 67 | { |
76ee76df | 68 | register unsigned long last, wind; |
53a5409e | 69 | register struct socket *so = tp->t_inpcb->inp_socket; |
76ee76df | 70 | struct mbuf *m; |
53a5409e | 71 | int flags = 0, forced, sent, len; |
76ee76df | 72 | |
ea727f86 | 73 | COUNT(TCP_SEND); |
76ee76df BJ |
74 | tp->snd_lst = tp->snd_nxt; |
75 | forced = 0; | |
76 | m = NULL; | |
ea727f86 | 77 | if (tp->snd_nxt == tp->iss) { |
76ee76df BJ |
78 | flags |= TH_SYN; |
79 | tp->snd_lst++; | |
80 | } | |
76ee76df | 81 | last = tp->snd_off; |
d52566dd | 82 | for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next) |
76ee76df | 83 | last += m->m_len; |
76ee76df | 84 | if (tp->snd_nxt > last) { |
76ee76df BJ |
85 | if ((tp->tc_flags&TC_SND_FIN) && |
86 | (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { | |
87 | ||
88 | flags |= TH_FIN; | |
89 | tp->seq_fin = tp->snd_lst++; | |
90 | } | |
ea727f86 | 91 | } else { |
76ee76df | 92 | if (tp->tc_flags&TC_SYN_ACKED) { |
76ee76df | 93 | wind = tp->snd_una + tp->snd_wnd; |
cdad2eb1 | 94 | tp->snd_lst = MIN(last, wind); |
76ee76df BJ |
95 | if ((len = tp->snd_lst - tp->snd_nxt) > 1024) |
96 | tp->snd_lst -= len - 1024; | |
76ee76df BJ |
97 | if (tp->snd_lst >= wind) |
98 | tp->t_persist = T_PERS; | |
99 | } | |
76ee76df BJ |
100 | if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { |
101 | tp->snd_lst = tp->snd_nxt + 1; | |
102 | forced = 1; | |
ddfd844e | 103 | } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0) |
7be5ba08 | 104 | return (0); |
4ad99bae | 105 | m = m_copy(so->so_snd.sb_mb, |
cdad2eb1 BJ |
106 | (int)(MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off), |
107 | (int)(tp->snd_lst - tp->snd_off)); | |
76ee76df BJ |
108 | if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) |
109 | flags |= TH_EOL; | |
76ee76df BJ |
110 | if ((tp->tc_flags&TC_SND_FIN) && !forced && |
111 | tp->snd_lst == last && | |
112 | (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { | |
76ee76df BJ |
113 | flags |= TH_FIN; |
114 | tp->seq_fin = tp->snd_lst++; | |
115 | } | |
116 | } | |
ddfd844e BJ |
117 | if (tp->snd_nxt >= tp->snd_lst) |
118 | return (0); | |
ea727f86 BJ |
119 | if (tp->tc_flags & TC_SND_URG) |
120 | flags |= TH_URG; | |
cdad2eb1 | 121 | sent = tcp_output(tp, flags, (int)(tp->snd_lst - tp->snd_nxt), m); |
ea727f86 BJ |
122 | if (!forced) { |
123 | tp->t_rexmt = tp->t_xmtime; | |
124 | tp->t_rexmt_val = tp->snd_lst; | |
125 | if ((tp->tc_flags&TC_REXMT) == 0) { | |
126 | tp->t_rexmttl = T_REXMTTL; | |
127 | tp->t_rtl_val = tp->snd_lst; | |
76ee76df | 128 | } |
76ee76df | 129 | } |
ea727f86 BJ |
130 | if (sent) |
131 | tp->snd_nxt = tp->snd_lst; | |
132 | if ((tp->tc_flags&TC_SYN_ACKED) && | |
133 | tp->snd_una > tp->t_xmt_val) { | |
134 | tp->t_xmt = 0; | |
135 | tp->t_xmt_val = tp->snd_lst; | |
76ee76df | 136 | } |
ea727f86 | 137 | tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); |
7be5ba08 | 138 | tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); |
ea727f86 | 139 | return (1); |
76ee76df | 140 | } |
76ee76df | 141 | tcp_output(tp, flags, len, dat) |
53a5409e | 142 | register struct tcpcb *tp; |
76ee76df BJ |
143 | register int flags; |
144 | int len; | |
145 | struct mbuf *dat; | |
146 | { | |
53a5409e | 147 | register struct tcpiphdr *t; /* known to be r9 */ |
76ee76df | 148 | register struct mbuf *m; |
53a5409e | 149 | struct socket *so = tp->t_inpcb->inp_socket; |
76ee76df | 150 | register struct ip *ip; |
3552a746 | 151 | COUNT(TCP_OUTPUT); |
76ee76df | 152 | |
e1506033 | 153 | if ((t = tp->t_template) == 0) |
76ee76df BJ |
154 | return (0); |
155 | MGET(m, 0); | |
156 | if (m == 0) | |
157 | return (0); | |
53a5409e BJ |
158 | m->m_off = MMAXOFF - sizeof(struct tcpiphdr); |
159 | m->m_len = sizeof (struct tcpiphdr); | |
76ee76df BJ |
160 | m->m_next = dat; |
161 | if (flags & TH_SYN) | |
162 | len--; | |
163 | if (flags & TH_FIN) | |
164 | len--; | |
cdad2eb1 BJ |
165 | if (len < 0) |
166 | panic("tcp_output"); | |
53a5409e BJ |
167 | bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr)); |
168 | t = mtod(m, struct tcpiphdr *); | |
76ee76df BJ |
169 | if (tp->tc_flags&TC_SND_RST) { |
170 | flags &= ~TH_SYN; | |
171 | flags |= TH_RST; | |
172 | } | |
173 | if (tp->tc_flags&TC_SYN_RCVD) | |
174 | flags |= TH_ACK; | |
eb44bfb2 | 175 | t->ti_flags = flags; |
76ee76df | 176 | if (flags & TH_URG) |
cdad2eb1 | 177 | t->ti_urp = htons((u_short)tp->snd_urp); /*XXX */ |
eb44bfb2 | 178 | t->ti_win = |
53a5409e BJ |
179 | so->so_rcv.sb_hiwat - |
180 | (so->so_rcv.sb_cc + tp->seqcnt); | |
eb44bfb2 BJ |
181 | if (tp->rcv_nxt + t->ti_win > tp->rcv_adv) |
182 | tp->rcv_adv = tp->rcv_nxt + t->ti_win; | |
76ee76df | 183 | if (len) |
2ff61f9d | 184 | t->ti_len = htons((u_short)(len + sizeof (struct tcphdr))); |
eb44bfb2 | 185 | t->ti_win = htons(t->ti_win); |
eb44bfb2 BJ |
186 | t->ti_seq = htonl(tp->snd_nxt); |
187 | t->ti_ackno = htonl(tp->rcv_nxt); | |
188 | t->ti_sum = 0; /* gratuitous? */ | |
2b4b57cd | 189 | t->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len); |
76ee76df BJ |
190 | ip = (struct ip *)t; |
191 | ip->ip_v = IPVERSION; | |
192 | ip->ip_hl = 5; | |
193 | ip->ip_tos = 0; | |
53a5409e | 194 | ip->ip_len = len + sizeof(struct tcpiphdr); |
76ee76df BJ |
195 | ip->ip_id = ip_id++; |
196 | ip->ip_off = 0; | |
197 | ip->ip_ttl = MAXTTL; | |
2b4b57cd BJ |
198 | ip_send(ip); |
199 | return (1); | |
76ee76df | 200 | } |