1 /*
2  $Log:	rdp_macros.h,v $
3  * Revision 2.6  84/11/14  13:24:53  walsh
4  * macro to go with monitoring outgoing packets on a debugged RDP connection.
5  *
6  * Revision 2.5  84/11/08  16:11:38  walsh
7  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
8  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
9  * unless you do.
10  *
11  * Revision 2.4  84/11/05  15:53:21  walsh
12  * update_nulltimer() macro began to look inappropriate with recent
13  * changes, so its been stripped out and put in-line.
14  *
15  * Revision 2.3  84/11/05  14:24:45  walsh
16  * added comment.
17  *
18  * Revision 2.2  84/11/02  18:23:51  walsh
19  * Protocol specifiers want NULL message to have own sequence number in
20  * case of slow (t>NULL msg timeout) packets.  I don't see this as a problem,
21  * and even if happened (dubious) would only delay discovery, but I
22  * didn't win this one.  Initially not designed for this, but fixes are
23  * in almost neatly.
24  *
25  * Revision 2.1  84/11/02  10:13:25  walsh
26  * Fixed to include RCS comments in checked out source.
27  *
28  *
29  * description:
30  * Organized macros used by RDP and put most of them here.
31  *
32  * revision 1.3
33  * date: 84/07/19 13:53:16;  author: walsh;  state: Exp;  lines added/del: 24/4
34  * worked on retransmit took too long macro.  Should now advise
35  * sockets sleeping in connect(2) and does trash child sockets
36  * who cannot connect to their peers.
37  *
38  * revision 1.2
39  * date: 84/07/19 10:53:06;  author: walsh;  state: Exp;  lines added/del: 8/5
40  * Changed retransmit took too long timer to be advisory in nature.  It
41  * reports error to user, but does not affect connection state.
42  *
43  * revision 1.1
44  * date: 84/07/19 10:24:08;  author: walsh;  state: Exp;
45  * Initial revision
46  */
47 
48 
49 /********** Macros to hide (socket) level above **********/
50 
51 /*
52  * The user notifies the RDP of the maximum sized datagram he's willing to
53  * receive by adjusting the socket receive buffering accordingly.
54  */
55 #define pick_ourmaxlen(rdpcb) \
56 	((rdpcb)->r_ourmaxlen = (rdpcb)->r_inpcb->inp_socket->so_rcv.sb_hiwat)
57 
58 /*
59  * Notify user of error condition via the socket
60  */
61 #define set_error(rdpcb, error) (rdpcb)->r_inpcb->inp_socket->so_error = error;
62 
63 /*
64  * On packet reception, can we q a datagram on the socket for the user?
65  * We only q one on the socket at a time.
66  */
67 #define usr_rbuf_is_empty(rdpcb) \
68 	((rdpcb)->r_inpcb->inp_socket->so_rcv.sb_cc == 0)
69 
70 /*
71  * All the datagrams are buffered by RDP.  RDP has reached its buffering
72  * limit, so prevent the user from queueing more up until we get some
73  * acknowledgements back from the other side.
74  */
75 #define sendbufisfull(rdpcb) \
76 	{ struct sockbuf *sosnd;				\
77 	  sosnd = &(rdpcb)->r_inpcb->inp_socket->so_snd;	\
78 	  sosnd->sb_cc = sosnd->sb_hiwat;			\
79 	}
80 
81 /*
82  * Permit the user to q up more datagrams for sending.
83  *
84  * We only need to wake up a writer if he's blocked for
85  * buffering space.  RDP allows at most 1 datagram in
86  * the socket code, and no datagrams for transmission
87  * are stored on the socket due to RDP's messing with
88  * so_snd.sb_cc, so we are able to do the wakeup iff necessary
89  */
90 #define sendbufhasspace(rdpcb) \
91 	{ struct socket *so;			\
92 	  so = (rdpcb)->r_inpcb->inp_socket;	\
93 	  if (so->so_snd.sb_cc) {		\
94 		  so->so_snd.sb_cc = 0;		\
95 		  sowwakeup(so);		\
96 	}}
97 
98 #define wakeup_reader(rdpcb) sorwakeup((rdpcb)->r_inpcb->inp_socket)
99 #define wakeup_writer(rdpcb) sowwakeup((rdpcb)->r_inpcb->inp_socket)
100 
101 /*
102  * We can't send any new datagrams after we've been reset.
103  */
104 #define user_cantsendmore(rdpcb) socantsendmore((rdpcb)->r_inpcb->inp_socket)
105 
106 #define user_cantreadmore(rdpcb) socantrcvmore((rdpcb)->r_inpcb->inp_socket)
107 
108 /*
109  * The socket code prevents read(2) or write(2) until we're connected to
110  * the other end.  Nor can a child socket be accept(2)ed until the connection
111  * is established.
112  */
113 #define rdpisconnected(rdpcb) soisconnected((rdpcb)->r_inpcb->inp_socket)
114 
115 
116 /********** Macros to save duplicating code fragments **********/
117 
118 /*
119  * set up re-transmission timer for packet we just sent.
120  */
121 #define set_rxtimer(rdpcb, N) \
122 	{ (rdpcb)->r_rxtimers[N] = (rdpcb)->r_rxmitime;		\
123 	  (rdpcb)->r_timers[RDP_tRXMIT] = RDP_tvRXCHECK;	\
124 	  if ((rdpcb)->r_rttlindex < 0) {			\
125 		(rdpcb)->r_rttlindex = N;			\
126 		(rdpcb)->r_timers[RDP_tRTTL] = (rdpcb)->r_rttl;	\
127 	} }
128 
129 /*
130  * we received the other guy's SYN, and it was in packet seqnum
131  */
132 #define got_syn(rdpcb, seqnum) \
133 	{ (rdpcb)->r_synrcvd = TRUE;                \
134 	  (rdpcb)->r_rcvq.rq_baseseq = (seqnum) +1; \
135 	  (rdpcb)->r_irs = seqnum;                  \
136 	}
137 
138 /*
139  * RFC 908 section 3.5 page 16 says to use twice the advertised buffering
140  * This is a bad idea that is an attempt to make up for network latency
141  * and to try to keep things pipelined.  We'll use only advertised buffering.
142  * Approach:  Don't make trouble, other end must ask for it.  (by
143  * advertising more than has)
144  */
145 #define process_synopt(rdpcb, synopt) \
146 	{ (rdpcb)->r_hisnbuf = MAX(1, MIN (ntohs((u_short)(synopt)->rh_nbuf), \
147 					   RDP_MAXDGRAMS));	 \
148 	  (rdpcb)->r_hismaxlen = ntohs((u_short)(synopt)->rh_maxlen);     \
149 	  (rdpcb)->r_sequential = (rdpcb)->r_sequential ||       \
150 		(ntohs((u_short)(synopt)->rh_options) & RDP_oSEQUENTIAL); \
151 	  sbreserve(&((rdpcb)->r_inpcb->inp_socket->so_snd),     \
152 		(rdpcb)->r_hismaxlen - HDRSLOP);		 \
153 	}
154 
155 /*
156  * Advisory and does not close connection.  Allows user to pick up any
157  * q'd received datagrams.  But, if there's no host-host communications
158  * then these probably aren't useful.  The real reason for advisory nature
159  * is that the user process knows best what to do, having contextual info.
160  * ??? break this up into specific code in state timeout functions ???
161  *
162  * RTTL occurs for 1) normal user datagrams, and 2) NULL messages
163  */
164 #define rttl(rdpcb) \
165 	{ struct socket *rttlso;					\
166 									\
167 	rttlso = (rdpcb)->r_inpcb->inp_socket;				\
168 	if (rttlso->so_state & SS_NOFDREF)				\
169 		/*							\
170 		 * was a child socket of a listen(2)er trying to	\
171 		 * establish connection with other end.  RDP_sLSYNRCVD	\
172 		 */							\
173 		trash_pcbs(rdpcb);					\
174 	else {								\
175 		set_error(rdpcb, ETIMEDOUT);				\
176 		/*							\
177 		 * sleeping in connect(2) and not using NBIO.		\
178 		 * RDP_sSYNSENT (syn not acked yet)			\
179 		 */							\
180 		wakeup((caddr_t) &rttlso->so_timeo);			\
181 		/*							\
182 		 * sleeping in write(2) waiting for buffer space	\
183 		 * or sleeping in select(2).  RDP_sESTAB		\
184 		 */							\
185 		wakeup_writer(rdpcb);					\
186 		/*							\
187 		 * sleeping in read(2) for datagram from other side	\
188 		 * and NULL msgs imply connection lost RDP_sESTAB	\
189 		 */							\
190 		wakeup_reader(rdpcb);					\
191 		(rdpcb)->r_timers[RDP_tRTTL] = (rdpcb)->r_rttl;		\
192 	}}
193 
194 /*
195  * Pass datagram to user.
196  * On UNIX, mark end of datagram by setting m_act on last mbuf in chain.
197  */
198 #define usr_rbuf_append(rdpcb, m) \
199 	{ MBUF *x;						\
200 	  for (x = (m); x->m_next; x = x->m_next)		\
201 		;						\
202 	  x->m_act = ((MBUF *) 1);				\
203 	  sbappend(&(rdpcb)->r_inpcb->inp_socket->so_rcv, m);	\
204 	}
205 
206 /*
207  * For in-line coding of the state transition function.
208  */
209 #ifdef RDP_CS
210 #define RDP_ACTION1 (rdpcb)->r_entered[newstate] = iptime();
211 #else
212 #define RDP_ACTION1 /**/
213 #endif
214 
215 #define debug_rdpcb(r) ((r)->r_inpcb->inp_socket->so_options & SO_DEBUG)
216 
217 #define RDP_ACTION(input, rdpcb, arg, newstate) \
218 	{ int	(*func)();						\
219 \
220 	func = rdp_action_table[(rdpcb)->r_state][input];		\
221 	if (! func){							\
222 		/*							\
223 		 * invalid state transition, just print a message and ignore \
224 		 */							\
225 		printf("rdp bad transition: rdpcb 0x%x state %d input %d\n", \
226 			(rdpcb), (rdpcb)->r_state, (input));		\
227 		if (arg && (input == RDP_iNETR))			\
228 			m_freem(dtom(arg));				\
229 		newstate = RDP_sSAME;					\
230 	} else {							\
231 		boolean debug_on;					\
232 \
233 		debug_on = debug_rdpcb(rdpcb);				\
234 		newstate = (*func)(rdpcb, arg);				\
235 		if (debug_on)						\
236 			rdp_debug (rdpcb, arg, input, newstate);	\
237 \
238 		/*							\
239 		 * No longer have mbufs for protocol control blocks if closed \
240 		 */							\
241 		if ((newstate != RDP_sSAME) && (newstate != RDP_sCLOSED)){ \
242 			rdpcb->r_state = newstate;			\
243 			RDP_ACTION1					\
244 	} } }
245 
246