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