1*4678Swnj /* tcp_output.c 4.2 81/10/30 */ 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 15*4678Swnj /* 16*4678Swnj * Special routines to send control messages. 17*4678Swnj */ 18*4678Swnj tcp_sndctl(tp) 19*4678Swnj struct tcb *tp; 20*4678Swnj { 21*4678Swnj COUNT(TCP_SNDCTL); 22*4678Swnj 23*4678Swnj if (tcp_send(tp)) 24*4678Swnj return (1); 25*4678Swnj tcp_sndnull(tp); 26*4678Swnj return(0); 27*4678Swnj } 28*4678Swnj 29*4678Swnj tcp_sndwin(tp) 30*4678Swnj struct tcb *tp; 31*4678Swnj { 32*4678Swnj int ihave, hehas; 33*4678Swnj COUNT(TCP_SNDWIN); 34*4678Swnj 35*4678Swnj if (tp->rcv_adv) { 36*4678Swnj ihave = tp->t_ucb->uc_rhiwat - 37*4678Swnj (tp->t_ucb->uc_rcc + tp->seqcnt); 38*4678Swnj hehas = tp->rcv_adv - tp->rcv_nxt; 39*4678Swnj if (hehas > 32 && 40*4678Swnj (100*(ihave-hehas)/tp->t_ucb->uc_rhiwat) < 35) 41*4678Swnj return; 42*4678Swnj } 43*4678Swnj if (tcp_send(tp)) 44*4678Swnj return (1); 45*4678Swnj tcp_sndnull(tp); 46*4678Swnj return (0); 47*4678Swnj } 48*4678Swnj 49*4678Swnj tcp_sndnull(tp) 504677Swnj register struct tcb *tp; 514677Swnj { 52*4678Swnj COUNT(TCP_SNDNULL); 53*4678Swnj 54*4678Swnj tcp_output(tp, 0, 0, (struct mbuf *)0); 55*4678Swnj tp->tc_flags &= ~TC_ACK_DUE; 56*4678Swnj } 57*4678Swnj 58*4678Swnj tcp_sndrst(tp, n) 59*4678Swnj register struct tcb *tp; 60*4678Swnj register struct th *n; 61*4678Swnj { 62*4678Swnj COUNT(TCP_SNDRST); 63*4678Swnj 64*4678Swnj /* don't send a reset in response to a reset */ 65*4678Swnj if (n->th_flags&TH_RST) 66*4678Swnj return; 67*4678Swnj tp->tc_flags |= TC_SND_RST; 68*4678Swnj if (n->th_flags&TH_ACK) 69*4678Swnj tp->snd_nxt = n->t_ackno; 70*4678Swnj tp->tc_flags &= ~TC_SYN_RCVD; 71*4678Swnj tcp_sndnull(tp); 72*4678Swnj tp->tc_flags &= ~TC_SND_RST; 73*4678Swnj } 74*4678Swnj 75*4678Swnj /* 76*4678Swnj * Tcp segment output routine. 77*4678Swnj */ 78*4678Swnj tcp_send(tp) 79*4678Swnj register struct tcb *tp; 80*4678Swnj { 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 88*4678Swnj COUNT(TCP_SEND); 894677Swnj up = tp->t_ucb; 904677Swnj tp->snd_lst = tp->snd_nxt; 914677Swnj forced = 0; 924677Swnj m = NULL; 93*4678Swnj 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 } 107*4678Swnj } 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; 1194677Swnj } 1204677Swnj m = tcp_sndcopy(tp, max(tp->iss+1,tp->snd_nxt), tp->snd_lst); 1214677Swnj if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 1224677Swnj flags |= TH_EOL; 1234677Swnj if ((tp->tc_flags&TC_SND_FIN) && !forced && 1244677Swnj tp->snd_lst == last && 1254677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 1264677Swnj flags |= TH_FIN; 1274677Swnj tp->seq_fin = tp->snd_lst++; 1284677Swnj } 1294677Swnj } 130*4678Swnj if (tp->snd_nxt >= tp->snd_lst) 131*4678Swnj return (0); 132*4678Swnj if (tp->tc_flags & TC_SND_URG) 133*4678Swnj flags |= TH_URG; 134*4678Swnj sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 135*4678Swnj if (!forced) { 136*4678Swnj tp->t_rexmt = tp->t_xmtime; 137*4678Swnj tp->t_rexmt_val = tp->snd_lst; 138*4678Swnj if ((tp->tc_flags&TC_REXMT) == 0) { 139*4678Swnj tp->t_rexmttl = T_REXMTTL; 140*4678Swnj tp->t_rtl_val = tp->snd_lst; 1414677Swnj } 1424677Swnj } 143*4678Swnj if (sent) 144*4678Swnj tp->snd_nxt = tp->snd_lst; 145*4678Swnj if ((tp->tc_flags&TC_SYN_ACKED) && 146*4678Swnj tp->snd_una > tp->t_xmt_val) { 147*4678Swnj tp->t_xmt = 0; 148*4678Swnj tp->t_xmt_val = tp->snd_lst; 1494677Swnj } 150*4678Swnj tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 151*4678Swnj tp->snd_hi = max(tp->snd_nxt, tp->snd_hi); 152*4678Swnj 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 } 3334677Swnj 3344677Swnj tcp_enq(p, prev) 3354677Swnj register struct th *p; 3364677Swnj register struct th *prev; 3374677Swnj { 3384677Swnj 3394677Swnj p->t_prev = prev; 3404677Swnj p->t_next = prev->t_next; 3414677Swnj prev->t_next->t_prev = p; 3424677Swnj prev->t_next = p; 3434677Swnj } 3444677Swnj 3454677Swnj tcp_deq(p) 3464677Swnj register struct th *p; 3474677Swnj { 3484677Swnj 3494677Swnj p->t_prev->t_next = p->t_next; 3504677Swnj p->t_next->t_prev = p->t_prev; 3514677Swnj } 352