1 /* tcp_output.c 4.12 81/11/15 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/socket.h" 7 #include "../h/socketvar.h" 8 #include "../net/inet_cksum.h" 9 #include "../net/inet.h" 10 #include "../net/inet_host.h" 11 #include "../net/inet_pcb.h" 12 #include "../net/inet_systm.h" 13 #include "../net/imp.h" 14 #include "../net/ip.h" 15 #include "../net/ip_var.h" 16 #include "../net/tcp.h" 17 #include "../net/tcp_var.h" 18 #include "../net/tcp_fsm.h" 19 #include "/usr/include/errno.h" 20 21 /* 22 * Special routines to send control messages. 23 */ 24 tcp_sndctl(tp) 25 struct tcpcb *tp; 26 { 27 COUNT(TCP_SNDCTL); 28 29 if (tcp_send(tp)) 30 return (1); 31 tcp_sndnull(tp); 32 return (0); 33 } 34 35 tcp_sndwin(tp) 36 struct tcpcb *tp; 37 { 38 int ihave, hehas; 39 COUNT(TCP_SNDWIN); 40 41 if (tp->rcv_adv) { 42 register struct socket *so = tp->t_inpcb->inp_socket; 43 44 ihave = so->so_rcv.sb_hiwat - 45 (so->so_rcv.sb_cc + tp->seqcnt); 46 hehas = tp->rcv_adv - tp->rcv_nxt; 47 if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35) 48 return; 49 } 50 if (tcp_send(tp)) 51 return (1); 52 tcp_sndnull(tp); 53 return (0); 54 } 55 56 tcp_sndnull(tp) 57 register struct tcpcb *tp; 58 { 59 COUNT(TCP_SNDNULL); 60 61 tcp_output(tp, 0, 0, (struct mbuf *)0); 62 tp->tc_flags &= ~TC_ACK_DUE; 63 } 64 65 tcp_sndrst(tp, n) 66 register struct tcpcb *tp; 67 register struct tcpiphdr *n; 68 { 69 COUNT(TCP_SNDRST); 70 71 /* don't send a reset in response to a reset */ 72 if (n->ti_flags&TH_RST) 73 return; 74 tp->tc_flags |= TC_SND_RST; 75 if (n->ti_flags&TH_ACK) 76 tp->snd_nxt = n->ti_ackno; 77 tp->tc_flags &= ~TC_SYN_RCVD; 78 tcp_sndnull(tp); 79 tp->tc_flags &= ~TC_SND_RST; 80 } 81 82 /* 83 * Tcp segment output routine. 84 */ 85 tcp_send(tp) 86 register struct tcpcb *tp; 87 { 88 register unsigned long last, wind; 89 register struct socket *so = tp->t_inpcb->inp_socket; 90 struct mbuf *m; 91 int flags = 0, forced, sent, len; 92 93 COUNT(TCP_SEND); 94 tp->snd_lst = tp->snd_nxt; 95 forced = 0; 96 m = NULL; 97 if (tp->snd_nxt == tp->iss) { 98 flags |= TH_SYN; 99 tp->snd_lst++; 100 } 101 last = tp->snd_off; 102 for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next) 103 last += m->m_len; 104 if (tp->snd_nxt > last) { 105 if ((tp->tc_flags&TC_SND_FIN) && 106 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 107 108 flags |= TH_FIN; 109 tp->seq_fin = tp->snd_lst++; 110 } 111 } else { 112 if (tp->tc_flags&TC_SYN_ACKED) { 113 wind = tp->snd_una + tp->snd_wnd; 114 tp->snd_lst = min(last, wind); 115 if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 116 tp->snd_lst -= len - 1024; 117 if (tp->snd_lst >= wind) 118 tp->t_persist = T_PERS; 119 } 120 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 121 tp->snd_lst = tp->snd_nxt + 1; 122 forced = 1; 123 } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0) 124 return (0); 125 m = sb_copy(&so->so_snd, 126 MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off, 127 tp->snd_lst - tp->snd_off); 128 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 129 flags |= TH_EOL; 130 if ((tp->tc_flags&TC_SND_FIN) && !forced && 131 tp->snd_lst == last && 132 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 133 flags |= TH_FIN; 134 tp->seq_fin = tp->snd_lst++; 135 } 136 } 137 if (tp->snd_nxt >= tp->snd_lst) 138 return (0); 139 if (tp->tc_flags & TC_SND_URG) 140 flags |= TH_URG; 141 sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 142 if (!forced) { 143 tp->t_rexmt = tp->t_xmtime; 144 tp->t_rexmt_val = tp->snd_lst; 145 if ((tp->tc_flags&TC_REXMT) == 0) { 146 tp->t_rexmttl = T_REXMTTL; 147 tp->t_rtl_val = tp->snd_lst; 148 } 149 } 150 if (sent) 151 tp->snd_nxt = tp->snd_lst; 152 if ((tp->tc_flags&TC_SYN_ACKED) && 153 tp->snd_una > tp->t_xmt_val) { 154 tp->t_xmt = 0; 155 tp->t_xmt_val = tp->snd_lst; 156 } 157 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 158 tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); 159 return (1); 160 } 161 162 /* 163 * Create template to be used to send tcp packets on a connection. 164 * Call after host entry created, allocates an mbuf and fills 165 * in a skeletal tcp/ip header, minimizing the amount of work 166 * necessary when the connection is used. 167 */ 168 struct tcpiphdr * 169 tcp_template(tp) 170 struct tcpcb *tp; 171 { 172 register struct inpcb *inp = tp->t_inpcb; 173 register struct in_host *h = inp->inp_fhost; 174 register struct mbuf *m; 175 register struct tcpiphdr *n; 176 177 if (h == 0) 178 return (0); 179 m = m_get(1); 180 if (m == 0) 181 return (0); 182 m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 183 m->m_len = sizeof (struct tcpiphdr); 184 n = mtod(m, struct tcpiphdr *); 185 n->ti_next = n->ti_prev = 0; 186 n->ti_x1 = 0; 187 n->ti_pr = IPPROTO_TCP; 188 n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 189 n->ti_src.s_addr = n_lhost.s_addr; 190 n->ti_dst.s_addr = h->h_addr.s_addr; 191 n->ti_sport = htons(inp->inp_lport); 192 n->ti_dport = htons(inp->inp_fport); 193 n->ti_seq = 0; 194 n->ti_ackno = 0; 195 n->ti_x2 = 0; 196 n->ti_off = 5; 197 n->ti_flags = 0; 198 n->ti_win = 0; 199 n->ti_sum = 0; 200 n->ti_urp = 0; 201 return (n); 202 } 203 204 tcp_output(tp, flags, len, dat) 205 register struct tcpcb *tp; 206 register int flags; 207 int len; 208 struct mbuf *dat; 209 { 210 register struct tcpiphdr *t; /* known to be r9 */ 211 register struct mbuf *m; 212 struct socket *so = tp->t_inpcb->inp_socket; 213 register struct ip *ip; 214 int i; 215 #ifdef TCPDEBUG 216 struct tcp_debug tdb; 217 #endif 218 COUNT(TCP_OUTPUT); 219 220 if ((t = tp->t_template) == 0) 221 return (0); 222 MGET(m, 0); 223 if (m == 0) 224 return (0); 225 m->m_off = MMAXOFF - sizeof(struct tcpiphdr); 226 m->m_len = sizeof (struct tcpiphdr); 227 m->m_next = dat; 228 if (flags & TH_SYN) 229 len--; 230 if (flags & TH_FIN) 231 len--; 232 bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr)); 233 t = mtod(m, struct tcpiphdr *); 234 if (tp->tc_flags&TC_SND_RST) { 235 flags &= ~TH_SYN; 236 flags |= TH_RST; 237 } 238 if (tp->tc_flags&TC_SYN_RCVD) 239 flags |= TH_ACK; 240 t->ti_flags = flags; 241 if (flags & TH_URG) 242 t->ti_urp = htons(tp->snd_urp); 243 t->ti_win = 244 so->so_rcv.sb_hiwat - 245 (so->so_rcv.sb_cc + tp->seqcnt); 246 if (tp->rcv_nxt + t->ti_win > tp->rcv_adv) 247 tp->rcv_adv = tp->rcv_nxt + t->ti_win; 248 if (len) 249 t->ti_len = htons(len + TCPSIZE); 250 t->ti_win = htons(t->ti_win); 251 #ifdef TCPDEBUG 252 if ((so->so_options & SO_DEBUG) || tcpconsdebug) { 253 t->ti_seq = tp->snd_nxt; 254 t->ti_ackno = tp->rcv_nxt; 255 tdb_setup(tp, t, INSEND, &tdb); 256 tdb_stuff(&tdb, -2); 257 } 258 #endif 259 t->ti_seq = htonl(tp->snd_nxt); 260 t->ti_ackno = htonl(tp->rcv_nxt); 261 t->ti_sum = 0; /* gratuitous? */ 262 CKSUM_TCPSET(m, t, r9, sizeof (struct tcpiphdr) + len); 263 ip = (struct ip *)t; 264 ip->ip_v = IPVERSION; 265 ip->ip_hl = 5; 266 ip->ip_tos = 0; 267 ip->ip_len = len + sizeof(struct tcpiphdr); 268 ip->ip_id = ip_id++; 269 ip->ip_off = 0; 270 ip->ip_ttl = MAXTTL; 271 i = ip_send(ip); 272 return (i); 273 } 274 275 tcp_fasttimo() 276 { 277 278 } 279