1*25202Skarels 2*25202Skarels /*** macros to simulate action() ***/ 3*25202Skarels 4*25202Skarels extern int tcprint; 5*25202Skarels 6*25202Skarels #define TCP_DEBUG(soptr,tptr,wptr,act,newstate) \ 7*25202Skarels if (soptr){ \ 8*25202Skarels if ((soptr)->so_options & SO_DEBUG) { \ 9*25202Skarels if (tcprint) \ 10*25202Skarels printf("via 0x%x, ", fsactab[act]); \ 11*25202Skarels tcp_debug(tptr, wptr, newstate); \ 12*25202Skarels } \ 13*25202Skarels } 14*25202Skarels 15*25202Skarels 16*25202Skarels /* 17*25202Skarels * Simulates calls to action. 18*25202Skarels * tp valid tcpcb pointer ( == wp->w_tcb ) 19*25202Skarels * so valid socket pointer ( == tp->t_in_pcb->inp_socket ) 20*25202Skarels * wp valid work pointer 21*25202Skarels * wtype == wp->w_type, used so compiler can remove constant conditionals 22*25202Skarels * wdat == wp->w_dat 23*25202Skarels * 24*25202Skarels * act, newstate integers 25*25202Skarels * 26*25202Skarels * Remember that if the state transition results in CLOSED, then we have 27*25202Skarels * lost the mbuf(s) containing the tcpcb... 28*25202Skarels * 29*25202Skarels * moved tcp->net_keep to tcp_net_keep to avoid race condition since don't 30*25202Skarels * always have MBUF holding tcp after state transition function returns. 31*25202Skarels */ 32*25202Skarels extern int tcp_net_keep; 33*25202Skarels 34*25202Skarels #define ACTION(tp, so, wp, wtype, wdat, act, newstate) \ 35*25202Skarels { act = fstab[(tp)->t_state][wtype]; \ 36*25202Skarels if (act == 0) { \ 37*25202Skarels /* \ 38*25202Skarels * invalid state transition, just print a message and ignore \ 39*25202Skarels */ \ 40*25202Skarels printf("tcp bad state: tcb=%x state=%d input=%d\n", \ 41*25202Skarels tp, (tp)->t_state, wtype); \ 42*25202Skarels if (wdat != NULL && wtype == INRECV) \ 43*25202Skarels m_freem(dtom(wdat)); \ 44*25202Skarels } else { \ 45*25202Skarels tcp_net_keep = FALSE; \ 46*25202Skarels newstate = (*fsactab[act])(wp); \ 47*25202Skarels TCP_DEBUG (so, tp, wp, act, newstate); \ 48*25202Skarels if (wdat != NULL && !tcp_net_keep && wtype == INRECV) \ 49*25202Skarels m_freem(dtom(wdat)); \ 50*25202Skarels if ((newstate != SAME) && (newstate != CLOSED)) \ 51*25202Skarels (tp)->t_state = newstate; \ 52*25202Skarels } \ 53*25202Skarels } 54*25202Skarels 55*25202Skarels extern char fstab[TCP_NSTATES][INOP]; 56*25202Skarels extern int (*fsactab[])(); 57*25202Skarels 58*25202Skarels /* 59*25202Skarels * like w_alloc() macro, but suitable for above ACTION. 60*25202Skarels */ 61*25202Skarels #define W_ALLOC(type, stype, tp, m, so, act, newstate) \ 62*25202Skarels { \ 63*25202Skarels struct work w; \ 64*25202Skarels w.w_type = type; w.w_stype = stype; w.w_tcb = tp; w.w_dat = (char *)m; \ 65*25202Skarels ACTION(tp, so, &w, type, m, act, newstate); \ 66*25202Skarels } 67*25202Skarels 68*25202Skarels 69*25202Skarels /* 70*25202Skarels * Enqueue/dequeue segment on tcp sequencing queue 71*25202Skarels */ 72*25202Skarels #define TCP_ENQ(new, list, tp) \ 73*25202Skarels { (tp)->t_rcv_len += (new)->t_len; \ 74*25202Skarels insque(new, list); \ 75*25202Skarels } 76*25202Skarels 77*25202Skarels #define TCP_DEQ(old, tp) \ 78*25202Skarels { (tp)->t_rcv_len -= (old)->t_len; \ 79*25202Skarels remque(old); \ 80*25202Skarels } 81*25202Skarels 82*25202Skarels /* 83*25202Skarels * Macro form of firstempty(). Find the first empty spot in rcv buffer. 84*25202Skarels */ 85*25202Skarels #define FIRSTEMPTY(tp, retval) \ 86*25202Skarels { register struct th *p; \ 87*25202Skarels \ 88*25202Skarels if ((p = (tp)->t_rcv_next) == (struct th *)(tp) || \ 89*25202Skarels SEQ_LT((tp)->rcv_nxt, p->t_seq)) \ 90*25202Skarels retval = (tp)->rcv_nxt; \ 91*25202Skarels else { \ 92*25202Skarels register struct th *q; \ 93*25202Skarels \ 94*25202Skarels while ((q = p->t_next) != (struct th *)(tp) && \ 95*25202Skarels SEQ_EQ(t_end(p)+1, q->t_seq)) \ 96*25202Skarels p = q; \ 97*25202Skarels \ 98*25202Skarels retval = t_end(p) + 1; \ 99*25202Skarels }} 100*25202Skarels 101*25202Skarels /* 102*25202Skarels * macro form of present_data(). 103*25202Skarels */ 104*25202Skarels extern struct mbuf *extract_oob(); 105*25202Skarels 106*25202Skarels #define PRESENT_DATA(tp) \ 107*25202Skarels { \ 108*25202Skarels /* connection must be synced and data available for user */ \ 109*25202Skarels \ 110*25202Skarels if ((tp)->syn_acked){ \ 111*25202Skarels register struct th *t; \ 112*25202Skarels struct socket *so; \ 113*25202Skarels \ 114*25202Skarels so = (tp)->t_in_pcb->inp_socket; \ 115*25202Skarels if ((t = (tp)->t_rcv_next) != (struct th *)(tp)) { \ 116*25202Skarels /* \ 117*25202Skarels * move as many mbufs as possible from tcb \ 118*25202Skarels * to user queue. Used to use firstempty(), \ 119*25202Skarels * but that caused traversal of list twice. \ 120*25202Skarels */ \ 121*25202Skarels if (SEQ_LEQ(t->t_seq, (tp)->rcv_nxt)) { \ 122*25202Skarels register struct sockbuf *sorcv; \ 123*25202Skarels register int done; \ 124*25202Skarels register struct mbuf *m; \ 125*25202Skarels register struct th *next; \ 126*25202Skarels \ 127*25202Skarels sorcv = &so->so_rcv; \ 128*25202Skarels done = FALSE; \ 129*25202Skarels while (sbspace(sorcv) > 0 && !done) { \ 130*25202Skarels /* \ 131*25202Skarels * Note order of events: sbappend tries to \ 132*25202Skarels * coalesce mbufs, so if get a packet in, it \ 133*25202Skarels * may use the mbuf that sbappend may free. \ 134*25202Skarels */ \ 135*25202Skarels \ 136*25202Skarels /* dequeue chunk from tcb */ \ 137*25202Skarels \ 138*25202Skarels next = t->t_next; \ 139*25202Skarels TCP_DEQ(t, tp); \ 140*25202Skarels m = dtom(t); \ 141*25202Skarels \ 142*25202Skarels /* \ 143*25202Skarels * check for end of list and gaps. \ 144*25202Skarels */ \ 145*25202Skarels if ((next == (struct th *)tp) || \ 146*25202Skarels (t_end(t)+1 != next->t_seq)) \ 147*25202Skarels done = TRUE; \ 148*25202Skarels \ 149*25202Skarels /* SS_CANTRCVMORE == usr_abort */ \ 150*25202Skarels if (so->so_state & SS_CANTRCVMORE) \ 151*25202Skarels m_freem(m); \ 152*25202Skarels else { \ 153*25202Skarels /* \ 154*25202Skarels * remove urgent data from input stream\ 155*25202Skarels */ \ 156*25202Skarels if (SEQ_GEQ((tp)->rcv_urpend, (tp)->rcv_urp)) \ 157*25202Skarels m = extract_oob(tp, m, sorcv); \ 158*25202Skarels \ 159*25202Skarels if (m) \ 160*25202Skarels /* \ 161*25202Skarels * chain new data to user \ 162*25202Skarels * receive buf \ 163*25202Skarels */ \ 164*25202Skarels sbappend(sorcv, m); \ 165*25202Skarels } \ 166*25202Skarels \ 167*25202Skarels t = next; \ 168*25202Skarels } \ 169*25202Skarels \ 170*25202Skarels /* awaken reader only if any data on user rcv queue */ \ 171*25202Skarels if (sorcv->sb_cc > 0) \ 172*25202Skarels sbwakeup(sorcv); \ 173*25202Skarels } \ 174*25202Skarels } \ 175*25202Skarels \ 176*25202Skarels /* let user know about foreign tcp close if no more data \ 177*25202Skarels * OR if no data ever transferred. \ 178*25202Skarels */ \ 179*25202Skarels \ 180*25202Skarels if ((tp)->fin_rcvd && /* !tp->usr_closed && */ rcv_empty(tp)) \ 181*25202Skarels socantrcvmore(so); \ 182*25202Skarels }} 183