1*4692Swnj /* tcp_output.c 4.5 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; 394688Swnj 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 } 106*4692Swnj if (tp->snd_nxt >= tp->snd_lst) 107*4692Swnj return (0); 1084678Swnj } else { 1094677Swnj if (tp->tc_flags&TC_SYN_ACKED) { 1104677Swnj wind = tp->snd_una + tp->snd_wnd; 1114677Swnj tp->snd_lst = min(last, wind); 1124677Swnj if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 1134677Swnj tp->snd_lst -= len - 1024; 1144677Swnj if (tp->snd_lst >= wind) 1154677Swnj tp->t_persist = T_PERS; 1164677Swnj } 1174677Swnj if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 1184677Swnj tp->snd_lst = tp->snd_nxt + 1; 1194677Swnj forced = 1; 120*4692Swnj } else if (tp->snd_nxt >= tp->snd_lst) 121*4692Swnj return (0); 122*4692Swnj m = tcp_sndcopy(tp, MAX(tp->iss+1,tp->snd_nxt), tp->snd_lst); 1234677Swnj if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 1244677Swnj flags |= TH_EOL; 1254677Swnj if ((tp->tc_flags&TC_SND_FIN) && !forced && 1264677Swnj tp->snd_lst == last && 1274677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1284677Swnj flags |= TH_FIN; 1294677Swnj tp->seq_fin = tp->snd_lst++; 1304677Swnj } 1314677Swnj } 1324678Swnj if (tp->tc_flags & TC_SND_URG) 1334678Swnj flags |= TH_URG; 1344678Swnj sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 1354678Swnj if (!forced) { 1364678Swnj tp->t_rexmt = tp->t_xmtime; 1374678Swnj tp->t_rexmt_val = tp->snd_lst; 1384678Swnj if ((tp->tc_flags&TC_REXMT) == 0) { 1394678Swnj tp->t_rexmttl = T_REXMTTL; 1404678Swnj tp->t_rtl_val = tp->snd_lst; 1414677Swnj } 1424677Swnj } 1434678Swnj if (sent) 1444678Swnj tp->snd_nxt = tp->snd_lst; 1454678Swnj if ((tp->tc_flags&TC_SYN_ACKED) && 1464678Swnj tp->snd_una > tp->t_xmt_val) { 1474678Swnj tp->t_xmt = 0; 1484678Swnj tp->t_xmt_val = tp->snd_lst; 1494677Swnj } 1504678Swnj tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 151*4692Swnj tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); 1524678Swnj return (1); 1534677Swnj } 1544677Swnj 1554677Swnj /* 1564677Swnj * Create template to be used to send tcp packets on a connection. 1574677Swnj * Call after host entry created, allocates an mbuf and fills 1584677Swnj * in a skeletal tcp/ip header, minimizing the amount of work 1594677Swnj * necessary when the connection is used. 1604677Swnj */ 1614677Swnj struct th * 1624677Swnj tcp_template(tp) 1634677Swnj struct tcb *tp; 1644677Swnj { 1654677Swnj register struct host *h = tp->t_ucb->uc_host; 1664677Swnj register struct mbuf *m; 1674677Swnj register struct th *n; 1684677Swnj register struct ip *ip; 1694677Swnj 1704677Swnj if (h == 0) 1714677Swnj return (0); 1724677Swnj m = m_get(1); 1734677Swnj if (m == 0) 1744677Swnj return (0); 1754677Swnj m->m_off = MMAXOFF - sizeof (struct th); 1764677Swnj m->m_len = sizeof (struct th); 1774677Swnj n = mtod(m, struct th *); 1784677Swnj n->t_next = n->t_prev = 0; 1794677Swnj n->t_x1 = 0; 1804677Swnj n->t_pr = TCPROTO; 1814677Swnj n->t_len = htons(sizeof (struct th) - sizeof (struct ip)); 1824677Swnj n->t_s.s_addr = n_lhost.s_addr; 1834677Swnj n->t_d.s_addr = h->h_addr.s_addr; 1844677Swnj n->t_src = htons(tp->t_lport); 1854677Swnj n->t_dst = htons(tp->t_fport); 1864677Swnj n->t_seq = 0; 1874677Swnj n->t_ackno = 0; 1884677Swnj n->t_x2 = 0; 1894677Swnj n->t_off = 5; 1904677Swnj n->th_flags = 0; 1914677Swnj n->t_win = 0; 1924677Swnj n->t_sum = 0; 1934677Swnj n->t_urp = 0; 1944677Swnj return (n); 1954677Swnj } 1964677Swnj 1974677Swnj tcp_output(tp, flags, len, dat) 1984677Swnj register struct tcb *tp; 1994677Swnj register int flags; 2004677Swnj int len; 2014677Swnj struct mbuf *dat; 2024677Swnj { 2034677Swnj register struct mbuf *m; 2044677Swnj register struct th *t; 2054677Swnj register struct ip *ip; 2064677Swnj int i; 2074677Swnj #ifdef TCPDEBUG 2084677Swnj struct tcp_debug tdb; 2094677Swnj #endif 2104677Swnj COUNT(SEND_TCP); 2114677Swnj 2124677Swnj if ((t = tp->t_ucb->uc_template) == 0) 2134677Swnj return (0); 2144677Swnj MGET(m, 0); 2154677Swnj if (m == 0) 2164677Swnj return (0); 2174677Swnj m->m_off = MMAXOFF - sizeof(struct th); 2184677Swnj m->m_len = sizeof (struct th); 2194677Swnj m->m_next = dat; 2204677Swnj if (flags & TH_SYN) 2214677Swnj len--; 2224677Swnj if (flags & TH_FIN) 2234677Swnj len--; 2244677Swnj bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th)); 2254677Swnj t = mtod(m, struct th *); 2264677Swnj if (tp->tc_flags&TC_SND_RST) { 2274677Swnj flags &= ~TH_SYN; 2284677Swnj flags |= TH_RST; 2294677Swnj } 2304677Swnj if (tp->tc_flags&TC_SYN_RCVD) 2314677Swnj flags |= TH_ACK; 2324677Swnj t->th_flags = flags; 2334677Swnj if (flags & TH_URG) 2344677Swnj t->t_urp = htons(tp->snd_urp); 2354677Swnj t->t_win = 2364677Swnj tp->t_ucb->uc_rhiwat - (tp->t_ucb->uc_rcc + tp->seqcnt); 2374677Swnj if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 2384677Swnj tp->rcv_adv = tp->rcv_nxt + t->t_win; 2394677Swnj if (len) 2404677Swnj t->t_len = htons(len + TCPSIZE); 2414677Swnj t->t_win = htons(t->t_win); 2424677Swnj #ifdef TCPDEBUG 2434677Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 2444677Swnj t->t_seq = tp->snd_nxt; 2454677Swnj t->t_ackno = tp->rcv_nxt; 2464677Swnj tdb_setup(tp, t, INSEND, &tdb); 2474677Swnj tdb_stuff(&tdb, -2); 2484677Swnj } 2494677Swnj #endif 2504677Swnj t->t_seq = htonl(tp->snd_nxt); 2514677Swnj t->t_ackno = htonl(tp->rcv_nxt); 2524677Swnj t->t_sum = cksum(m, len + sizeof(struct th)); 2534677Swnj ip = (struct ip *)t; 2544677Swnj ip->ip_v = IPVERSION; 2554677Swnj ip->ip_hl = 5; 2564677Swnj ip->ip_tos = 0; 2574677Swnj ip->ip_len = len + sizeof(struct th); 2584677Swnj ip->ip_id = ip_id++; 2594677Swnj ip->ip_off = 0; 2604677Swnj ip->ip_ttl = MAXTTL; 2614677Swnj i = ip_send(ip); 2624677Swnj return(i); 2634677Swnj } 2644677Swnj 2654677Swnj firstempty(tp) 2664677Swnj register struct tcb *tp; 2674677Swnj { 2684677Swnj register struct th *p, *q; 2694677Swnj COUNT(FIRSTEMPTY); 2704677Swnj 2714677Swnj if ((p = tp->t_rcv_next) == (struct th *)tp || tp->rcv_nxt < p->t_seq) 2724677Swnj return (tp->rcv_nxt); 2734677Swnj while ((q = p->t_next) != (struct th *)tp && 2744677Swnj (t_end(p) + 1) == q->t_seq) 2754677Swnj p = q; 2764677Swnj return (t_end(p) + 1); 2774677Swnj } 2784677Swnj 2794677Swnj struct mbuf * 2804677Swnj tcp_sndcopy(tp, start, end) 2814677Swnj struct tcb *tp; 2824677Swnj u_long start, end; 2834677Swnj { 2844677Swnj register struct mbuf *m, *n, **np; 2854677Swnj u_long off; 2864677Swnj register int len; 2874677Swnj int adj; 2884677Swnj struct mbuf *top, *p; 2894677Swnj COUNT(SND_COPY); 2904677Swnj 2914677Swnj if (start >= end) 2924677Swnj return(NULL); 2934677Swnj off = tp->snd_off; 2944677Swnj m = tp->t_ucb->uc_sbuf; 2954677Swnj while (m != NULL && start >= (off + m->m_len)) { 2964677Swnj off += m->m_len; 2974677Swnj m = m->m_next; 2984677Swnj } 2994677Swnj np = ⊤ 3004677Swnj top = 0; 3014677Swnj adj = start - off; 3024677Swnj len = end - start; 3034677Swnj while (m && len > 0) { 3044677Swnj MGET(n, 1); 3054677Swnj *np = n; 3064677Swnj if (n == 0) 3074677Swnj goto nospace; 3084677Swnj n->m_len = MIN(len, m->m_len - adj); 3094677Swnj if (m->m_off > MMAXOFF) { 3104677Swnj p = mtod(m, struct mbuf *); 3114677Swnj n->m_off = ((int)p - (int)n) + adj; 3124677Swnj mprefcnt[mtopf(p)]++; 3134677Swnj } else { 3144677Swnj n->m_off = MMINOFF; 3154677Swnj bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t), 3164677Swnj n->m_len); 3174677Swnj } 3184677Swnj len -= n->m_len; 3194677Swnj adj = 0; 3204677Swnj m = m->m_next; 3214677Swnj /* SHOULD TRY PACKING INTO SMALL MBUFS HERE */ 3224677Swnj np = &n->m_next; 3234677Swnj } 3244677Swnj /* SHOULD NEVER RUN OUT OF m WHEN LEN */ 3254677Swnj if (len) 3264677Swnj printf("snd_copy: m %x len %d\n", m, len); 3274677Swnj return (top); 3284677Swnj nospace: 3294677Swnj printf("snd_copy: no space\n"); 3304677Swnj m_freem(top); 3314677Swnj return (0); 3324677Swnj } 333