1*4885Swnj /* tcp_output.c 4.11 81/11/14 */ 24677Swnj 34677Swnj #include "../h/param.h" 44677Swnj #include "../h/systm.h" 54677Swnj #include "../h/mbuf.h" 64677Swnj #include "../h/socket.h" 74804Swnj #include "../h/socketvar.h" 84804Swnj #include "../net/inet_cksum.h" 94804Swnj #include "../net/inet.h" 104804Swnj #include "../net/inet_host.h" 11*4885Swnj #include "../net/inet_pcb.h" 124804Swnj #include "../net/inet_systm.h" 134804Swnj #include "../net/imp.h" 144804Swnj #include "../net/ip.h" 154804Swnj #include "../net/tcp.h" 164804Swnj #include "../net/tcp_var.h" 174804Swnj #include "../net/tcp_fsm.h" 184804Swnj #include "/usr/include/errno.h" 194677Swnj 204678Swnj /* 214678Swnj * Special routines to send control messages. 224678Swnj */ 234678Swnj tcp_sndctl(tp) 24*4885Swnj struct tcpcb *tp; 254678Swnj { 264678Swnj COUNT(TCP_SNDCTL); 274678Swnj 284678Swnj if (tcp_send(tp)) 294678Swnj return (1); 304678Swnj tcp_sndnull(tp); 314804Swnj return (0); 324678Swnj } 334678Swnj 344678Swnj tcp_sndwin(tp) 35*4885Swnj struct tcpcb *tp; 364678Swnj { 374678Swnj int ihave, hehas; 384678Swnj COUNT(TCP_SNDWIN); 394678Swnj 404678Swnj if (tp->rcv_adv) { 41*4885Swnj register struct socket *so = tp->t_inpcb->inp_socket; 42*4885Swnj 434804Swnj ihave = so->so_rcv.sb_hiwat - 444804Swnj (so->so_rcv.sb_cc + tp->seqcnt); 454678Swnj hehas = tp->rcv_adv - tp->rcv_nxt; 464804Swnj if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35) 474678Swnj return; 484678Swnj } 494678Swnj if (tcp_send(tp)) 504678Swnj return (1); 514678Swnj tcp_sndnull(tp); 524678Swnj return (0); 534678Swnj } 544678Swnj 554678Swnj tcp_sndnull(tp) 56*4885Swnj register struct tcpcb *tp; 574677Swnj { 584678Swnj COUNT(TCP_SNDNULL); 594678Swnj 604678Swnj tcp_output(tp, 0, 0, (struct mbuf *)0); 614678Swnj tp->tc_flags &= ~TC_ACK_DUE; 624678Swnj } 634678Swnj 644678Swnj tcp_sndrst(tp, n) 65*4885Swnj register struct tcpcb *tp; 66*4885Swnj register struct tcpiphdr *n; 674678Swnj { 684678Swnj COUNT(TCP_SNDRST); 694678Swnj 704678Swnj /* don't send a reset in response to a reset */ 714678Swnj if (n->th_flags&TH_RST) 724678Swnj return; 734678Swnj tp->tc_flags |= TC_SND_RST; 744678Swnj if (n->th_flags&TH_ACK) 754678Swnj tp->snd_nxt = n->t_ackno; 764678Swnj tp->tc_flags &= ~TC_SYN_RCVD; 774678Swnj tcp_sndnull(tp); 784678Swnj tp->tc_flags &= ~TC_SND_RST; 794678Swnj } 804678Swnj 814678Swnj /* 824678Swnj * Tcp segment output routine. 834678Swnj */ 844678Swnj tcp_send(tp) 85*4885Swnj register struct tcpcb *tp; 864678Swnj { 874677Swnj register unsigned long last, wind; 88*4885Swnj register struct socket *so = tp->t_inpcb->inp_socket; 894677Swnj struct mbuf *m; 90*4885Swnj int flags = 0, forced, sent, len; 914677Swnj 924678Swnj COUNT(TCP_SEND); 934677Swnj tp->snd_lst = tp->snd_nxt; 944677Swnj forced = 0; 954677Swnj m = NULL; 964678Swnj if (tp->snd_nxt == tp->iss) { 974677Swnj flags |= TH_SYN; 984677Swnj tp->snd_lst++; 994677Swnj } 1004677Swnj last = tp->snd_off; 1014804Swnj for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next) 1024677Swnj last += m->m_len; 1034677Swnj if (tp->snd_nxt > last) { 1044677Swnj if ((tp->tc_flags&TC_SND_FIN) && 1054677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1064677Swnj 1074677Swnj flags |= TH_FIN; 1084677Swnj tp->seq_fin = tp->snd_lst++; 1094677Swnj } 1104678Swnj } else { 1114677Swnj if (tp->tc_flags&TC_SYN_ACKED) { 1124677Swnj wind = tp->snd_una + tp->snd_wnd; 1134677Swnj tp->snd_lst = min(last, wind); 1144677Swnj if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 1154677Swnj tp->snd_lst -= len - 1024; 1164677Swnj if (tp->snd_lst >= wind) 1174677Swnj tp->t_persist = T_PERS; 1184677Swnj } 1194677Swnj if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 1204677Swnj tp->snd_lst = tp->snd_nxt + 1; 1214677Swnj forced = 1; 1224698Swnj } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0) 1234692Swnj return (0); 124*4885Swnj m = sb_copy(&so->so_snd, 125*4885Swnj MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off, 126*4885Swnj tp->snd_lst - tp->snd_off); 1274677Swnj if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 1284677Swnj flags |= TH_EOL; 1294677Swnj if ((tp->tc_flags&TC_SND_FIN) && !forced && 1304677Swnj tp->snd_lst == last && 1314677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1324677Swnj flags |= TH_FIN; 1334677Swnj tp->seq_fin = tp->snd_lst++; 1344677Swnj } 1354677Swnj } 1364698Swnj if (tp->snd_nxt >= tp->snd_lst) 1374698Swnj return (0); 1384678Swnj if (tp->tc_flags & TC_SND_URG) 1394678Swnj flags |= TH_URG; 1404678Swnj sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 1414678Swnj if (!forced) { 1424678Swnj tp->t_rexmt = tp->t_xmtime; 1434678Swnj tp->t_rexmt_val = tp->snd_lst; 1444678Swnj if ((tp->tc_flags&TC_REXMT) == 0) { 1454678Swnj tp->t_rexmttl = T_REXMTTL; 1464678Swnj tp->t_rtl_val = tp->snd_lst; 1474677Swnj } 1484677Swnj } 1494678Swnj if (sent) 1504678Swnj tp->snd_nxt = tp->snd_lst; 1514678Swnj if ((tp->tc_flags&TC_SYN_ACKED) && 1524678Swnj tp->snd_una > tp->t_xmt_val) { 1534678Swnj tp->t_xmt = 0; 1544678Swnj tp->t_xmt_val = tp->snd_lst; 1554677Swnj } 1564678Swnj tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 1574692Swnj tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); 1584678Swnj return (1); 1594677Swnj } 1604677Swnj 1614677Swnj /* 1624677Swnj * Create template to be used to send tcp packets on a connection. 1634677Swnj * Call after host entry created, allocates an mbuf and fills 1644677Swnj * in a skeletal tcp/ip header, minimizing the amount of work 1654677Swnj * necessary when the connection is used. 1664677Swnj */ 167*4885Swnj struct tcpiphdr * 1684677Swnj tcp_template(tp) 169*4885Swnj struct tcpcb *tp; 1704677Swnj { 171*4885Swnj register struct inpcb *inp = tp->t_inpcb; 172*4885Swnj register struct in_host *h = inp->inp_fhost; 1734677Swnj register struct mbuf *m; 174*4885Swnj register struct tcpiphdr *n; 1754677Swnj 1764677Swnj if (h == 0) 1774677Swnj return (0); 1784677Swnj m = m_get(1); 1794677Swnj if (m == 0) 1804677Swnj return (0); 181*4885Swnj m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 182*4885Swnj m->m_len = sizeof (struct tcpiphdr); 183*4885Swnj n = mtod(m, struct tcpiphdr *); 1844677Swnj n->t_next = n->t_prev = 0; 1854677Swnj n->t_x1 = 0; 1864734Swnj n->t_pr = IPPROTO_TCP; 187*4885Swnj n->t_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 1884677Swnj n->t_s.s_addr = n_lhost.s_addr; 1894677Swnj n->t_d.s_addr = h->h_addr.s_addr; 190*4885Swnj n->t_src = htons(inp->inp_lport); 191*4885Swnj n->t_dst = htons(inp->inp_fport); 1924677Swnj n->t_seq = 0; 1934677Swnj n->t_ackno = 0; 1944677Swnj n->t_x2 = 0; 1954677Swnj n->t_off = 5; 1964677Swnj n->th_flags = 0; 1974677Swnj n->t_win = 0; 1984677Swnj n->t_sum = 0; 1994677Swnj n->t_urp = 0; 2004677Swnj return (n); 2014677Swnj } 2024677Swnj 2034677Swnj tcp_output(tp, flags, len, dat) 204*4885Swnj register struct tcpcb *tp; 2054677Swnj register int flags; 2064677Swnj int len; 2074677Swnj struct mbuf *dat; 2084677Swnj { 209*4885Swnj register struct tcpiphdr *t; /* known to be r9 */ 2104677Swnj register struct mbuf *m; 211*4885Swnj struct socket *so = tp->t_inpcb->inp_socket; 2124677Swnj register struct ip *ip; 2134677Swnj int i; 2144677Swnj #ifdef TCPDEBUG 2154677Swnj struct tcp_debug tdb; 2164677Swnj #endif 2174719Swnj COUNT(TCP_OUTPUT); 2184677Swnj 2194734Swnj if ((t = tp->t_template) == 0) 2204677Swnj return (0); 2214677Swnj MGET(m, 0); 2224677Swnj if (m == 0) 2234677Swnj return (0); 224*4885Swnj m->m_off = MMAXOFF - sizeof(struct tcpiphdr); 225*4885Swnj m->m_len = sizeof (struct tcpiphdr); 2264677Swnj m->m_next = dat; 2274677Swnj if (flags & TH_SYN) 2284677Swnj len--; 2294677Swnj if (flags & TH_FIN) 2304677Swnj len--; 231*4885Swnj bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr)); 232*4885Swnj t = mtod(m, struct tcpiphdr *); 2334677Swnj if (tp->tc_flags&TC_SND_RST) { 2344677Swnj flags &= ~TH_SYN; 2354677Swnj flags |= TH_RST; 2364677Swnj } 2374677Swnj if (tp->tc_flags&TC_SYN_RCVD) 2384677Swnj flags |= TH_ACK; 2394677Swnj t->th_flags = flags; 2404677Swnj if (flags & TH_URG) 2414677Swnj t->t_urp = htons(tp->snd_urp); 2424677Swnj t->t_win = 243*4885Swnj so->so_rcv.sb_hiwat - 244*4885Swnj (so->so_rcv.sb_cc + tp->seqcnt); 2454677Swnj if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 2464677Swnj tp->rcv_adv = tp->rcv_nxt + t->t_win; 2474677Swnj if (len) 2484677Swnj t->t_len = htons(len + TCPSIZE); 2494677Swnj t->t_win = htons(t->t_win); 2504677Swnj #ifdef TCPDEBUG 251*4885Swnj if ((so->so_options & SO_DEBUG) || tcpconsdebug) { 2524677Swnj t->t_seq = tp->snd_nxt; 2534677Swnj t->t_ackno = tp->rcv_nxt; 2544677Swnj tdb_setup(tp, t, INSEND, &tdb); 2554677Swnj tdb_stuff(&tdb, -2); 2564677Swnj } 2574677Swnj #endif 2584677Swnj t->t_seq = htonl(tp->snd_nxt); 2594677Swnj t->t_ackno = htonl(tp->rcv_nxt); 2604696Swnj t->t_sum = 0; /* gratuitous? */ 261*4885Swnj CKSUM_TCPSET(m, t, r9, sizeof (struct tcpiphdr) + len); 2624677Swnj ip = (struct ip *)t; 2634677Swnj ip->ip_v = IPVERSION; 2644677Swnj ip->ip_hl = 5; 2654677Swnj ip->ip_tos = 0; 266*4885Swnj ip->ip_len = len + sizeof(struct tcpiphdr); 2674677Swnj ip->ip_id = ip_id++; 2684677Swnj ip->ip_off = 0; 2694677Swnj ip->ip_ttl = MAXTTL; 2704677Swnj i = ip_send(ip); 2714804Swnj return (i); 2724677Swnj } 2734677Swnj 2744804Swnj tcp_fasttimo() 2754804Swnj { 2764804Swnj 2774804Swnj } 278