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