1*4677Swnj /* tcp_output.c 4.1 81/10/30 */ 2*4677Swnj 3*4677Swnj #include "../h/param.h" 4*4677Swnj #include "../h/systm.h" 5*4677Swnj #include "../h/mbuf.h" 6*4677Swnj #include "../h/socket.h" 7*4677Swnj #include "../inet/inet.h" 8*4677Swnj #include "../inet/inet_host.h" 9*4677Swnj #include "../inet/inet_systm.h" 10*4677Swnj #include "../inet/imp.h" 11*4677Swnj #include "../inet/ip.h" 12*4677Swnj #include "../inet/tcp.h" 13*4677Swnj #include "../inet/tcp_fsm.h" 14*4677Swnj 15*4677Swnj send(tp) /* send data */ 16*4677Swnj register struct tcb *tp; 17*4677Swnj { 18*4677Swnj register struct ucb *up; 19*4677Swnj register unsigned long last, wind; 20*4677Swnj struct mbuf *m; 21*4677Swnj int flags = 0, forced, sent; 22*4677Swnj struct mbuf *tcp_sndcopy(); 23*4677Swnj int len; 24*4677Swnj 25*4677Swnj COUNT(SEND); 26*4677Swnj up = tp->t_ucb; 27*4677Swnj tp->snd_lst = tp->snd_nxt; 28*4677Swnj forced = 0; 29*4677Swnj m = NULL; 30*4677Swnj 31*4677Swnj if (tp->snd_nxt == tp->iss) { /* first data to be sent */ 32*4677Swnj flags |= TH_SYN; 33*4677Swnj tp->snd_lst++; 34*4677Swnj } 35*4677Swnj 36*4677Swnj /* get seq # of last datum in send buffer */ 37*4677Swnj 38*4677Swnj last = tp->snd_off; 39*4677Swnj for (m = up->uc_sbuf; m != NULL; m = m->m_next) 40*4677Swnj last += m->m_len; 41*4677Swnj 42*4677Swnj /* no data to send in buffer */ 43*4677Swnj 44*4677Swnj if (tp->snd_nxt > last) { 45*4677Swnj 46*4677Swnj /* should we send FIN? don't unless haven't already sent one */ 47*4677Swnj 48*4677Swnj if ((tp->tc_flags&TC_SND_FIN) && 49*4677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 50*4677Swnj 51*4677Swnj flags |= TH_FIN; 52*4677Swnj tp->seq_fin = tp->snd_lst++; 53*4677Swnj } 54*4677Swnj 55*4677Swnj } else { /* there is data to send */ 56*4677Swnj 57*4677Swnj /* send data only if there is a window defined */ 58*4677Swnj 59*4677Swnj if (tp->tc_flags&TC_SYN_ACKED) { 60*4677Swnj 61*4677Swnj wind = tp->snd_una + tp->snd_wnd; 62*4677Swnj 63*4677Swnj /* use window to limit send */ 64*4677Swnj 65*4677Swnj tp->snd_lst = min(last, wind); 66*4677Swnj 67*4677Swnj /* make sure we don't do ip fragmentation */ 68*4677Swnj 69*4677Swnj if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 70*4677Swnj tp->snd_lst -= len - 1024; 71*4677Swnj 72*4677Swnj /* set persist timer */ 73*4677Swnj 74*4677Swnj if (tp->snd_lst >= wind) 75*4677Swnj tp->t_persist = T_PERS; 76*4677Swnj } 77*4677Swnj 78*4677Swnj /* check if window is closed and must force a byte out */ 79*4677Swnj 80*4677Swnj if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 81*4677Swnj tp->snd_lst = tp->snd_nxt + 1; 82*4677Swnj forced = 1; 83*4677Swnj } 84*4677Swnj 85*4677Swnj /* copy data to send from send buffer */ 86*4677Swnj 87*4677Swnj m = tcp_sndcopy(tp, max(tp->iss+1,tp->snd_nxt), tp->snd_lst); 88*4677Swnj 89*4677Swnj /* see if EOL should be sent */ 90*4677Swnj 91*4677Swnj if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 92*4677Swnj flags |= TH_EOL; 93*4677Swnj 94*4677Swnj /* must send FIN and no more data left to send after this */ 95*4677Swnj 96*4677Swnj if ((tp->tc_flags&TC_SND_FIN) && !forced && 97*4677Swnj tp->snd_lst == last && 98*4677Swnj (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 99*4677Swnj 100*4677Swnj flags |= TH_FIN; 101*4677Swnj tp->seq_fin = tp->snd_lst++; 102*4677Swnj } 103*4677Swnj } 104*4677Swnj 105*4677Swnj if (tp->snd_nxt < tp->snd_lst) { /* something to send */ 106*4677Swnj 107*4677Swnj if (tp->tc_flags & TC_SND_URG) 108*4677Swnj flags |= TH_URG; 109*4677Swnj sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 110*4677Swnj /* set timers for retransmission if necessary */ 111*4677Swnj 112*4677Swnj if (!forced) { 113*4677Swnj tp->t_rexmt = tp->t_xmtime; 114*4677Swnj tp->t_rexmt_val = tp->snd_lst; 115*4677Swnj 116*4677Swnj if ((tp->tc_flags&TC_REXMT) == 0) { 117*4677Swnj tp->t_rexmttl = T_REXMTTL; 118*4677Swnj tp->t_rtl_val = tp->snd_lst; 119*4677Swnj } 120*4677Swnj 121*4677Swnj } 122*4677Swnj 123*4677Swnj /* update seq for next send if this one got out */ 124*4677Swnj 125*4677Swnj if (sent) 126*4677Swnj tp->snd_nxt = tp->snd_lst; 127*4677Swnj 128*4677Swnj 129*4677Swnj /* if last timed message has been acked, start timing 130*4677Swnj this one */ 131*4677Swnj 132*4677Swnj if ((tp->tc_flags&TC_SYN_ACKED) && tp->snd_una > tp->t_xmt_val) { 133*4677Swnj tp->t_xmt = 0; 134*4677Swnj tp->t_xmt_val = tp->snd_lst; 135*4677Swnj } 136*4677Swnj 137*4677Swnj tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 138*4677Swnj tp->snd_hi = max(tp->snd_nxt, tp->snd_hi); 139*4677Swnj return (1); 140*4677Swnj } 141*4677Swnj 142*4677Swnj return(0); 143*4677Swnj } 144*4677Swnj 145*4677Swnj tcp_sndctl(tp) /* send a control msg */ 146*4677Swnj struct tcb *tp; 147*4677Swnj { 148*4677Swnj COUNT(SEND_CTL); 149*4677Swnj if (!send(tp)) { 150*4677Swnj tcp_sndnull(tp); 151*4677Swnj return(0); 152*4677Swnj } 153*4677Swnj return(1); 154*4677Swnj } 155*4677Swnj 156*4677Swnj int printhave = 0; 157*4677Swnj 158*4677Swnj tcp_sndwin(tp) 159*4677Swnj struct tcb *tp; 160*4677Swnj { 161*4677Swnj int ihave; 162*4677Swnj int hehas; 163*4677Swnj 164*4677Swnj if (tp->rcv_adv) { 165*4677Swnj /* figure out window we would advertise */ 166*4677Swnj ihave = tp->t_ucb->uc_rhiwat - 167*4677Swnj (tp->t_ucb->uc_rcc + tp->seqcnt); 168*4677Swnj hehas = tp->rcv_adv - tp->rcv_nxt; 169*4677Swnj if (printhave) 170*4677Swnj printf("ihave %d, hehas %d\n", ihave, hehas); 171*4677Swnj if (hehas > 32 && 172*4677Swnj (100*(ihave-hehas)/tp->t_ucb->uc_rhiwat) < 35) 173*4677Swnj return; 174*4677Swnj if (printhave) 175*4677Swnj printf("update him\n"); 176*4677Swnj } 177*4677Swnj if (send(tp)) 178*4677Swnj return (1); 179*4677Swnj tcp_sndnull(tp); 180*4677Swnj return (0); 181*4677Swnj } 182*4677Swnj tcp_sndnull(tp) /* send only control information */ 183*4677Swnj register struct tcb *tp; 184*4677Swnj { 185*4677Swnj COUNT(SEND_NULL); 186*4677Swnj 187*4677Swnj tcp_output(tp, 0, 0, (struct mbuf *)0); 188*4677Swnj tp->tc_flags &= ~TC_ACK_DUE; 189*4677Swnj } 190*4677Swnj 191*4677Swnj tcp_sndrst(tp, n) /* send a reset */ 192*4677Swnj register struct tcb *tp; 193*4677Swnj register struct th *n; 194*4677Swnj { 195*4677Swnj COUNT(SEND_RST); 196*4677Swnj /* don't send a reset in response to a reset */ 197*4677Swnj 198*4677Swnj if (n->th_flags&TH_RST) 199*4677Swnj return; 200*4677Swnj 201*4677Swnj tp->tc_flags |= TC_SND_RST; 202*4677Swnj 203*4677Swnj if (n->th_flags&TH_ACK) 204*4677Swnj tp->snd_nxt = n->t_ackno; 205*4677Swnj 206*4677Swnj tp->tc_flags &= ~TC_SYN_RCVD; 207*4677Swnj tcp_sndnull(tp); 208*4677Swnj tp->tc_flags &= ~TC_SND_RST; 209*4677Swnj } 210*4677Swnj 211*4677Swnj /* 212*4677Swnj * Create template to be used to send tcp packets on a connection. 213*4677Swnj * Call after host entry created, allocates an mbuf and fills 214*4677Swnj * in a skeletal tcp/ip header, minimizing the amount of work 215*4677Swnj * necessary when the connection is used. 216*4677Swnj */ 217*4677Swnj struct th * 218*4677Swnj tcp_template(tp) 219*4677Swnj struct tcb *tp; 220*4677Swnj { 221*4677Swnj register struct host *h = tp->t_ucb->uc_host; 222*4677Swnj register struct mbuf *m; 223*4677Swnj register struct th *n; 224*4677Swnj register struct ip *ip; 225*4677Swnj 226*4677Swnj if (h == 0) 227*4677Swnj return (0); 228*4677Swnj m = m_get(1); 229*4677Swnj if (m == 0) 230*4677Swnj return (0); 231*4677Swnj m->m_off = MMAXOFF - sizeof (struct th); 232*4677Swnj m->m_len = sizeof (struct th); 233*4677Swnj n = mtod(m, struct th *); 234*4677Swnj n->t_next = n->t_prev = 0; 235*4677Swnj n->t_x1 = 0; 236*4677Swnj n->t_pr = TCPROTO; 237*4677Swnj n->t_len = htons(sizeof (struct th) - sizeof (struct ip)); 238*4677Swnj n->t_s.s_addr = n_lhost.s_addr; 239*4677Swnj n->t_d.s_addr = h->h_addr.s_addr; 240*4677Swnj n->t_src = htons(tp->t_lport); 241*4677Swnj n->t_dst = htons(tp->t_fport); 242*4677Swnj n->t_seq = 0; 243*4677Swnj n->t_ackno = 0; 244*4677Swnj n->t_x2 = 0; 245*4677Swnj n->t_off = 5; 246*4677Swnj n->th_flags = 0; 247*4677Swnj n->t_win = 0; 248*4677Swnj n->t_sum = 0; 249*4677Swnj n->t_urp = 0; 250*4677Swnj return (n); 251*4677Swnj } 252*4677Swnj 253*4677Swnj tcp_output(tp, flags, len, dat) 254*4677Swnj register struct tcb *tp; 255*4677Swnj register int flags; 256*4677Swnj int len; 257*4677Swnj struct mbuf *dat; 258*4677Swnj { 259*4677Swnj register struct mbuf *m; 260*4677Swnj register struct th *t; 261*4677Swnj register struct ip *ip; 262*4677Swnj int i; 263*4677Swnj #ifdef TCPDEBUG 264*4677Swnj struct tcp_debug tdb; 265*4677Swnj #endif 266*4677Swnj COUNT(SEND_TCP); 267*4677Swnj 268*4677Swnj if ((t = tp->t_ucb->uc_template) == 0) 269*4677Swnj return (0); 270*4677Swnj MGET(m, 0); 271*4677Swnj if (m == 0) 272*4677Swnj return (0); 273*4677Swnj m->m_off = MMAXOFF - sizeof(struct th); 274*4677Swnj m->m_len = sizeof (struct th); 275*4677Swnj m->m_next = dat; 276*4677Swnj if (flags & TH_SYN) 277*4677Swnj len--; 278*4677Swnj if (flags & TH_FIN) 279*4677Swnj len--; 280*4677Swnj bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th)); 281*4677Swnj t = mtod(m, struct th *); 282*4677Swnj if (tp->tc_flags&TC_SND_RST) { 283*4677Swnj flags &= ~TH_SYN; 284*4677Swnj flags |= TH_RST; 285*4677Swnj } 286*4677Swnj if (tp->tc_flags&TC_SYN_RCVD) 287*4677Swnj flags |= TH_ACK; 288*4677Swnj t->th_flags = flags; 289*4677Swnj if (flags & TH_URG) 290*4677Swnj t->t_urp = htons(tp->snd_urp); 291*4677Swnj t->t_win = 292*4677Swnj tp->t_ucb->uc_rhiwat - (tp->t_ucb->uc_rcc + tp->seqcnt); 293*4677Swnj if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 294*4677Swnj tp->rcv_adv = tp->rcv_nxt + t->t_win; 295*4677Swnj if (len) 296*4677Swnj t->t_len = htons(len + TCPSIZE); 297*4677Swnj t->t_win = htons(t->t_win); 298*4677Swnj #ifdef TCPDEBUG 299*4677Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 300*4677Swnj t->t_seq = tp->snd_nxt; 301*4677Swnj t->t_ackno = tp->rcv_nxt; 302*4677Swnj tdb_setup(tp, t, INSEND, &tdb); 303*4677Swnj tdb_stuff(&tdb, -2); 304*4677Swnj } 305*4677Swnj #endif 306*4677Swnj t->t_seq = htonl(tp->snd_nxt); 307*4677Swnj t->t_ackno = htonl(tp->rcv_nxt); 308*4677Swnj t->t_sum = cksum(m, len + sizeof(struct th)); 309*4677Swnj ip = (struct ip *)t; 310*4677Swnj ip->ip_v = IPVERSION; 311*4677Swnj ip->ip_hl = 5; 312*4677Swnj ip->ip_tos = 0; 313*4677Swnj ip->ip_len = len + sizeof(struct th); 314*4677Swnj ip->ip_id = ip_id++; 315*4677Swnj ip->ip_off = 0; 316*4677Swnj ip->ip_ttl = MAXTTL; 317*4677Swnj i = ip_send(ip); 318*4677Swnj #ifdef notdef 319*4677Swnj if (tp->t_ucb->uc_flags & UDEBUG) { 320*4677Swnj w.w_dat = (char *)t; 321*4677Swnj w.w_stype = i; 322*4677Swnj tcp_debug(tp, &w, INRECV, -1); 323*4677Swnj } 324*4677Swnj #endif 325*4677Swnj return(i); 326*4677Swnj } 327*4677Swnj 328*4677Swnj firstempty(tp) 329*4677Swnj register struct tcb *tp; 330*4677Swnj { 331*4677Swnj register struct th *p, *q; 332*4677Swnj COUNT(FIRSTEMPTY); 333*4677Swnj 334*4677Swnj if ((p = tp->t_rcv_next) == (struct th *)tp || tp->rcv_nxt < p->t_seq) 335*4677Swnj return (tp->rcv_nxt); 336*4677Swnj while ((q = p->t_next) != (struct th *)tp && 337*4677Swnj (t_end(p) + 1) == q->t_seq) 338*4677Swnj p = q; 339*4677Swnj return (t_end(p) + 1); 340*4677Swnj } 341*4677Swnj 342*4677Swnj /* SHOULD BE A MACRO, AFTER KEEP TRACK OF ASS Q SPACE */ 343*4677Swnj 344*4677Swnj struct mbuf * 345*4677Swnj tcp_sndcopy(tp, start, end) 346*4677Swnj struct tcb *tp; 347*4677Swnj u_long start, end; 348*4677Swnj { 349*4677Swnj register struct mbuf *m, *n, **np; 350*4677Swnj u_long off; 351*4677Swnj register int len; 352*4677Swnj int adj; 353*4677Swnj struct mbuf *top, *p; 354*4677Swnj COUNT(SND_COPY); 355*4677Swnj 356*4677Swnj /* 357*4677Swnj printf("st %x end %x off %x\n", start, end, tp->snd_off); 358*4677Swnj */ 359*4677Swnj if (start >= end) 360*4677Swnj return(NULL); 361*4677Swnj off = tp->snd_off; 362*4677Swnj m = tp->t_ucb->uc_sbuf; 363*4677Swnj while (m != NULL && start >= (off + m->m_len)) { 364*4677Swnj off += m->m_len; 365*4677Swnj m = m->m_next; 366*4677Swnj } 367*4677Swnj np = ⊤ 368*4677Swnj top = 0; 369*4677Swnj adj = start - off; 370*4677Swnj len = end - start; 371*4677Swnj while (m && len > 0) { 372*4677Swnj MGET(n, 1); 373*4677Swnj *np = n; 374*4677Swnj if (n == 0) 375*4677Swnj goto nospace; 376*4677Swnj n->m_len = MIN(len, m->m_len - adj); 377*4677Swnj if (m->m_off > MMAXOFF) { 378*4677Swnj p = mtod(m, struct mbuf *); 379*4677Swnj n->m_off = ((int)p - (int)n) + adj; 380*4677Swnj mprefcnt[mtopf(p)]++; 381*4677Swnj } else { 382*4677Swnj n->m_off = MMINOFF; 383*4677Swnj bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t), 384*4677Swnj n->m_len); 385*4677Swnj } 386*4677Swnj len -= n->m_len; 387*4677Swnj adj = 0; 388*4677Swnj m = m->m_next; 389*4677Swnj /* SHOULD TRY PACKING INTO SMALL MBUFS HERE */ 390*4677Swnj np = &n->m_next; 391*4677Swnj } 392*4677Swnj /* SHOULD NEVER RUN OUT OF m WHEN LEN */ 393*4677Swnj if (len) 394*4677Swnj printf("snd_copy: m %x len %d\n", m, len); 395*4677Swnj return (top); 396*4677Swnj nospace: 397*4677Swnj printf("snd_copy: no space\n"); 398*4677Swnj m_freem(top); 399*4677Swnj return (0); 400*4677Swnj } 401*4677Swnj 402*4677Swnj tcp_enq(p, prev) 403*4677Swnj register struct th *p; 404*4677Swnj register struct th *prev; 405*4677Swnj { 406*4677Swnj 407*4677Swnj p->t_prev = prev; 408*4677Swnj p->t_next = prev->t_next; 409*4677Swnj prev->t_next->t_prev = p; 410*4677Swnj prev->t_next = p; 411*4677Swnj } 412*4677Swnj 413*4677Swnj tcp_deq(p) 414*4677Swnj register struct th *p; 415*4677Swnj { 416*4677Swnj 417*4677Swnj p->t_prev->t_next = p->t_next; 418*4677Swnj p->t_next->t_prev = p->t_prev; 419*4677Swnj } 420