1 /*
2 $Log: rdp_prim.c,v $
3 * Revision 2.15 85/03/12 08:41:13 walsh
4 * Don't advise the user about ENOBUFS errors passed back from device drivers+
5 * ip_send() when the protocol has a retransmission strategy.
6 *
7 * Revision 2.14 85/03/06 10:06:16 walsh
8 * Corrected some error handling and reporting.
9 *
10 * Revision 2.13 85/02/26 08:26:56 walsh
11 * First pass at using IP source routing information to establish connections
12 * (possibly with hosts not known by the Internet gateways.) The hooks with
13 * TCP could be better done - particularly dealing with IP addresses in the
14 * header for checksums and tcpdb lookups.
15 *
16 * Revision 2.12 84/11/15 09:56:04 walsh
17 * redid how we deal with compiler padding in the RDP header structure.
18 *
19 * Revision 2.11 84/11/08 16:11:51 walsh
20 * Added code to gather statistics on RDP traffic. This makes the RDPCB
21 * too big unles you make mbufs 512 bytes large. RDP_CS should be turned off
22 * unless you do.
23 *
24 * Revision 2.10 84/11/06 15:24:26 walsh
25 * *** empty log message ***
26 *
27 * Revision 2.9 84/11/06 14:30:23 walsh
28 * intorduced RDP_HLSHIFT
29 *
30 * Revision 2.8 84/11/06 09:09:16 walsh
31 * added missing include.
32 *
33 * Revision 2.7 84/11/05 15:55:28 walsh
34 * update_nulltimer() macro began to look inappropriate with recent
35 * changes, so its been stripped out and put in-line.
36 *
37 * Revision 2.6 84/11/05 15:23:23 walsh
38 * *** empty log message ***
39 *
40 * Revision 2.5 84/11/05 15:17:53 walsh
41 * added comments on acknowledgement strategy.
42 *
43 * Revision 2.4 84/11/05 11:05:20 walsh
44 * comment and adjust number for rdp_iss in a mathematically correct way
45 * as a result of benchmarks (cf. operationally correct).
46 *
47 * Revision 2.3 84/11/02 18:24:09 walsh
48 * Protocol specifiers want NULL message to have own sequence number in
49 * case of slow (t>NULL msg timeout) packets. I don't see this as a problem,
50 * and even if happened (dubious) would only delay discovery, but I
51 * didn't win this one. Initially not designed for this, but fixes are
52 * in almost neatly.
53 *
54 * Revision 2.2 84/11/02 15:28:56 walsh
55 * Allow for RDP header fields not on natural boundries. (Protocol
56 * specifiers say will be part of next version in 6-12 months).
57 * Until then, there goes the speed... Yucho modifications.
58 *
59 * Revision 2.1 84/11/02 10:13:48 walsh
60 * Fixed to include RCS comments in checked out source.
61 *
62 *
63 * description:
64 * some primitives for RDP.
65 *
66 * revision 1.10
67 * date: 84/07/19 10:21:35; author: walsh; state: Exp; lines added/del: 1/0
68 * Organized macros and classified their definitions in rdp_macros.h.
69 *
70 * revision 1.9
71 * date: 84/07/18 18:50:44; author: walsh; state: Exp; lines added/del: 5/0
72 * Added provision for sending of NULL messages. These are sent on an idle
73 * connection to determine that the other side still exists.
74 *
75 * revision 1.8
76 * date: 84/07/12 20:04:16; author: walsh; state: Exp; lines added/del: 1/2
77 * *** empty log message ***
78 *
79 * revision 1.7
80 * date: 84/07/12 13:48:14; author: walsh; state: Exp; lines added/del: 31/16
81 * Rather than in-line stuffing of IP/RDP headers, at least half of which are
82 * constant, copy headers in from a template of what the headers are like. The
83 * bcopy() call is turned into a movc3 instruction on the VAX by a sed script
84 * run over the assembler output of the C compiler. Marginal speed-up.
85 *
86 * revision 1.6
87 * date: 84/07/12 09:29:48; author: walsh; state: Exp; lines added/del: 6/9
88 * Found:
89 * 1. If MGET saves anything over mget, it's down in the noise, so skip it.
90 * 2. stuff_eacks as macro DOES save time.
91 * 3. Optimized stuff_eacks by timing and looking at a lot of assembler output
92 * from the C compiler.
93 *
94 * revision 1.5
95 * date: 84/07/10 09:41:52; author: walsh; state: Exp; lines added/del: 43/41
96 * Corrected problem with conversion of stuff_eacks from a function to a
97 * macro.
98 *
99 * Changed rdp_sendpkt to avoid unecessary allocation and deallocation of
100 * an mbuf for syn and eack options.
101 *
102 * revision 1.4
103 * date: 84/07/09 14:39:54; author: walsh; state: Exp; lines added/del: 1/0
104 * Part of ACK-delay algorithm. Whenever send a packet with an ACK, set
105 * ACK-delay timer to zero.
106 *
107 * revision 1.3
108 * date: 84/07/06 14:10:35; author: wjacobso; state: Exp; lines added/del: 34/34
109 * stuff_eacks made into macro; added register var definitions
110 *
111 * revision 1.2
112 * date: 84/07/06 09:49:37; author: root; state: Exp; lines added/del: 11/4
113 * This version seems to run bug-free.
114 *
115 * revision 1.1
116 * date: 84/06/26 14:17:39; author: walsh; state: Exp;
117 * Initial revision
118 *
119 */
120
121
122 #ifdef RDP
123 #include "../h/param.h"
124 #include "../h/dir.h"
125 #include "../h/user.h"
126 #include "../h/kernel.h"
127 #include "../h/inode.h"
128 #include "../h/mbuf.h"
129 #include "../h/socket.h"
130 #include "../h/socketvar.h"
131 #include "../h/protosw.h"
132
133 #include "../net/if.h"
134 #include "../net/route.h"
135
136 #include "../bbnnet/in.h"
137 #include "../bbnnet/in_var.h"
138 #include "../bbnnet/net.h"
139 #include "../bbnnet/in_pcb.h"
140 #include "../bbnnet/ip.h"
141 #include "../bbnnet/rdp.h"
142 #include "../bbnnet/rdp_macros.h"
143
144 extern struct inpcb rdp;
145
rdp_template(rdpcb)146 rdp_template(rdpcb)
147 RDPCB *rdpcb;
148 {
149 register struct ip *ip;
150 register RDPHDR *pkt;
151 register INPCB *inp;
152
153 ip = (struct ip *) rdpcb->r_template;
154 pkt = (RDPHDR *) (ip+1);
155 inp = rdpcb->r_inpcb;
156
157 ip->ip_p = IPPROTO_RDP;
158 ip->ip_tos = 0;
159 ip->ip_src = inp->inp_laddr;
160 ip->ip_dst = inp->inp_faddr;
161
162 pkt->rh_ver = RDP_VERSION;
163 pkt->rh_hdrlen = RDPHDRSZ >> RDP_HLSHIFT;
164 pkt->rh_sport = inp->inp_lport;
165 pkt->rh_dport = inp->inp_fport;
166 pkt->rh_flags = 0;
167 RDP_CKSUM(pkt) = 0;
168 }
169
170 /***********************************************************************
171 Comments on the Acknowledgement Strategy
172
173 I. It would be desirable to save network, CPU, and buffering resources
174 by not retransmitting packets which have arrived at the destination
175 host. One might think of doing this by using the cumulative ack
176 (ACK) for flow control and the extended ack (EACK) for reliability.
177 [EACK upon reception by protocol module, ACK upon reception by
178 application]
179
180 You can't do this.
181
182 1. The protocol specifiers state that an implementation may choose
183 to treat ACK#1 EACK#2 EACK#3 as ACK#3. We want to avoid receiving
184 packets we can't buffer. (see goals above)
185 2. NULL packets are sent on idle connections (all packets acknowledged)
186 and occupy sequence number space. We want to avoid situations
187 where a NULL packet goes out of our window, doesn't get acked,
188 and the connection gets dropped. (connection would be idle since
189 no transmissions/retransmissions would be going on if packets
190 received by RDP, but destination process busy doing something
191 else.)
192 3. Relying on ACKs to be sent to move the window's edge after the
193 datagram is picked up by the user process has to deal with the
194 fact that that ACK may be lost. In TCP, one uses a persistence
195 timer to deal with this. Use of ACK/EACK above implies that
196 there is no data with which to perform persistence (if buffers
197 reclaimed at EACK and not at ACK.) One could think of using
198 NULL messages to reopen the window, but a) NULL messages only
199 start up after LONG delays, b) implementations are only required
200 to respond to, not initiate, NULL messages.
201
202 2 would be a correctness error. 1+3 would be stylistic problems.
203 Therefore, the acknowledgement strategy implemented here is to
204 ACK or EACK messages only after they have been received by the destination
205 process. This means that some unecessary retransmissions might occur,
206 but such is life. (Unecessary from the point of view that the
207 information made it through the network a-o.k.)
208
209 If the application is slow to pick up messages from the protocol,
210 then that will be reflected in the round trip time estimate (and
211 retransmission time) for the other end. So, maybe this isn't all
212 that bad. Especially since most processes will be fairly interested
213 and responsive to network input.
214
215 ***********************************************************************/
216
217 /*
218 * rdp_init ensures max # of options fit in mbuf
219 */
220 #define stuff_eacks(rdpcb, optm) \
221 { \
222 register int pass; \
223 register int index; \
224 EACKOPTIONS *eopt; \
225 \
226 pass = 0; \
227 index = rdpcb->r_rcvq.rq_front; \
228 \
229 do { \
230 if (rdpcb->r_rcvq.rq_msgs[index] == RDP_DELIVERED){ \
231 if (optm == NULL){ \
232 optm = m_get(M_DONTWAIT, MT_HEADER); \
233 if (optm == NULL) \
234 break; \
235 optm->m_len = 0; \
236 eopt = mtod(optm, EACKOPTIONS *); \
237 } \
238 eopt->rh_eackno = \
239 htonl(rdpcb->r_rcvq.rq_baseseq + pass); \
240 eopt ++; \
241 optm->m_len += sizeof(EACKOPTIONS); \
242 } \
243 index = (index + 1) % rdpcb->r_rcvq.rq_maxqlen; \
244 } while (++pass < rdpcb->r_rcvq.rq_maxqlen); \
245 }
246
rdp_sendpkt(rdpcb,data,datalen,seqnum)247 rdp_sendpkt (rdpcb, data, datalen, seqnum)
248 register RDPCB *rdpcb;
249 MBUF *data;
250 int datalen; /* length of data mbuf chain in bytes */
251 rdpsequence seqnum; /* host order. seq# of this packet */
252 {
253 register MBUF *m;
254 register RDPHDR *pkt;
255
256 m = m_get(M_DONTWAIT, MT_HEADER);
257 if (m == NULL)
258 {
259 m_freem(data);
260 return (ENOBUFS);
261 }
262
263 m->m_len = sizeof(struct ip) + RDPHDRSZ;
264 m->m_off = MMAXOFF
265 - (sizeof(struct ip) + RDPHDRSZ + sizeof(SYNOPTIONS));
266 m->m_next = data;
267
268 pkt = (RDPHDR *) (mtod(m, caddr_t) + sizeof(struct ip));
269 /*
270 * Fills in most IP and RDP header fields
271 */
272 bcopy (rdpcb->r_template, mtod(m, caddr_t), (unsigned)RDP_TEMPLSIZE);
273
274 pkt->rh_dlen = htons((u_short)datalen);
275 RDP_SEQNO(pkt) = htonl((u_long)seqnum);
276
277 if (rdpcb->r_sendrst)
278 {
279 pkt->rh_flags |= RDP_fRST;
280 #ifdef RDP_CS
281 rdpcb->r_sent.r_rstpkts ++;
282 #endif
283 }
284 else
285 {
286 if (! rdpcb->r_synacked)
287 {
288 register SYNOPTIONS *synopt;
289
290 pkt->rh_flags |= RDP_fSYN;
291 pkt->rh_hdrlen += sizeof(SYNOPTIONS) >> RDP_HLSHIFT;
292 m->m_len += sizeof(SYNOPTIONS);
293 synopt = RDP_OPT(pkt, SYNOPTIONS *);
294 synopt->rh_nbuf = htons((u_short)rdpcb->r_ournbuf);
295 synopt->rh_maxlen = htons((u_short)rdpcb->r_ourmaxlen + HDRSLOP);
296 synopt->rh_options = 0;
297 if (rdpcb->r_sequential)
298 synopt->rh_options |= RDP_oSEQUENTIAL;
299 synopt->rh_options = htons(synopt->rh_options);
300 #ifdef RDP_CS
301 rdpcb->r_sent.r_synpkts ++;
302 #endif
303 }
304 else
305 {
306 register MBUF *optm;
307
308 /* possible EACK */
309 optm = NULL;
310 stuff_eacks(rdpcb, optm);
311
312 if (optm)
313 {
314 #define OKSZ (datalen+RDPHDRSZ+sizeof(struct ip)+optm->m_len <= rdpcb->r_hismaxlen)
315 if (OKSZ)
316 {
317 pkt->rh_flags |= RDP_fEACK;
318 pkt->rh_hdrlen += optm->m_len >> RDP_HLSHIFT;
319 optm->m_next = m->m_next;
320 m->m_next = optm;
321 }
322 else
323 m_free(optm);
324 #undef OKSZ
325 }
326
327 if (rdpcb->r_sendnull)
328 {
329 rdpcb->r_sendnull = FALSE;
330 pkt->rh_flags |= RDP_fNULL;
331 #ifdef RDP_CS
332 rdpcb->r_sent.r_nullpkts ++;
333 #endif
334 }
335 }
336
337 if (rdpcb->r_synrcvd)
338 {
339 rdpcb->r_timers[RDP_tACKDELAY] = 0;
340 pkt->rh_flags |= RDP_fACK;
341 RDP_ACKNO(pkt) = htonl(rdpcb->r_rcvq.rq_baseseq -1);
342 }
343 }
344
345 RDP_CKSUM(pkt) = rdp_cksum (m);
346
347 #ifdef RDP_CS
348 rdpcb->r_sent.r_total ++;
349 #endif
350
351 if (debug_rdpcb(rdpcb))
352 rdp_debug (rdpcb, mtod(m, caddr_t), -1, RDP_sSAME);
353
354 /*
355 * and ship packet off via IP. Remember that since this protocol
356 * involves retransmissions, errors can occur asynchronous to a
357 * (write) system call, and that therefore we can not send the
358 * error all the way back up through subroutine return values. We
359 * must also post it back via advise_user() at some point, and this
360 * looks like a good point to try it.
361 */
362 {
363 register int error;
364
365 error = ip_send (rdpcb->r_inpcb, m,(int)( datalen + hdrlen(pkt)),FALSE);
366
367 if (error)
368 /*
369 * Since we use retransmissions, don't need to tell user
370 * process about this. (Can be as simple as interface
371 * or host structure queues are too long due to current
372 * heavy traffic. Backing off will take care of that.)
373 */
374 if (error != ENOBUFS)
375 advise_user(rdpcbtoso(rdpcb), error);
376 return (error);
377 }
378 }
379
rdp_timeo()380 rdp_timeo()
381 {
382 register struct inpcb *inp, *next;
383 register RDPCB *rdpcb;
384 register int timer;
385 int s;
386 register rdpstate newstate;
387
388 s = splnet();
389 rdp_iss += RDP_ISSINCR;
390 /*
391 * Remember, if CLOSEWAIT timer goes off, lose rdpcb's mbuf and
392 * and next pointer in it.
393 */
394 inp = rdp.inp_next;
395 while (inp != &rdp)
396 {
397 next = inp->inp_next;
398 if (rdpcb = inptordpcb(inp))
399 {
400 rdpcb->r_rtt ++;
401
402 for (timer = 0; timer < RDP_NTIMERS; timer++)
403 {
404 if (rdpcb->r_timers[timer])
405 {
406 rdpcb->r_timers[timer] --;
407 if (rdpcb->r_timers[timer] == 0)
408 {
409 RDP_ACTION (RDP_iTIMER, rdpcb, timer, newstate)
410 if (newstate == RDP_sCLOSED)
411 /* next rdpcb */
412 break;
413 }
414 }
415 }
416 }
417 inp = next;
418 }
419 splx(s);
420 }
421 #endif
422