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