1 /*
2  $Log:	rdp_usrreq.c,v $
3  * Revision 2.8  85/05/30  11:54:12  walsh
4  * initialize r_srtt.
5  *
6  * Revision 2.7  85/02/26  08:27:02  walsh
7  * First pass at using IP source routing information to establish connections
8  * (possibly with hosts not known by the Internet gateways.)  The hooks with
9  * TCP could be better done - particularly dealing with IP addresses in the
10  * header for checksums and tcpdb lookups.
11  *
12  * Revision 2.6  84/11/29  12:51:00  walsh
13  * changed references to currentrtt into references to srtt, a better
14  * and less misleading mnemonic.
15  *
16  * Revision 2.5  84/11/08  16:13:17  walsh
17  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
18  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
19  * unless you do.
20  *
21  * Revision 2.4  84/11/05  12:41:29  walsh
22  * Set things up so can debug RDP connections just like can debug TCP
23  * connections.
24  *
25  * Revision 2.3  84/11/05  11:05:42  walsh
26  * comment and adjust number for rdp_iss in a mathematically correct way
27  * as a result of benchmarks (cf. operationally correct).
28  *
29  * Revision 2.2  84/11/05  10:49:01  walsh
30  * More changes to go with NULL messages getting their own sequence
31  * number.
32  *
33  * Revision 2.1  84/11/02  10:16:02  walsh
34  * Fixed to include RCS comments in checked out source.
35  *
36  *
37  * description:
38  * The user system call interface to RDP.
39  *
40  * revision 1.11
41  * date: 84/07/20 12:35:26;  author: root;  state: Exp;  lines added/del: 2/2
42  * fix syntax error.
43  *
44  * revision 1.10
45  * date: 84/07/20 11:25:53;  author: walsh;  state: Exp;  lines added/del: 3/2
46  * Don't let user use unreasonable (too small) retranmit took too long timers.
47  *
48  * revision 1.9
49  * date: 84/07/19 10:22:59;  author: walsh;  state: Exp;  lines added/del: 2/1
50  * Organized macros and classified their definitions in rdp_macros.h.
51  *
52  * revision 1.8
53  * date: 84/07/18 18:51:41;  author: walsh;  state: Exp;  lines added/del: 29/1
54  * Added provision for sending of NULL messages.  These are sent on an idle
55  * connection to determine that the other side still exists.
56  *
57  * revision 1.7
58  * date: 84/07/18 13:49:19;  author: walsh;  state: Exp;  lines added/del: 19/1
59  * RTTL timer is now user alterable.
60  *
61  * revision 1.6
62  * date: 84/07/17 22:42:08;  author: walsh;  state: Exp;  lines added/del: 7/3
63  * Can't connect to port numbers greater than RDP_pMAX.
64  *
65  * revision 1.5
66  * date: 84/07/12 13:48:38;  author: walsh;  state: Exp;  lines added/del: 2/1
67  * Rather than in-line stuffing of IP/RDP headers, at least half of which are
68  * constant, copy headers in from a template of what the headers are like.  The
69  * bcopy() call is turned into a movc3 instruction on the VAX by a sed script
70  * run over the assembler output of the C compiler.  Marginal speed-up.
71  *
72  * revision 1.4
73  * date: 84/07/10 10:45:38;  author: walsh;  state: Exp;  lines added/del: 20/19
74  * neatened up some formatting.
75  *
76  * revision 1.3
77  * date: 84/07/06 14:41:15;  author: wjacobso;  state: Exp;  lines added/del: 11/3
78  * use RSP_ACTION macro instead of rdp_action
79  *
80  * revision 1.2
81  * date: 84/07/06 09:51:35;  author: root;  state: Exp;  lines added/del: 56/17
82  * This version seems to run bug-free.
83  *
84  * revision 1.1
85  * date: 84/06/26 14:18:47;  author: walsh;  state: Exp;
86  * Initial revision
87  */
88 
89 
90 
91 #ifdef RDP
92 #ifdef	RCSIDENT
93 static char rcsident[] = "$Header: rdp_usrreq.c,v 2.8 85/05/30 11:54:12 walsh Exp $";
94 #endif RCSIDENT
95 
96 #include "../h/param.h"
97 #include "../h/systm.h"
98 #include "../h/mbuf.h"
99 #include "../h/socket.h"
100 #include "../h/socketvar.h"
101 #include "../h/protosw.h"
102 #include "../h/errno.h"
103 #include "../h/ioctl.h"
104 #include "../h/time.h"
105 #include "../h/kernel.h"
106 
107 #include "../net/if.h"
108 #include "../net/route.h"
109 
110 #include "../bbnnet/in.h"
111 #include "../bbnnet/net.h"
112 #include "../bbnnet/in_pcb.h"
113 #include "../bbnnet/in_var.h"
114 #include "../bbnnet/ip.h"
115 #include "../bbnnet/icmp.h"
116 #include "../bbnnet/rdp.h"
117 #include "../bbnnet/rdp_macros.h"
118 
119 /*
120  * RDP protocol interface to socket abstraction.
121  */
122 
123 /*
124  * misc data structures
125  */
126 
127 struct inpcb rdp;
128 struct rdp_stat rdpstat;
129 
130 struct dfilter	rdp_dfilter;
131 rdpsequence rdp_iss;
132 
133 /*
134  * RDP port allocation information
135  */
136 
137 extern rdp_binding_used();
138 
139 struct pr_advice rdp_advice =
140 {
141     RDP_RESERVED,
142     RDP_USERRESERVED,
143     RDP_MAXPORT,
144     RDP_USERRESERVED+1,
145     sizeof(u_char),
146     rdp_binding_used
147 } ;
148 
149 
150 /*
151  * Allocate and initialize a new RDPCB
152  * rdp_usrreq calls rdp_attach calls us.  rdp_usrreq splnet()'s
153  *
154  * Default allocation for kernel receive buffering is
155  * (rdp_ournbuf * rdp_ourmaxlen) bytes.
156  */
157 int rdp_ournbuf = 8;
158 int rdp_ourmaxlen = IPMAX - HDRSLOP;
159 
160 rdp_newrdpcb(inp)
161 register INPCB	*inp;
162 {
163     register RDPCB	*rdpcb;
164     register MBUF	*m;
165     MBUF	*mrq, *msq;
166 
167     m	= m_getclr(M_WAIT, MT_PCB);
168     mrq	= m_getclr(M_WAIT, MT_PCB);
169     msq	= m_getclr(M_WAIT, MT_PCB);
170     if ((m == NULL) || (mrq == NULL) || (msq == NULL))
171     {
172 	if (m)
173 	    m_free(m);
174 	if (mrq)
175 	    m_free(mrq);
176 	if (msq)
177 	    m_free(msq);
178 	return(ENOBUFS);
179     }
180 
181     rdpcb = mtod(m, RDPCB *);
182 
183     /* initialize non-zero tcb fields */
184 
185     rdpcb->r_sendq.rq_msgs	= mtod(msq, MBUF **);
186     rdpcb->r_rcvq.rq_msgs	= mtod(mrq, MBUF **);
187     rdpcb->r_state		= RDP_sUNOPENED;
188 #ifdef RDP_CS
189     rdpcb->r_entered[RDP_sUNOPENED] = iptime();
190 #endif
191     rdpcb->r_ournbuf	= MAX(1, MIN(RDP_MAXDGRAMS, rdp_ournbuf));
192     rdpcb->r_hisnbuf	= 1;
193 /*  rdpcb->r_synrcvd	= FALSE;	*/
194 /*  rdpcb->r_synacked	= FALSE;	*/
195 /*  rdpcb->r_usrclosed	= FALSE;	*/
196 /*  rdpcb->r_rttiming	= FALSE;	*/
197     rdpcb->r_sequential	= TRUE;
198     rdpcb->r_closewait	= RDP_tvCLOSEWAIT;
199     rdpcb->r_rttl	= RDP_tvRTTL;
200     rdpcb->r_tvnull	= RDP_tvNULL;
201     rdpcb->r_srtt	= RDP_tvRXMIN; /*###*/
202     rdpcb->r_rxmitime	= rdpcb->r_srtt + 1;
203     rdpcb->r_rttlindex	= (-1);
204     rdpcb->r_iss = rdp_iss;
205     rdpcb->r_sndnxt = rdpcb->r_snduna = rdpcb->r_iss +1;
206     rdp_iss += RDP_ISSINCR;
207 
208     /* attach the protocol specific pcb to the generic internet pcb */
209     inp->inp_ppcb = (caddr_t)rdpcb;
210     rdpcb->r_inpcb = inp;
211 
212     /*
213      * User has until listen(2) or connect(2) to increase max dgram
214      * size we will accept.  He does this by adjusting his socket's
215      * amount of receive buffering.
216      */
217     sbreserve (&rdpcb->r_inpcb->inp_socket->so_rcv, rdp_ourmaxlen);
218     pick_ourmaxlen(rdpcb);
219 
220     return(0);
221 }
222 
223 rdp_pcbdisconnect(inp)
224 INPCB	*inp;
225 {
226     register RDPCB	*rdpcb;
227     register MBUF	*m;
228     register int	 i;
229 
230     if (rdpcb = (RDPCB *) inp->inp_ppcb)
231     {
232 	inp->inp_ppcb = (caddr_t) NULL;
233 
234 	/*
235 	 * free all data on receive and send qs
236 	 * Remember, due to EACKS, send q may contain non-NULL
237 	 * RDP_DELIVERED pointers.
238 	 * If we close while we're retransmitting a NULL message,
239 	 * may have one of those on our send queue.
240 	 */
241 	for (i=0; i<RDP_MAXDGRAMS; i++)
242 	{
243 	    if (m = rdpcb->r_sendq.rq_msgs[i])
244 		if ((m != RDP_DELIVERED) && (m != RDP_NULLMSG))
245 		    m_freem(m);
246 	    if (m = rdpcb->r_rcvq.rq_msgs[i])
247 		if (m != RDP_DELIVERED)  /* just in case */
248 		    m_freem(m);
249 	}
250 	m_free(dtom(rdpcb->r_sendq.rq_msgs));
251 	m_free(dtom(rdpcb->r_rcvq.rq_msgs));
252 
253 	m_free(dtom(rdpcb));
254     }
255 }
256 
257 /*
258  * Is a rdp port/address pair already in use by some socket on this machine?
259  * Passed to in_pcbbind() to help it find a port/address binding
260  * that is unique for rdp.
261  */
262 int rdp_binding_used(inp, lport, laddr, reuselocal)
263 INPCB	*inp;
264 rdpportnum lport;
265 u_long laddr;
266 {
267     register INPCB		*i;
268 
269     for(i = rdp.inp_next; i != &rdp; i = i->inp_next)
270     {
271 	/*
272 	 * Since our inpcb is in this linked list, don't want to know
273 	 * if we, ourselves, are already using this binding.
274 	 */
275 	if (i != inp)
276 	    if (i->inp_lport == lport)
277 		/*
278 		 * Our/His address is unbound (INADDR_ANY) iff
279 		 * not yet connected to foreign host.
280 		 */
281 		if ((i->inp_laddr.s_addr == laddr) ||
282 		    (i->inp_laddr.s_addr == INADDR_ANY) ||
283 		    (laddr == INADDR_ANY))
284 		{
285 		    if (!reuselocal)
286 			break;
287 		    if (i->inp_faddr.s_addr == INADDR_ANY)
288 			/*
289 			 * We're both waiting for foreign
290 			 * connection.  Could only re-use if
291 			 * he was already connected.
292 			 */
293 			break;
294 		}
295     }
296     return (i != &rdp);
297 }
298 
299 char *rdp_conn_used(inp, lport, laddr, fport, faddr)
300 INPCB	*inp;
301 rdpportnum lport;
302 u_long laddr;
303 rdpportnum fport;
304 u_long faddr;
305 {
306     register INPCB		*i;
307 
308     for(i = rdp.inp_next; i != &rdp; i = i->inp_next)
309     {
310 	/*
311 	 * Since our inpcb is in this linked list, don't want to know
312 	 * if we, ourselves, are already using this connetion.
313 	 */
314 	if (i != inp)
315 	    if ((i->inp_lport == lport) &&
316 	    (i->inp_fport == fport) &&
317 	    (i->inp_laddr.s_addr == laddr) &&
318 	    (i->inp_faddr.s_addr == faddr))
319 
320 		return((char *)(i->inp_ppcb));
321     }
322     return ((char *) NULL);
323 }
324 
325 rdp_ioctl (rdpcb, command, data)
326 RDPCB *rdpcb;
327 int command;
328 caddr_t data;
329 {
330     switch (command)
331     {
332       case SIOCGNDGRAMS:
333 	*((int *) data) = rdpcb->r_ournbuf;
334 	break;
335 
336       case SIOCSNDGRAMS:
337 	if ((rdpcb->r_state == RDP_sUNOPENED) && (*((int *) data) > 0))
338 	    rdpcb->r_ournbuf = MIN (*((int *) data), RDP_MAXDGRAMS);
339 	else
340 	    return EINVAL;
341 	break;
342 
343 
344       case SIOCGSEQ:
345 	*((int *) data) = rdpcb->r_sequential;
346 	break;
347 
348       case SIOCSSEQ:
349 	if (rdpcb->r_state == RDP_sUNOPENED)
350 	    rdpcb->r_sequential = *((int *) data) ? TRUE : FALSE;
351 	else
352 	    return EINVAL;
353 	break;
354 
355 
356       case SIOCGRTTL:
357 	*((int *) data) = rdpcb->r_rttl;
358 	break;
359 
360       case SIOCSRTTL:
361 	{
362 	    /*
363 	     * Allow user to set r_rttl to 0 to disable.
364 	     */
365 	    unsigned int	newvalue;
366 
367 	    newvalue = *((unsigned int *) data);
368 	    if ((newvalue > RDP_MAXTIMERVAL) ||
369 		(newvalue && (newvalue < MIN(rdpcb->r_srtt, rdpcb->r_rxmitime))))
370 		return EINVAL;
371 	    else
372 		rdpcb->r_rttl = newvalue;
373 	}
374 	break;
375 
376 	/*
377 	 * Problem with socket level KEEPALIVES is that timer
378 	 * would be constant for all connections.
379 	 */
380       case SIOCGNULL:
381 	*((int *) data) = rdpcb->r_tvnull;
382 	break;
383 
384       case SIOCSNULL:
385 	{
386 	    /*
387 	     * Allow user to set to 0 to disable.
388 	     */
389 	    unsigned int	newvalue;
390 
391 	    newvalue = *((unsigned int *) data);
392 	    if ((newvalue > RDP_MAXTIMERVAL) ||
393 		(newvalue && (newvalue < rdpcb->r_rttl)))
394 		return EINVAL;
395 	    else
396 		rdpcb->r_tvnull = newvalue;
397 	}
398 	break;
399 
400       default:
401 	/* not our ioctl, let lower level try ioctl */
402 	return ip_ioctl (rdpcb->r_inpcb, command, data);
403     }
404 
405     return (0);
406 }
407 
408 /*
409  * Process a RDP user request (system call).
410  */
411 /*ARGSUSED*/
412 rdp_usrreq(so, req, m, nam, rights)
413 struct socket *so;
414 int req;
415 struct mbuf *m, *nam, *rights;
416 {
417     register RDPCB	*rdpcb;
418     register struct inpcb *inp;
419     register int s;
420     int error = 0;
421 
422     s = splnet();
423     inp = sotoinpcb(so);
424 
425     if (rights && rights->m_len)
426     {
427 	splx(s);
428 	return (EINVAL);
429     }
430     /*
431      * When an RDPCB is attached to a socket, then there will be
432      * an INPCB pointed at by the socket, and this
433      * structure will point at a subsidary RDPCB.
434      */
435     if (inp == 0 && req != PRU_ATTACH)
436     {
437 	splx(s);
438 	return (EINVAL);	/* XXX */
439     }
440     if (inp)
441 	rdpcb = (RDPCB *) inp->inp_ppcb;
442 
443     /*
444      * This switch becomes a 'caseb', so put common ones at top.
445      */
446     switch (req)
447     {
448 
449       case PRU_RCVD:
450 	/*
451 	 * After user has received message, ack the message. read(2)
452 	 */
453 	{
454 	    register rdpstate newstate;
455 
456 	    RDP_ACTION(RDP_iRCV, rdpcb, 0, newstate);
457 	}
458 	break;
459 
460       case PRU_SEND:
461 	/*
462 	 * Send this message. write(2)
463 	 */
464 	{
465 	    register rdpstate newstate;
466 
467 	    RDP_ACTION(RDP_iSEND, rdpcb, ((int) m), newstate);
468 	}
469 	break;
470 
471       case PRU_ATTACH:
472 	/*
473 	 * set up protocol control blocks.  socket(2)
474 	 */
475 	if (inp)
476 	{
477 	    error = EISCONN;
478 	    break;
479 	}
480 	if (error = rdp_attach(so))
481 	    break;
482 
483 	/*
484 	 * so_linger doesn't affect anything I know of in the socket level
485 	 * -- see soclose().  Maybe this is one of those someday things.
486 	 */
487 	if ((so->so_options & SO_LINGER) && so->so_linger == 0)
488 		so->so_linger = 120;
489 
490 	rdpcb = (RDPCB *) ((INPCB *) so->so_pcb)->inp_ppcb;
491 	break;
492 
493       case PRU_DETACH:
494 	/*
495 	 * close(2) the connection
496 	 */
497 	rdp_close(rdpcb);
498 	break;
499 
500       case PRU_BIND:
501 	/*
502 	 * Give the socket an address.  bind(2)
503 	 */
504 	error = in_pcbbind(inp, nam, &rdp_advice);
505 	break;
506 
507       case PRU_LISTEN:
508 	/*
509 	 * Prepare to accept connections.  Passive open.  listen(2)
510 	 */
511 	if (inp->inp_lport == 0)
512 	    if (error = in_pcbbind(inp, (MBUF *)0, &rdp_advice))
513 		break;
514 
515 	pick_ourmaxlen(rdpcb);
516 	rdp_action(RDP_iLISTEN, rdpcb, 0);
517 	break;
518 
519       case PRU_CONNECT:
520 	/*
521 	 * Active open.  connect(2).  Initiate connection to peer.
522 	 * Bind the local end if not already.  Set the routing.
523 	 * Crank up the state machine.
524 	 */
525 	{
526 	    struct sockaddr_in *sin;
527 
528 	    /*
529 	     * ensure foreign address might be valid.
530 	     * Can't connect to broadcast address...
531 	     */
532 	    sin = mtod(nam, struct sockaddr_in *);
533 	    if ((in_broadcast(sin->sin_addr)) ||
534 		(sin->sin_port > RDP_MAXPORT))
535 	    {
536 		error = EADDRNOTAVAIL;
537 		break;
538 	    }
539 
540 	    if (inp->inp_lport == 0)
541 		if (error = in_pcbbind(inp, (MBUF *)0, &rdp_advice))
542 		    break;
543 	    if (error = in_pcbconnect(inp, nam, rdp_conn_used))
544 		break;
545 
546 	    /*
547 	     * So can debug connection problems without having to change
548 	     * every program or apply debugging flag to each program every
549 	     * time run it.
550 	     */
551 	    dowedebug(inp, so, &rdp_dfilter);
552 
553 	    soisconnecting(so);
554 	    pick_ourmaxlen(rdpcb);
555 	    rdp_template(rdpcb);
556 	    rdp_action(RDP_iCONNECT, rdpcb, 0);
557 	}
558 	break;
559 
560 	/*
561 	 * Create a TCP connection between two sockets.
562 	 */
563       case PRU_CONNECT2:
564 	error = EOPNOTSUPP;
565 	break;
566 
567       case PRU_DISCONNECT:
568 	/*
569 	 * close(2)
570 	 */
571 	rdp_close(rdpcb);
572 	break;
573 
574       case PRU_ACCEPT:
575 	/*
576 	 * accept(2).  Socket code has waited until a new connection
577 	 * is available for the listener/server.  Now that there is
578 	 * one, we just tell them who it is.
579 	 */
580 	{
581 	    struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
582 
583 	    nam->m_len = sizeof (struct sockaddr_in);
584 	    sin->sin_family = AF_INET;
585 	    sin->sin_port = inp->inp_fport;
586 	    sin->sin_addr = inp->inp_faddr;
587 	}
588 	break;
589 
590       case PRU_SHUTDOWN:
591 	/*
592 	 * user has shutdown(2) for writing.  This is a friendly close;
593 	 * the user may still want to read.
594 	 */
595 	socantsendmore(so);
596 	break;
597 
598       case PRU_ABORT:
599 	/*
600 	 * abort un-accept(2)ed connections when close listening socket
601 	 * act as if it was accepted and closed.  Remove socket from
602 	 * parent socket's qs so that not hang in soclose()
603 	 */
604 
605 	/* accept */
606 	if (! soqremque(so, 0)) /* SYNSENT, LSYNRCVD */
607 	    if (! soqremque(so, 1)) /* ESTAB */
608 		panic("rdp ABORT");
609 
610 	/* close */
611 	rdp_close(rdpcb);
612 	break;
613 
614       case PRU_CONTROL:
615 	error = rdp_ioctl(rdpcb, (int) m, (caddr_t) nam);
616 	break;
617 
618 /* SOME AS YET UNIMPLEMENTED HOOKS */
619       case PRU_SENSE:
620 	error = EOPNOTSUPP;
621 	break;
622 /* END UNIMPLEMENTED HOOKS */
623 
624       case PRU_RCVOOB:
625       case PRU_SENDOOB:
626 	error = EOPNOTSUPP;
627 	break;
628 
629       case PRU_SOCKADDR:
630 	/*
631 	 * Tell user his (local) address/binding
632 	 */
633 	in_setsockaddr(inp, nam);
634 	break;
635 
636       case PRU_PEERADDR:
637 	in_setpeeraddr(inp, nam);
638 	break;
639 
640 #ifdef neverdef
641       case PRU_SLOWTIMO:
642 	rdp_timeo();
643 	break;
644 #endif
645 
646       default:
647 	panic("rdp_usrreq");
648     }
649     splx(s);
650     return (error);
651 }
652 
653 /*
654  * get/setsockopt() handler
655  */
656 
657 rdp_ctloutput(req,so,level,optname,optval)
658 int req;
659 struct socket *so;
660 int level, optname;
661 struct mbuf **optval;
662 {
663     int s = splnet(); /* like PRU/packet/timer entry into net code */
664     int error;
665     struct inpcb *inp;
666 
667     /*
668      * See comments by tcp_ctloutput()
669      */
670     if (level == IPPROTO_RDP)
671     {
672 	inp = sotoinpcb(so);
673 
674 	switch(optname)
675 	{
676 	  case PRCO_GETOPT:
677 	    error = rdp_getopt(inp, optname, optval);
678 	    break;
679 
680 	  case PRCO_SETOPT:
681 	    error = rdp_setopt(inp, optname, optval);
682 	    break;
683 
684 	  default:
685 	    panic("rdp_ctloutput");
686 	}
687     } else
688         error = ip_ctloutput(req,so,level,optname,optval);
689 
690     splx(s);
691     return (error);
692 }
693 
694 rdp_setopt (inp, command, data)
695 struct inpcb	*inp;
696 struct mbuf	**data;
697 {
698     /* no RDP specific options accessed by setsockopt() as yet */
699     return EOPNOTSUPP;
700 }
701 
702 rdp_getopt (inp, command, data)
703 struct inpcb	*inp;
704 struct mbuf	**data;
705 {
706     /* no RDP specific options accessed by getsockopt() as yet */
707     return EOPNOTSUPP;
708 }
709 
710 /*
711  * attach rdp protocol to socket
712  */
713 rdp_attach(so)
714 struct socket *so;
715 {
716     struct inpcb *inp;
717     int error;
718 
719     if ((error = in_pcballoc(so,&rdp)) == 0)
720     {
721 	inp = sotoinpcb(so);
722 	if (error = rdp_newrdpcb(inp))
723 	    in_pcbdetach(inp,(int(*)())0);
724     }
725     return(error);
726 }
727 
728 
729 
730 /*
731  * Initiate (or continue) disconnect.  close(2).
732  */
733 rdp_close(rdpcb)
734 register RDPCB *rdpcb;
735 {
736     struct socket *so;
737 
738     if (! rdpcb->r_usrclosed)
739     {
740 	rdpcb->r_usrclosed = TRUE;
741 	so = rdpcb->r_inpcb->inp_socket;
742 	soisdisconnecting(so);
743 	sbflush(&so->so_rcv);
744 	rdp_action(RDP_iUCLOSE, rdpcb, 0);
745     }
746 }
747 
748 rdp_init()
749 {
750     /*
751      * Leave these checks in!  It's a pain in the ass to find out
752      * problems caused by too small mbufs if someone changes the
753      * size of an mbuf.
754      */
755     if (sizeof(RDPCB) > MLEN)
756 	panic("rdpcb too big");
757 
758     if (sizeof(R_DEBUG) > MLEN)
759 	panic("r_debug too big");
760 
761     if (sizeof(RDPHDR) + sizeof(struct ip) > MLEN)
762 	panic("rdphdr too big");
763 
764     /*
765      * When send a packet, we allocate an mbuf for options and assume
766      * they'll always fit.
767      */
768     if (sizeof(EACKOPTIONS) * RDP_MAXDGRAMS > MLEN)
769 	panic("RDP_MAXDGRAMS too big");
770 
771     /*
772      * rq_msgs is assumed to fit within a single mbuf.
773      */
774     if (sizeof(MBUF *) * RDP_MAXDGRAMS > MLEN)
775 	panic("RDP_MAXDGRAMS too big 2");
776 
777     /*
778      * When receive a packet, IP hdr + RDP hdr + RDP options pulled up
779      * into a single mbuf and later assumed to be contiguous.  We'd like
780      * to avoid deadlock on a connection leading to a timeout failure of
781      * the connection.  Also, later just before we pass the packet to the
782      * user, we trim off the headers assuming they're in one mbuf.
783      *
784      * This superceeds a few of the above, but if we change things, the
785      * separate listing will make things easier.
786      */
787     if (sizeof(struct ip)+sizeof(RDPHDR)+(sizeof(EACKOPTIONS)*RDP_MAXDGRAMS)
788 	> MLEN)
789 	panic("RDP_MAXDGRAMS too big 3");
790 
791     rdp_iss = time.tv_sec;
792 
793     rdp.inp_next = rdp.inp_prev = &rdp;
794 
795     /* are only 4 things to match. turn off for now */
796     rdp_dfilter.matches = 5;
797 
798     ipsw[IPPROTO_RDP].ipsw_hlen = sizeof(struct ip) + RDPHDRSZ;
799 }
800 
801 rdp_ctlinput (prc_code, arg)
802 caddr_t arg;
803 {
804     int error;
805 
806     error = inetctlerrmap[prc_code];
807 
808     switch (prc_code)
809     {
810 	case PRC_UNREACH_PROTOCOL:	/* icmp message */
811 	case PRC_UNREACH_PORT:
812 	case PRC_MSGSIZE:
813 	    {
814 	    RDPHDR *pkt;
815 	    RDPCB *rdpcb;
816 	    struct ip *ip;
817 
818 	    ip = (struct ip *) (&((struct icmp *) arg)->ic_iphdr);
819 	    pkt = (RDPHDR *) (ip+1);
820 	    rdpcb = (RDPCB *) rdp_conn_used((struct inpcb *) NULL,
821 		pkt->rh_sport, ip->ip_src.s_addr,
822 		pkt->rh_dport, ip->ip_dst.s_addr);
823 
824 	    if (rdpcb)
825 	    {
826 		rdpcb->r_inpcb->inp_socket->so_error = error;
827 		rdp_close(rdpcb);
828 	    }
829 	    }
830 	    break;
831 
832 	case PRC_UNREACH_NET:
833 	case PRC_UNREACH_HOST:
834 	    {
835 	    RDPHDR *pkt;
836 	    RDPCB *rdpcb;
837 	    struct ip *ip;
838 
839 	    ip = (struct ip *) (&((struct icmp *) arg)->ic_iphdr);
840 	    pkt = (RDPHDR *) (ip+1);
841 	    rdpcb = (RDPCB *) rdp_conn_used((struct inpcb *) NULL,
842 		pkt->rh_sport, ip->ip_src.s_addr,
843 		pkt->rh_dport, ip->ip_dst.s_addr);
844 
845 	    if (rdpcb)
846 	    {
847 		struct socket *so;
848 
849 		so = rdpcb->r_inpcb->inp_socket;
850 		if ((so->so_state & SS_NOFDREF) == 0)
851 		    advise_user(so, error);
852 		else
853 		{
854 		    so->so_error = error;
855 		    rdp_close(rdpcb);
856 		}
857 	    }
858 	    }
859 	    break;
860 
861 	case PRC_GWDOWN:
862 	    in_gdown (&rdp, (u_long) arg);
863 	    break;
864 
865 	case PRC_REDIRECT_NET:	/* icmp message */
866 	case PRC_REDIRECT_HOST:
867 	    {
868 	    RDPHDR *pkt;
869 	    RDPCB *rdpcb;
870 	    struct ip *ip;
871 
872 	    ip = (struct ip *) (&((struct icmp *) arg)->ic_iphdr);
873 	    pkt = (RDPHDR *) (ip+1);
874 	    rdpcb = (RDPCB *) rdp_conn_used((struct inpcb *) NULL,
875 		pkt->rh_sport, ip->ip_src.s_addr,
876 		pkt->rh_dport, ip->ip_dst.s_addr);
877 
878 	    if (rdpcb)
879 		icmp_redirect_inp(rdpcb->r_inpcb, (struct icmp *) arg,
880 		     prc_code == PRC_REDIRECT_NET ? rtnet : rthost);
881 	    }
882 	    break;
883 
884 	case PRC_TIMXCEED_INTRANS:	/* icmp message */
885 	case PRC_TIMXCEED_REASS:
886 	case PRC_PARAMPROB:
887 	    break;
888 
889 	case PRC_QUENCH:	/* icmp message */
890 	    /*
891 	     * Reduce the traffic on this connection, so the gateway is happy.
892 	     * Since can't change message size, must change frequency.  If continue
893 	     * to send it straight out in response to write(2), can only tweak
894 	     * retransmission period.
895 	     *
896 	     * This will allow the gateway to relax until things flow again and we
897 	     * calculate another round trip time.
898 	     */
899 	    {
900 	    RDPHDR *pkt;
901 	    RDPCB *rdpcb;
902 	    struct ip *ip;
903 
904 	    ip = (struct ip *) (&((struct icmp *) arg)->ic_iphdr);
905 	    pkt = (RDPHDR *) (ip+1);
906 	    rdpcb = (RDPCB *) rdp_conn_used((struct inpcb *) NULL,
907 		pkt->rh_sport, ip->ip_src.s_addr,
908 		pkt->rh_dport, ip->ip_dst.s_addr);
909 	    if (rdpcb)
910 		rdpcb->r_rxmitime = MIN(rdpcb->r_rxmitime +1, RDP_tvRXMAX);
911 	    }
912 	    break;
913 
914 	case PRC_IFDOWN:
915 	    {
916 	    u_long addr;
917 
918 	    addr = ((struct sockaddr_in *)(arg))->sin_addr.s_addr;
919 	    inpcb_notify(&rdp, addr, (u_long) 0, error);
920 	    inpcb_notify(&rdp, (u_long) 0, addr, error);
921 	    }
922 	    break;
923 
924 	case PRC_HOSTDEAD:	/* from imp interface */
925 	case PRC_HOSTUNREACH:
926 	    /*
927 	     * get same message for destination hosts and gateways.
928 	     */
929 	    {
930 	    u_long addr;
931 
932 	    addr = ((struct sockaddr_in *)arg)->sin_addr.s_addr;
933 	    in_gdown (&rdp, addr);
934 	    inpcb_notify(&rdp, (u_long) 0, addr, error);
935 	    }
936 	    break;
937 
938 	default:
939 	    panic("rdp_ctlinput");
940     }
941 }
942 #endif
943