1*4804Swnj /* tcp_output.c 4.10 81/11/08 */ 24677Swnj 34677Swnj #include "../h/param.h" 44677Swnj #include "../h/systm.h" 54677Swnj #include "../h/mbuf.h" 64677Swnj #include "../h/socket.h" 7*4804Swnj #include "../h/socketvar.h" 8*4804Swnj #include "../net/inet_cksum.h" 9*4804Swnj #include "../net/inet.h" 10*4804Swnj #include "../net/inet_host.h" 11*4804Swnj #include "../net/inet_systm.h" 12*4804Swnj #include "../net/imp.h" 13*4804Swnj #include "../net/ip.h" 14*4804Swnj #include "../net/tcp.h" 15*4804Swnj #include "../net/tcp_var.h" 16*4804Swnj #include "../net/tcp_fsm.h" 17*4804Swnj #include "/usr/include/errno.h" 184677Swnj 194678Swnj /* 204678Swnj * Special routines to send control messages. 214678Swnj */ 224678Swnj tcp_sndctl(tp) 234678Swnj struct tcb *tp; 244678Swnj { 254678Swnj COUNT(TCP_SNDCTL); 264678Swnj 274678Swnj if (tcp_send(tp)) 284678Swnj return (1); 294678Swnj tcp_sndnull(tp); 30*4804Swnj return (0); 314678Swnj } 324678Swnj 334678Swnj tcp_sndwin(tp) 344678Swnj struct tcb *tp; 354678Swnj { 364678Swnj int ihave, hehas; 37*4804Swnj register struct socket *so = tp->t_socket; 384678Swnj COUNT(TCP_SNDWIN); 394678Swnj 404678Swnj if (tp->rcv_adv) { 41*4804Swnj ihave = so->so_rcv.sb_hiwat - 42*4804Swnj (so->so_rcv.sb_cc + tp->seqcnt); 434678Swnj hehas = tp->rcv_adv - tp->rcv_nxt; 44*4804Swnj if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35) 454678Swnj return; 464678Swnj } 474678Swnj if (tcp_send(tp)) 484678Swnj return (1); 494678Swnj tcp_sndnull(tp); 504678Swnj return (0); 514678Swnj } 524678Swnj 534678Swnj tcp_sndnull(tp) 544677Swnj register struct tcb *tp; 554677Swnj { 564678Swnj COUNT(TCP_SNDNULL); 574678Swnj 584678Swnj tcp_output(tp, 0, 0, (struct mbuf *)0); 594678Swnj tp->tc_flags &= ~TC_ACK_DUE; 604678Swnj } 614678Swnj 624678Swnj tcp_sndrst(tp, n) 634678Swnj register struct tcb *tp; 644678Swnj register struct th *n; 654678Swnj { 664678Swnj COUNT(TCP_SNDRST); 674678Swnj 684678Swnj /* don't send a reset in response to a reset */ 694678Swnj if (n->th_flags&TH_RST) 704678Swnj return; 714678Swnj tp->tc_flags |= TC_SND_RST; 724678Swnj if (n->th_flags&TH_ACK) 734678Swnj tp->snd_nxt = n->t_ackno; 744678Swnj tp->tc_flags &= ~TC_SYN_RCVD; 754678Swnj tcp_sndnull(tp); 764678Swnj tp->tc_flags &= ~TC_SND_RST; 774678Swnj } 784678Swnj 794678Swnj /* 804678Swnj * Tcp segment output routine. 814678Swnj */ 824678Swnj tcp_send(tp) 834678Swnj register struct tcb *tp; 844678Swnj { 85*4804Swnj register struct socket *so; 864677Swnj register unsigned long last, wind; 874677Swnj struct mbuf *m; 884677Swnj int flags = 0, forced, sent; 894677Swnj struct mbuf *tcp_sndcopy(); 904677Swnj int len; 914677Swnj 924678Swnj COUNT(TCP_SEND); 93*4804Swnj so = tp->t_socket; 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; 102*4804Swnj 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); 1254692Swnj m = tcp_sndcopy(tp, MAX(tp->iss+1,tp->snd_nxt), tp->snd_lst); 1264677Swnj if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 1274677Swnj flags |= TH_EOL; 1284677Swnj if ((tp->tc_flags&TC_SND_FIN) && !forced && 1294677Swnj tp->snd_lst == last && 1304677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1314677Swnj flags |= TH_FIN; 1324677Swnj tp->seq_fin = tp->snd_lst++; 1334677Swnj } 1344677Swnj } 1354698Swnj if (tp->snd_nxt >= tp->snd_lst) 1364698Swnj return (0); 1374678Swnj if (tp->tc_flags & TC_SND_URG) 1384678Swnj flags |= TH_URG; 1394678Swnj sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 1404678Swnj if (!forced) { 1414678Swnj tp->t_rexmt = tp->t_xmtime; 1424678Swnj tp->t_rexmt_val = tp->snd_lst; 1434678Swnj if ((tp->tc_flags&TC_REXMT) == 0) { 1444678Swnj tp->t_rexmttl = T_REXMTTL; 1454678Swnj tp->t_rtl_val = tp->snd_lst; 1464677Swnj } 1474677Swnj } 1484678Swnj if (sent) 1494678Swnj tp->snd_nxt = tp->snd_lst; 1504678Swnj if ((tp->tc_flags&TC_SYN_ACKED) && 1514678Swnj tp->snd_una > tp->t_xmt_val) { 1524678Swnj tp->t_xmt = 0; 1534678Swnj tp->t_xmt_val = tp->snd_lst; 1544677Swnj } 1554678Swnj tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 1564692Swnj tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); 1574678Swnj return (1); 1584677Swnj } 1594677Swnj 1604677Swnj /* 1614677Swnj * Create template to be used to send tcp packets on a connection. 1624677Swnj * Call after host entry created, allocates an mbuf and fills 1634677Swnj * in a skeletal tcp/ip header, minimizing the amount of work 1644677Swnj * necessary when the connection is used. 1654677Swnj */ 1664677Swnj struct th * 1674677Swnj tcp_template(tp) 1684677Swnj struct tcb *tp; 1694677Swnj { 170*4804Swnj register struct host *h = tp->t_host; 1714677Swnj register struct mbuf *m; 1724677Swnj register struct th *n; 1734677Swnj register struct ip *ip; 1744677Swnj 1754677Swnj if (h == 0) 1764677Swnj return (0); 1774677Swnj m = m_get(1); 1784677Swnj if (m == 0) 1794677Swnj return (0); 1804677Swnj m->m_off = MMAXOFF - sizeof (struct th); 1814677Swnj m->m_len = sizeof (struct th); 1824677Swnj n = mtod(m, struct th *); 1834677Swnj n->t_next = n->t_prev = 0; 1844677Swnj n->t_x1 = 0; 1854734Swnj n->t_pr = IPPROTO_TCP; 1864677Swnj n->t_len = htons(sizeof (struct th) - sizeof (struct ip)); 1874677Swnj n->t_s.s_addr = n_lhost.s_addr; 1884677Swnj n->t_d.s_addr = h->h_addr.s_addr; 1894677Swnj n->t_src = htons(tp->t_lport); 1904677Swnj n->t_dst = htons(tp->t_fport); 1914677Swnj n->t_seq = 0; 1924677Swnj n->t_ackno = 0; 1934677Swnj n->t_x2 = 0; 1944677Swnj n->t_off = 5; 1954677Swnj n->th_flags = 0; 1964677Swnj n->t_win = 0; 1974677Swnj n->t_sum = 0; 1984677Swnj n->t_urp = 0; 1994677Swnj return (n); 2004677Swnj } 2014677Swnj 2024677Swnj tcp_output(tp, flags, len, dat) 2034677Swnj register struct tcb *tp; 2044677Swnj register int flags; 2054677Swnj int len; 2064677Swnj struct mbuf *dat; 2074677Swnj { 2084696Swnj register struct th *t; /* known to be r9 */ 2094677Swnj register struct mbuf *m; 2104677Swnj register struct ip *ip; 2114677Swnj int i; 2124677Swnj #ifdef TCPDEBUG 2134677Swnj struct tcp_debug tdb; 2144677Swnj #endif 2154719Swnj COUNT(TCP_OUTPUT); 2164677Swnj 2174734Swnj if ((t = tp->t_template) == 0) 2184677Swnj return (0); 2194677Swnj MGET(m, 0); 2204677Swnj if (m == 0) 2214677Swnj return (0); 2224677Swnj m->m_off = MMAXOFF - sizeof(struct th); 2234677Swnj m->m_len = sizeof (struct th); 2244677Swnj m->m_next = dat; 2254677Swnj if (flags & TH_SYN) 2264677Swnj len--; 2274677Swnj if (flags & TH_FIN) 2284677Swnj len--; 2294677Swnj bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th)); 2304677Swnj t = mtod(m, struct th *); 2314677Swnj if (tp->tc_flags&TC_SND_RST) { 2324677Swnj flags &= ~TH_SYN; 2334677Swnj flags |= TH_RST; 2344677Swnj } 2354677Swnj if (tp->tc_flags&TC_SYN_RCVD) 2364677Swnj flags |= TH_ACK; 2374677Swnj t->th_flags = flags; 2384677Swnj if (flags & TH_URG) 2394677Swnj t->t_urp = htons(tp->snd_urp); 2404677Swnj t->t_win = 241*4804Swnj tp->t_socket->so_rcv.sb_hiwat - 242*4804Swnj (tp->t_socket->so_rcv.sb_cc + tp->seqcnt); 2434677Swnj if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 2444677Swnj tp->rcv_adv = tp->rcv_nxt + t->t_win; 2454677Swnj if (len) 2464677Swnj t->t_len = htons(len + TCPSIZE); 2474677Swnj t->t_win = htons(t->t_win); 2484677Swnj #ifdef TCPDEBUG 249*4804Swnj if ((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug) { 2504677Swnj t->t_seq = tp->snd_nxt; 2514677Swnj t->t_ackno = tp->rcv_nxt; 2524677Swnj tdb_setup(tp, t, INSEND, &tdb); 2534677Swnj tdb_stuff(&tdb, -2); 2544677Swnj } 2554677Swnj #endif 2564677Swnj t->t_seq = htonl(tp->snd_nxt); 2574677Swnj t->t_ackno = htonl(tp->rcv_nxt); 2584696Swnj t->t_sum = 0; /* gratuitous? */ 2594696Swnj CKSUM_TCPSET(m, t, r9, sizeof (struct th) + len); 2604677Swnj ip = (struct ip *)t; 2614677Swnj ip->ip_v = IPVERSION; 2624677Swnj ip->ip_hl = 5; 2634677Swnj ip->ip_tos = 0; 2644677Swnj ip->ip_len = len + sizeof(struct th); 2654677Swnj ip->ip_id = ip_id++; 2664677Swnj ip->ip_off = 0; 2674677Swnj ip->ip_ttl = MAXTTL; 2684677Swnj i = ip_send(ip); 269*4804Swnj return (i); 2704677Swnj } 2714677Swnj 2724677Swnj firstempty(tp) 2734677Swnj register struct tcb *tp; 2744677Swnj { 2754677Swnj register struct th *p, *q; 2764677Swnj COUNT(FIRSTEMPTY); 2774677Swnj 278*4804Swnj if ((p = tp->tcb_hd.seg_next) == (struct th *)tp || 279*4804Swnj tp->rcv_nxt < p->t_seq) 2804677Swnj return (tp->rcv_nxt); 2814677Swnj while ((q = p->t_next) != (struct th *)tp && 2824677Swnj (t_end(p) + 1) == q->t_seq) 2834677Swnj p = q; 2844677Swnj return (t_end(p) + 1); 2854677Swnj } 2864677Swnj 2874677Swnj struct mbuf * 2884677Swnj tcp_sndcopy(tp, start, end) 2894677Swnj struct tcb *tp; 2904677Swnj u_long start, end; 2914677Swnj { 2924677Swnj register struct mbuf *m, *n, **np; 2934677Swnj u_long off; 2944677Swnj register int len; 2954677Swnj int adj; 2964677Swnj struct mbuf *top, *p; 2974719Swnj COUNT(TCP_SNDCOPY); 2984677Swnj 2994677Swnj if (start >= end) 300*4804Swnj return (NULL); 3014677Swnj off = tp->snd_off; 302*4804Swnj m = tp->t_socket->so_snd.sb_mb; 3034677Swnj while (m != NULL && start >= (off + m->m_len)) { 3044677Swnj off += m->m_len; 3054677Swnj m = m->m_next; 3064677Swnj } 3074677Swnj np = ⊤ 3084677Swnj top = 0; 3094677Swnj adj = start - off; 3104677Swnj len = end - start; 3114677Swnj while (m && len > 0) { 3124677Swnj MGET(n, 1); 3134677Swnj *np = n; 3144677Swnj if (n == 0) 3154677Swnj goto nospace; 3164677Swnj n->m_len = MIN(len, m->m_len - adj); 3174677Swnj if (m->m_off > MMAXOFF) { 3184677Swnj p = mtod(m, struct mbuf *); 3194677Swnj n->m_off = ((int)p - (int)n) + adj; 3204677Swnj mprefcnt[mtopf(p)]++; 3214677Swnj } else { 3224677Swnj n->m_off = MMINOFF; 3234677Swnj bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t), 3244677Swnj n->m_len); 3254677Swnj } 3264677Swnj len -= n->m_len; 3274677Swnj adj = 0; 3284677Swnj m = m->m_next; 3294677Swnj /* SHOULD TRY PACKING INTO SMALL MBUFS HERE */ 3304677Swnj np = &n->m_next; 3314677Swnj } 3324677Swnj /* SHOULD NEVER RUN OUT OF m WHEN LEN */ 3334677Swnj if (len) 3344677Swnj printf("snd_copy: m %x len %d\n", m, len); 3354677Swnj return (top); 3364677Swnj nospace: 3374677Swnj printf("snd_copy: no space\n"); 3384677Swnj m_freem(top); 3394677Swnj return (0); 3404677Swnj } 341*4804Swnj 342*4804Swnj tcp_fasttimo() 343*4804Swnj { 344*4804Swnj 345*4804Swnj } 346