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