1*4900Swnj /* tcp_output.c 4.12 81/11/15 */ 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" 114885Swnj #include "../net/inet_pcb.h" 124804Swnj #include "../net/inet_systm.h" 134804Swnj #include "../net/imp.h" 144804Swnj #include "../net/ip.h" 15*4900Swnj #include "../net/ip_var.h" 164804Swnj #include "../net/tcp.h" 174804Swnj #include "../net/tcp_var.h" 184804Swnj #include "../net/tcp_fsm.h" 194804Swnj #include "/usr/include/errno.h" 204677Swnj 214678Swnj /* 224678Swnj * Special routines to send control messages. 234678Swnj */ 244678Swnj tcp_sndctl(tp) 254885Swnj struct tcpcb *tp; 264678Swnj { 274678Swnj COUNT(TCP_SNDCTL); 284678Swnj 294678Swnj if (tcp_send(tp)) 304678Swnj return (1); 314678Swnj tcp_sndnull(tp); 324804Swnj return (0); 334678Swnj } 344678Swnj 354678Swnj tcp_sndwin(tp) 364885Swnj struct tcpcb *tp; 374678Swnj { 384678Swnj int ihave, hehas; 394678Swnj COUNT(TCP_SNDWIN); 404678Swnj 414678Swnj if (tp->rcv_adv) { 424885Swnj register struct socket *so = tp->t_inpcb->inp_socket; 434885Swnj 444804Swnj ihave = so->so_rcv.sb_hiwat - 454804Swnj (so->so_rcv.sb_cc + tp->seqcnt); 464678Swnj hehas = tp->rcv_adv - tp->rcv_nxt; 474804Swnj if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35) 484678Swnj return; 494678Swnj } 504678Swnj if (tcp_send(tp)) 514678Swnj return (1); 524678Swnj tcp_sndnull(tp); 534678Swnj return (0); 544678Swnj } 554678Swnj 564678Swnj tcp_sndnull(tp) 574885Swnj register struct tcpcb *tp; 584677Swnj { 594678Swnj COUNT(TCP_SNDNULL); 604678Swnj 614678Swnj tcp_output(tp, 0, 0, (struct mbuf *)0); 624678Swnj tp->tc_flags &= ~TC_ACK_DUE; 634678Swnj } 644678Swnj 654678Swnj tcp_sndrst(tp, n) 664885Swnj register struct tcpcb *tp; 674885Swnj register struct tcpiphdr *n; 684678Swnj { 694678Swnj COUNT(TCP_SNDRST); 704678Swnj 714678Swnj /* don't send a reset in response to a reset */ 72*4900Swnj if (n->ti_flags&TH_RST) 734678Swnj return; 744678Swnj tp->tc_flags |= TC_SND_RST; 75*4900Swnj if (n->ti_flags&TH_ACK) 76*4900Swnj tp->snd_nxt = n->ti_ackno; 774678Swnj tp->tc_flags &= ~TC_SYN_RCVD; 784678Swnj tcp_sndnull(tp); 794678Swnj tp->tc_flags &= ~TC_SND_RST; 804678Swnj } 814678Swnj 824678Swnj /* 834678Swnj * Tcp segment output routine. 844678Swnj */ 854678Swnj tcp_send(tp) 864885Swnj register struct tcpcb *tp; 874678Swnj { 884677Swnj register unsigned long last, wind; 894885Swnj register struct socket *so = tp->t_inpcb->inp_socket; 904677Swnj struct mbuf *m; 914885Swnj int flags = 0, forced, sent, len; 924677Swnj 934678Swnj COUNT(TCP_SEND); 944677Swnj tp->snd_lst = tp->snd_nxt; 954677Swnj forced = 0; 964677Swnj m = NULL; 974678Swnj if (tp->snd_nxt == tp->iss) { 984677Swnj flags |= TH_SYN; 994677Swnj tp->snd_lst++; 1004677Swnj } 1014677Swnj last = tp->snd_off; 1024804Swnj for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next) 1034677Swnj last += m->m_len; 1044677Swnj if (tp->snd_nxt > last) { 1054677Swnj if ((tp->tc_flags&TC_SND_FIN) && 1064677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1074677Swnj 1084677Swnj flags |= TH_FIN; 1094677Swnj tp->seq_fin = tp->snd_lst++; 1104677Swnj } 1114678Swnj } else { 1124677Swnj if (tp->tc_flags&TC_SYN_ACKED) { 1134677Swnj wind = tp->snd_una + tp->snd_wnd; 1144677Swnj tp->snd_lst = min(last, wind); 1154677Swnj if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 1164677Swnj tp->snd_lst -= len - 1024; 1174677Swnj if (tp->snd_lst >= wind) 1184677Swnj tp->t_persist = T_PERS; 1194677Swnj } 1204677Swnj if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 1214677Swnj tp->snd_lst = tp->snd_nxt + 1; 1224677Swnj forced = 1; 1234698Swnj } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0) 1244692Swnj return (0); 1254885Swnj m = sb_copy(&so->so_snd, 1264885Swnj MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off, 1274885Swnj tp->snd_lst - tp->snd_off); 1284677Swnj if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 1294677Swnj flags |= TH_EOL; 1304677Swnj if ((tp->tc_flags&TC_SND_FIN) && !forced && 1314677Swnj tp->snd_lst == last && 1324677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1334677Swnj flags |= TH_FIN; 1344677Swnj tp->seq_fin = tp->snd_lst++; 1354677Swnj } 1364677Swnj } 1374698Swnj if (tp->snd_nxt >= tp->snd_lst) 1384698Swnj return (0); 1394678Swnj if (tp->tc_flags & TC_SND_URG) 1404678Swnj flags |= TH_URG; 1414678Swnj sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 1424678Swnj if (!forced) { 1434678Swnj tp->t_rexmt = tp->t_xmtime; 1444678Swnj tp->t_rexmt_val = tp->snd_lst; 1454678Swnj if ((tp->tc_flags&TC_REXMT) == 0) { 1464678Swnj tp->t_rexmttl = T_REXMTTL; 1474678Swnj tp->t_rtl_val = tp->snd_lst; 1484677Swnj } 1494677Swnj } 1504678Swnj if (sent) 1514678Swnj tp->snd_nxt = tp->snd_lst; 1524678Swnj if ((tp->tc_flags&TC_SYN_ACKED) && 1534678Swnj tp->snd_una > tp->t_xmt_val) { 1544678Swnj tp->t_xmt = 0; 1554678Swnj tp->t_xmt_val = tp->snd_lst; 1564677Swnj } 1574678Swnj tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 1584692Swnj tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); 1594678Swnj return (1); 1604677Swnj } 1614677Swnj 1624677Swnj /* 1634677Swnj * Create template to be used to send tcp packets on a connection. 1644677Swnj * Call after host entry created, allocates an mbuf and fills 1654677Swnj * in a skeletal tcp/ip header, minimizing the amount of work 1664677Swnj * necessary when the connection is used. 1674677Swnj */ 1684885Swnj struct tcpiphdr * 1694677Swnj tcp_template(tp) 1704885Swnj struct tcpcb *tp; 1714677Swnj { 1724885Swnj register struct inpcb *inp = tp->t_inpcb; 1734885Swnj register struct in_host *h = inp->inp_fhost; 1744677Swnj register struct mbuf *m; 1754885Swnj register struct tcpiphdr *n; 1764677Swnj 1774677Swnj if (h == 0) 1784677Swnj return (0); 1794677Swnj m = m_get(1); 1804677Swnj if (m == 0) 1814677Swnj return (0); 1824885Swnj m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 1834885Swnj m->m_len = sizeof (struct tcpiphdr); 1844885Swnj n = mtod(m, struct tcpiphdr *); 185*4900Swnj n->ti_next = n->ti_prev = 0; 186*4900Swnj n->ti_x1 = 0; 187*4900Swnj n->ti_pr = IPPROTO_TCP; 188*4900Swnj n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 189*4900Swnj n->ti_src.s_addr = n_lhost.s_addr; 190*4900Swnj n->ti_dst.s_addr = h->h_addr.s_addr; 191*4900Swnj n->ti_sport = htons(inp->inp_lport); 192*4900Swnj n->ti_dport = htons(inp->inp_fport); 193*4900Swnj n->ti_seq = 0; 194*4900Swnj n->ti_ackno = 0; 195*4900Swnj n->ti_x2 = 0; 196*4900Swnj n->ti_off = 5; 197*4900Swnj n->ti_flags = 0; 198*4900Swnj n->ti_win = 0; 199*4900Swnj n->ti_sum = 0; 200*4900Swnj n->ti_urp = 0; 2014677Swnj return (n); 2024677Swnj } 2034677Swnj 2044677Swnj tcp_output(tp, flags, len, dat) 2054885Swnj register struct tcpcb *tp; 2064677Swnj register int flags; 2074677Swnj int len; 2084677Swnj struct mbuf *dat; 2094677Swnj { 2104885Swnj register struct tcpiphdr *t; /* known to be r9 */ 2114677Swnj register struct mbuf *m; 2124885Swnj struct socket *so = tp->t_inpcb->inp_socket; 2134677Swnj register struct ip *ip; 2144677Swnj int i; 2154677Swnj #ifdef TCPDEBUG 2164677Swnj struct tcp_debug tdb; 2174677Swnj #endif 2184719Swnj COUNT(TCP_OUTPUT); 2194677Swnj 2204734Swnj if ((t = tp->t_template) == 0) 2214677Swnj return (0); 2224677Swnj MGET(m, 0); 2234677Swnj if (m == 0) 2244677Swnj return (0); 2254885Swnj m->m_off = MMAXOFF - sizeof(struct tcpiphdr); 2264885Swnj m->m_len = sizeof (struct tcpiphdr); 2274677Swnj m->m_next = dat; 2284677Swnj if (flags & TH_SYN) 2294677Swnj len--; 2304677Swnj if (flags & TH_FIN) 2314677Swnj len--; 2324885Swnj bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr)); 2334885Swnj t = mtod(m, struct tcpiphdr *); 2344677Swnj if (tp->tc_flags&TC_SND_RST) { 2354677Swnj flags &= ~TH_SYN; 2364677Swnj flags |= TH_RST; 2374677Swnj } 2384677Swnj if (tp->tc_flags&TC_SYN_RCVD) 2394677Swnj flags |= TH_ACK; 240*4900Swnj t->ti_flags = flags; 2414677Swnj if (flags & TH_URG) 242*4900Swnj t->ti_urp = htons(tp->snd_urp); 243*4900Swnj t->ti_win = 2444885Swnj so->so_rcv.sb_hiwat - 2454885Swnj (so->so_rcv.sb_cc + tp->seqcnt); 246*4900Swnj if (tp->rcv_nxt + t->ti_win > tp->rcv_adv) 247*4900Swnj tp->rcv_adv = tp->rcv_nxt + t->ti_win; 2484677Swnj if (len) 249*4900Swnj t->ti_len = htons(len + TCPSIZE); 250*4900Swnj t->ti_win = htons(t->ti_win); 2514677Swnj #ifdef TCPDEBUG 2524885Swnj if ((so->so_options & SO_DEBUG) || tcpconsdebug) { 253*4900Swnj t->ti_seq = tp->snd_nxt; 254*4900Swnj t->ti_ackno = tp->rcv_nxt; 2554677Swnj tdb_setup(tp, t, INSEND, &tdb); 2564677Swnj tdb_stuff(&tdb, -2); 2574677Swnj } 2584677Swnj #endif 259*4900Swnj t->ti_seq = htonl(tp->snd_nxt); 260*4900Swnj t->ti_ackno = htonl(tp->rcv_nxt); 261*4900Swnj t->ti_sum = 0; /* gratuitous? */ 2624885Swnj CKSUM_TCPSET(m, t, r9, sizeof (struct tcpiphdr) + len); 2634677Swnj ip = (struct ip *)t; 2644677Swnj ip->ip_v = IPVERSION; 2654677Swnj ip->ip_hl = 5; 2664677Swnj ip->ip_tos = 0; 2674885Swnj ip->ip_len = len + sizeof(struct tcpiphdr); 2684677Swnj ip->ip_id = ip_id++; 2694677Swnj ip->ip_off = 0; 2704677Swnj ip->ip_ttl = MAXTTL; 2714677Swnj i = ip_send(ip); 2724804Swnj return (i); 2734677Swnj } 2744677Swnj 2754804Swnj tcp_fasttimo() 2764804Swnj { 2774804Swnj 2784804Swnj } 279