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
rdp_newrdpcb(inp)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
rdp_pcbdisconnect(inp)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 */
rdp_binding_used(inp,lport,laddr,reuselocal)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
rdp_conn_used(inp,lport,laddr,fport,faddr)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
rdp_ioctl(rdpcb,command,data)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
rdp_ctloutput(req,so,level,optname,optval)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 */
rdp_close(rdpcb)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
rdp_init()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
rdp_ctlinput(prc_code,arg)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