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