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