1*4688Swnj /* tcp_output.c 4.4 81/10/31 */ 24677Swnj 34677Swnj #include "../h/param.h" 44677Swnj #include "../h/systm.h" 54677Swnj #include "../h/mbuf.h" 64677Swnj #include "../h/socket.h" 74677Swnj #include "../inet/inet.h" 84677Swnj #include "../inet/inet_host.h" 94677Swnj #include "../inet/inet_systm.h" 104677Swnj #include "../inet/imp.h" 114677Swnj #include "../inet/ip.h" 124677Swnj #include "../inet/tcp.h" 134677Swnj #include "../inet/tcp_fsm.h" 144677Swnj 154678Swnj /* 164678Swnj * Special routines to send control messages. 174678Swnj */ 184678Swnj tcp_sndctl(tp) 194678Swnj struct tcb *tp; 204678Swnj { 214678Swnj COUNT(TCP_SNDCTL); 224678Swnj 234678Swnj if (tcp_send(tp)) 244678Swnj return (1); 254678Swnj tcp_sndnull(tp); 264678Swnj return(0); 274678Swnj } 284678Swnj 294678Swnj tcp_sndwin(tp) 304678Swnj struct tcb *tp; 314678Swnj { 324678Swnj int ihave, hehas; 334678Swnj COUNT(TCP_SNDWIN); 344678Swnj 354678Swnj if (tp->rcv_adv) { 364678Swnj ihave = tp->t_ucb->uc_rhiwat - 374678Swnj (tp->t_ucb->uc_rcc + tp->seqcnt); 384678Swnj hehas = tp->rcv_adv - tp->rcv_nxt; 39*4688Swnj if ((100*(ihave-hehas)/tp->t_ucb->uc_rhiwat) < 35) 404678Swnj return; 414678Swnj } 424678Swnj if (tcp_send(tp)) 434678Swnj return (1); 444678Swnj tcp_sndnull(tp); 454678Swnj return (0); 464678Swnj } 474678Swnj 484678Swnj tcp_sndnull(tp) 494677Swnj register struct tcb *tp; 504677Swnj { 514678Swnj COUNT(TCP_SNDNULL); 524678Swnj 534678Swnj tcp_output(tp, 0, 0, (struct mbuf *)0); 544678Swnj tp->tc_flags &= ~TC_ACK_DUE; 554678Swnj } 564678Swnj 574678Swnj tcp_sndrst(tp, n) 584678Swnj register struct tcb *tp; 594678Swnj register struct th *n; 604678Swnj { 614678Swnj COUNT(TCP_SNDRST); 624678Swnj 634678Swnj /* don't send a reset in response to a reset */ 644678Swnj if (n->th_flags&TH_RST) 654678Swnj return; 664678Swnj tp->tc_flags |= TC_SND_RST; 674678Swnj if (n->th_flags&TH_ACK) 684678Swnj tp->snd_nxt = n->t_ackno; 694678Swnj tp->tc_flags &= ~TC_SYN_RCVD; 704678Swnj tcp_sndnull(tp); 714678Swnj tp->tc_flags &= ~TC_SND_RST; 724678Swnj } 734678Swnj 744678Swnj /* 754678Swnj * Tcp segment output routine. 764678Swnj */ 774678Swnj tcp_send(tp) 784678Swnj register struct tcb *tp; 794678Swnj { 804677Swnj register struct ucb *up; 814677Swnj register unsigned long last, wind; 824677Swnj struct mbuf *m; 834677Swnj int flags = 0, forced, sent; 844677Swnj struct mbuf *tcp_sndcopy(); 854677Swnj int len; 864677Swnj 874678Swnj COUNT(TCP_SEND); 884677Swnj up = tp->t_ucb; 894677Swnj tp->snd_lst = tp->snd_nxt; 904677Swnj forced = 0; 914677Swnj m = NULL; 924678Swnj if (tp->snd_nxt == tp->iss) { 934677Swnj flags |= TH_SYN; 944677Swnj tp->snd_lst++; 954677Swnj } 964677Swnj last = tp->snd_off; 974677Swnj for (m = up->uc_sbuf; m != NULL; m = m->m_next) 984677Swnj last += m->m_len; 994677Swnj if (tp->snd_nxt > last) { 1004677Swnj if ((tp->tc_flags&TC_SND_FIN) && 1014677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1024677Swnj 1034677Swnj flags |= TH_FIN; 1044677Swnj tp->seq_fin = tp->snd_lst++; 1054677Swnj } 1064678Swnj } else { 1074677Swnj if (tp->tc_flags&TC_SYN_ACKED) { 1084677Swnj wind = tp->snd_una + tp->snd_wnd; 1094677Swnj tp->snd_lst = min(last, wind); 1104677Swnj if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 1114677Swnj tp->snd_lst -= len - 1024; 1124677Swnj if (tp->snd_lst >= wind) 1134677Swnj tp->t_persist = T_PERS; 1144677Swnj } 1154677Swnj if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 1164677Swnj tp->snd_lst = tp->snd_nxt + 1; 1174677Swnj forced = 1; 1184677Swnj } 1194677Swnj m = tcp_sndcopy(tp, max(tp->iss+1,tp->snd_nxt), tp->snd_lst); 1204677Swnj if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 1214677Swnj flags |= TH_EOL; 1224677Swnj if ((tp->tc_flags&TC_SND_FIN) && !forced && 1234677Swnj tp->snd_lst == last && 1244677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1254677Swnj flags |= TH_FIN; 1264677Swnj tp->seq_fin = tp->snd_lst++; 1274677Swnj } 1284677Swnj } 1294678Swnj if (tp->snd_nxt >= tp->snd_lst) 1304678Swnj return (0); 1314678Swnj if (tp->tc_flags & TC_SND_URG) 1324678Swnj flags |= TH_URG; 1334678Swnj sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 1344678Swnj if (!forced) { 1354678Swnj tp->t_rexmt = tp->t_xmtime; 1364678Swnj tp->t_rexmt_val = tp->snd_lst; 1374678Swnj if ((tp->tc_flags&TC_REXMT) == 0) { 1384678Swnj tp->t_rexmttl = T_REXMTTL; 1394678Swnj tp->t_rtl_val = tp->snd_lst; 1404677Swnj } 1414677Swnj } 1424678Swnj if (sent) 1434678Swnj tp->snd_nxt = tp->snd_lst; 1444678Swnj if ((tp->tc_flags&TC_SYN_ACKED) && 1454678Swnj tp->snd_una > tp->t_xmt_val) { 1464678Swnj tp->t_xmt = 0; 1474678Swnj tp->t_xmt_val = tp->snd_lst; 1484677Swnj } 1494678Swnj tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 1504678Swnj tp->snd_hi = max(tp->snd_nxt, tp->snd_hi); 1514678Swnj return (1); 1524677Swnj } 1534677Swnj 1544677Swnj /* 1554677Swnj * Create template to be used to send tcp packets on a connection. 1564677Swnj * Call after host entry created, allocates an mbuf and fills 1574677Swnj * in a skeletal tcp/ip header, minimizing the amount of work 1584677Swnj * necessary when the connection is used. 1594677Swnj */ 1604677Swnj struct th * 1614677Swnj tcp_template(tp) 1624677Swnj struct tcb *tp; 1634677Swnj { 1644677Swnj register struct host *h = tp->t_ucb->uc_host; 1654677Swnj register struct mbuf *m; 1664677Swnj register struct th *n; 1674677Swnj register struct ip *ip; 1684677Swnj 1694677Swnj if (h == 0) 1704677Swnj return (0); 1714677Swnj m = m_get(1); 1724677Swnj if (m == 0) 1734677Swnj return (0); 1744677Swnj m->m_off = MMAXOFF - sizeof (struct th); 1754677Swnj m->m_len = sizeof (struct th); 1764677Swnj n = mtod(m, struct th *); 1774677Swnj n->t_next = n->t_prev = 0; 1784677Swnj n->t_x1 = 0; 1794677Swnj n->t_pr = TCPROTO; 1804677Swnj n->t_len = htons(sizeof (struct th) - sizeof (struct ip)); 1814677Swnj n->t_s.s_addr = n_lhost.s_addr; 1824677Swnj n->t_d.s_addr = h->h_addr.s_addr; 1834677Swnj n->t_src = htons(tp->t_lport); 1844677Swnj n->t_dst = htons(tp->t_fport); 1854677Swnj n->t_seq = 0; 1864677Swnj n->t_ackno = 0; 1874677Swnj n->t_x2 = 0; 1884677Swnj n->t_off = 5; 1894677Swnj n->th_flags = 0; 1904677Swnj n->t_win = 0; 1914677Swnj n->t_sum = 0; 1924677Swnj n->t_urp = 0; 1934677Swnj return (n); 1944677Swnj } 1954677Swnj 1964677Swnj tcp_output(tp, flags, len, dat) 1974677Swnj register struct tcb *tp; 1984677Swnj register int flags; 1994677Swnj int len; 2004677Swnj struct mbuf *dat; 2014677Swnj { 2024677Swnj register struct mbuf *m; 2034677Swnj register struct th *t; 2044677Swnj register struct ip *ip; 2054677Swnj int i; 2064677Swnj #ifdef TCPDEBUG 2074677Swnj struct tcp_debug tdb; 2084677Swnj #endif 2094677Swnj COUNT(SEND_TCP); 2104677Swnj 2114677Swnj if ((t = tp->t_ucb->uc_template) == 0) 2124677Swnj return (0); 2134677Swnj MGET(m, 0); 2144677Swnj if (m == 0) 2154677Swnj return (0); 2164677Swnj m->m_off = MMAXOFF - sizeof(struct th); 2174677Swnj m->m_len = sizeof (struct th); 2184677Swnj m->m_next = dat; 2194677Swnj if (flags & TH_SYN) 2204677Swnj len--; 2214677Swnj if (flags & TH_FIN) 2224677Swnj len--; 2234677Swnj bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th)); 2244677Swnj t = mtod(m, struct th *); 2254677Swnj if (tp->tc_flags&TC_SND_RST) { 2264677Swnj flags &= ~TH_SYN; 2274677Swnj flags |= TH_RST; 2284677Swnj } 2294677Swnj if (tp->tc_flags&TC_SYN_RCVD) 2304677Swnj flags |= TH_ACK; 2314677Swnj t->th_flags = flags; 2324677Swnj if (flags & TH_URG) 2334677Swnj t->t_urp = htons(tp->snd_urp); 2344677Swnj t->t_win = 2354677Swnj tp->t_ucb->uc_rhiwat - (tp->t_ucb->uc_rcc + tp->seqcnt); 2364677Swnj if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 2374677Swnj tp->rcv_adv = tp->rcv_nxt + t->t_win; 2384677Swnj if (len) 2394677Swnj t->t_len = htons(len + TCPSIZE); 2404677Swnj t->t_win = htons(t->t_win); 2414677Swnj #ifdef TCPDEBUG 2424677Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 2434677Swnj t->t_seq = tp->snd_nxt; 2444677Swnj t->t_ackno = tp->rcv_nxt; 2454677Swnj tdb_setup(tp, t, INSEND, &tdb); 2464677Swnj tdb_stuff(&tdb, -2); 2474677Swnj } 2484677Swnj #endif 2494677Swnj t->t_seq = htonl(tp->snd_nxt); 2504677Swnj t->t_ackno = htonl(tp->rcv_nxt); 2514677Swnj t->t_sum = cksum(m, len + sizeof(struct th)); 2524677Swnj ip = (struct ip *)t; 2534677Swnj ip->ip_v = IPVERSION; 2544677Swnj ip->ip_hl = 5; 2554677Swnj ip->ip_tos = 0; 2564677Swnj ip->ip_len = len + sizeof(struct th); 2574677Swnj ip->ip_id = ip_id++; 2584677Swnj ip->ip_off = 0; 2594677Swnj ip->ip_ttl = MAXTTL; 2604677Swnj i = ip_send(ip); 2614677Swnj return(i); 2624677Swnj } 2634677Swnj 2644677Swnj firstempty(tp) 2654677Swnj register struct tcb *tp; 2664677Swnj { 2674677Swnj register struct th *p, *q; 2684677Swnj COUNT(FIRSTEMPTY); 2694677Swnj 2704677Swnj if ((p = tp->t_rcv_next) == (struct th *)tp || tp->rcv_nxt < p->t_seq) 2714677Swnj return (tp->rcv_nxt); 2724677Swnj while ((q = p->t_next) != (struct th *)tp && 2734677Swnj (t_end(p) + 1) == q->t_seq) 2744677Swnj p = q; 2754677Swnj return (t_end(p) + 1); 2764677Swnj } 2774677Swnj 2784677Swnj struct mbuf * 2794677Swnj tcp_sndcopy(tp, start, end) 2804677Swnj struct tcb *tp; 2814677Swnj u_long start, end; 2824677Swnj { 2834677Swnj register struct mbuf *m, *n, **np; 2844677Swnj u_long off; 2854677Swnj register int len; 2864677Swnj int adj; 2874677Swnj struct mbuf *top, *p; 2884677Swnj COUNT(SND_COPY); 2894677Swnj 2904677Swnj if (start >= end) 2914677Swnj return(NULL); 2924677Swnj off = tp->snd_off; 2934677Swnj m = tp->t_ucb->uc_sbuf; 2944677Swnj while (m != NULL && start >= (off + m->m_len)) { 2954677Swnj off += m->m_len; 2964677Swnj m = m->m_next; 2974677Swnj } 2984677Swnj np = ⊤ 2994677Swnj top = 0; 3004677Swnj adj = start - off; 3014677Swnj len = end - start; 3024677Swnj while (m && len > 0) { 3034677Swnj MGET(n, 1); 3044677Swnj *np = n; 3054677Swnj if (n == 0) 3064677Swnj goto nospace; 3074677Swnj n->m_len = MIN(len, m->m_len - adj); 3084677Swnj if (m->m_off > MMAXOFF) { 3094677Swnj p = mtod(m, struct mbuf *); 3104677Swnj n->m_off = ((int)p - (int)n) + adj; 3114677Swnj mprefcnt[mtopf(p)]++; 3124677Swnj } else { 3134677Swnj n->m_off = MMINOFF; 3144677Swnj bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t), 3154677Swnj n->m_len); 3164677Swnj } 3174677Swnj len -= n->m_len; 3184677Swnj adj = 0; 3194677Swnj m = m->m_next; 3204677Swnj /* SHOULD TRY PACKING INTO SMALL MBUFS HERE */ 3214677Swnj np = &n->m_next; 3224677Swnj } 3234677Swnj /* SHOULD NEVER RUN OUT OF m WHEN LEN */ 3244677Swnj if (len) 3254677Swnj printf("snd_copy: m %x len %d\n", m, len); 3264677Swnj return (top); 3274677Swnj nospace: 3284677Swnj printf("snd_copy: no space\n"); 3294677Swnj m_freem(top); 3304677Swnj return (0); 3314677Swnj } 3324677Swnj 3334677Swnj tcp_enq(p, prev) 3344677Swnj register struct th *p; 3354677Swnj register struct th *prev; 3364677Swnj { 3374677Swnj 3384677Swnj p->t_prev = prev; 3394677Swnj p->t_next = prev->t_next; 3404677Swnj prev->t_next->t_prev = p; 3414677Swnj prev->t_next = p; 3424677Swnj } 3434677Swnj 3444677Swnj tcp_deq(p) 3454677Swnj register struct th *p; 3464677Swnj { 3474677Swnj 3484677Swnj p->t_prev->t_next = p->t_next; 3494677Swnj p->t_next->t_prev = p->t_prev; 3504677Swnj } 351