home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / RDP / rdp_usrreq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-18  |  13.2 KB  |  609 lines

  1. /**************************************************************************/
  2. /*       Copyright(c) 1987, 1992 by BBN Systems and Technologies,         */
  3. /*         A Division of Bolt Beranek and Newman Inc.                     */
  4. /*                                                                        */
  5. /*       RDP implementation for 4.2/4.3bsd by Craig Partridge             */
  6. /*                                                                        */
  7. /*  Permission to use, copy, modify, distribute, and sell this software   */
  8. /*  and its documentation for any purpose is hereby granted without fee,  */
  9. /*  provided that the above copyright notice and this permission appear   */
  10. /*  in all copies and in supporting documentation, and that the name of   */
  11. /*  Bolt Beranek and Newman Inc.  not be used in advertising or           */
  12. /*  publicity pertaining to distribution of the software without          */
  13. /*  specific, written prior permission. BBN makes no representations      */
  14. /*  about the suitability of this software for any purposes.  It is       */
  15. /*  provided "AS IS" without express or implied warranties.               */
  16. /**************************************************************************/
  17.  
  18. #include "../h/param.h"
  19. #include "../h/dir.h"
  20. #include "../h/user.h"
  21. #include "../h/mbuf.h"
  22. #include "../h/protosw.h"
  23. #include "../h/socket.h"
  24. #include "../h/socketvar.h"
  25. #include "../h/stat.h"
  26. #include "../h/errno.h"
  27.  
  28. #include "../net/if.h"
  29. #include "../net/route.h"
  30.  
  31. #include "../netinet/in.h"
  32. #include "../netinet/in_pcb.h"
  33. #include "../netinet/in_systm.h"
  34. #include "../netinet/ip.h"
  35. #include "../netinet/ip_var.h"
  36. #include "../netinet/ip_icmp.h"
  37.  
  38. #include "../netinet/rdp.h"
  39. #include "../netinet/rdp_var.h"
  40. #include "../netinet/rdp_conf.h"
  41. #include "../netinet/rdp_ip.h"
  42.  
  43. /* head of pcb queue */
  44. struct inpcb rdb;
  45.  
  46. /* serial number counter */
  47. u_long rdpserial;
  48.  
  49. /* rdp statistics */
  50.  
  51. struct rdpstats rdp_info;
  52.  
  53. /*
  54.  * max seg size.  have treated it as an indication of how large a packet
  55.  * we are willing to buffer and have not tried to use it as a way of
  56.  * finding optimal packet size for connection.
  57.  */
  58. u_short rdp_mtu = 1024;
  59.  
  60. /*
  61.  * timer backoff table for starting connections
  62.  * after that we use rtt.  Can tune table for environment...
  63.  *
  64.  * currently tried to tune it for local net (2 tries, then long timeouts
  65.  * for wide-area network).
  66.  */
  67.  
  68. short rdp_start[] = 
  69. {
  70.     1, 3, 12, 28, 60, 128
  71. };
  72.  
  73. static short rdp_tryinit = sizeof(rdp_start)/sizeof(rdp_start[0]);
  74.  
  75.  
  76. /**************************************************************************/
  77. /*                        init routine                                    */
  78. /**************************************************************************/
  79.  
  80. rdp_init()
  81. {
  82.     struct rdphdr rdh;
  83.     static int called = 0;
  84.  
  85.     if (called)
  86.     return;
  87.  
  88.     called++;
  89.  
  90. #ifdef DEBUG
  91.     printf("rdpcb size =%d, mlen =%d\n",sizeof(struct rdpcb),MLEN);
  92.     printf("rdque size =%d, mlen =%d\n",sizeof(struct rdpque),MLEN);
  93. #endif DEBUG
  94.  
  95.     rdb.inp_next = rdb.inp_prev = &rdb;
  96.  
  97.     /* choose a random starting place? */
  98.     rdpserial = 1;
  99.  
  100. #ifdef DEBUG
  101.     printf("rdp_mtu is %d\n",rdp_mtu);
  102. #endif
  103.  
  104.     /* leave this in -- saves us from dumb mistakes */
  105.     if (sizeof(struct rdpcb) > MLEN)
  106.     {
  107.     panic("rdp_init: rdpcb size");
  108.     }
  109.  
  110.     if (sizeof(struct rdpque) > MLEN)
  111.     {
  112.     panic("rdp_init: rdpque size");
  113.     }
  114.  
  115.     /* compiler woes? */
  116.     if (sizeof(struct rdphdr) != R_HDRSIZE)
  117.     {
  118.     /* may be o.k. -- just that there is trailing junk in header */
  119.     if (((caddr_t)&rdh.rh_sum - (caddr_t)&rdh) != (R_HDRSIZE- 2))
  120.         panic("rdp_init: rdphdr size");
  121.     }
  122.  
  123.     /*
  124.      * IP header + RDP header (including EACKs)
  125.      * must fit in a single mbuf
  126.      */
  127.  
  128.     if ((RI_SIZE + (R_RCVWIN * 4)) > MLEN)
  129.     {
  130.     /* our eacks for packets from remote will exceed mbuf */
  131.     panic("rdp_init: rcv eacks");
  132.     }
  133.  
  134.     if ((RI_SIZE + (R_MAXSND * 4)) > MLEN)
  135.     {
  136.     /* remote's eacks for our packets will exceed mbuf */
  137.     panic("rdp_init: snd eacks");
  138.     }
  139.  
  140. #ifdef DEBUG
  141.     printf("rdp options: DEBUG");
  142. #ifdef EACK
  143.     printf(" EACK");
  144. #endif /* EACK */
  145. #ifdef INETCKSUM
  146.     printf(" INETCKSUM");
  147. #endif /* INETCKSUM */
  148. #ifdef ALTRTT
  149.     printf(" ALTRTT");
  150. #else
  151.     printf(" OLDRTT");
  152. #endif /* ALTRTT */
  153.     printf("\n");
  154. #endif /* DEBUG */
  155. }
  156.  
  157.  
  158.  
  159. /**************************************************************************/
  160. /*       usrreq routine -- see BSD Networking Implementation Notes        */
  161. /**************************************************************************/
  162.  
  163. rdp_usrreq(so,req,m,addr,rights)
  164. struct socket *so;
  165. int req;
  166. struct mbuf *m, *addr, *rights;
  167. {
  168.     struct inpcb *inp = sotoinpcb(so);
  169.     struct rdpcb *rp;
  170.     int error = 0;
  171.     int s;
  172.  
  173.     s = splnet();
  174.  
  175. #ifdef BSD4_3
  176.     /* special case -- sigh... */
  177.  
  178.     if (req == PRU_CONTROL)
  179.     return(in_control(so,(int)m,(caddr_t)addr,(struct ifnet *)rights));
  180. #endif /* BSD4_3 */
  181.  
  182.     /* pre-process and check values */
  183.  
  184.     if ((rights != 0) && rights->m_len)
  185.     {
  186.     error = EINVAL;
  187.     goto done;
  188.     }
  189.  
  190.     switch (req)
  191.     {
  192.     case PRU_ATTACH:
  193.         if (inp != 0)
  194.         {
  195.         error = EINVAL;
  196.         goto done;
  197.         }
  198.         break;
  199.     
  200.     case PRU_DETACH:
  201.     case PRU_BIND:
  202.     case PRU_ABORT:
  203.     case PRU_SENSE:
  204.     case PRU_CONTROL:
  205.     case PRU_SHUTDOWN:
  206.         if (inp == 0)
  207.         {
  208.         error = EINVAL;
  209.         goto done;
  210.         }
  211.         break;
  212.  
  213.         /* these require us to be bound at our end */
  214.     case PRU_SOCKADDR:
  215.     case PRU_CONNECT:
  216.     case PRU_LISTEN:
  217.         if (inp == 0)
  218.         error = EINVAL;
  219.         else if (inp->inp_lport == 0)
  220.         error = in_pcbbind(inp,(struct mbuf *)0);
  221.  
  222.         if (error)
  223.         goto done;
  224.         break;
  225.  
  226.  
  227.         /* these make no sense if we aren't connected? */
  228.     case PRU_DISCONNECT:
  229.     case PRU_ACCEPT:
  230.     case PRU_SEND:
  231.     case PRU_PEERADDR:
  232.         if ((inp ==0) || (inp->inp_lport == 0) || (inp->inp_fport == 0))
  233.         {
  234.         error = EINVAL;
  235.         goto done;
  236.         }
  237.         break;
  238.  
  239.     case PRU_RCVD:
  240.     case PRU_RCVOOB:
  241.     case PRU_SENDOOB:
  242.     case PRU_FASTTIMO:
  243.     case PRU_SLOWTIMO:
  244.     case PRU_CONNECT2:
  245.     case PRU_PROTORCV:
  246.     case PRU_PROTOSEND:
  247.         error = EOPNOTSUPP;
  248.         goto done;
  249.  
  250.     default:
  251.         panic("rdp_usrreq");
  252.     }
  253.  
  254.     if (req != PRU_ATTACH)
  255.     rp = (struct rdpcb *)inp->inp_ppcb;
  256.  
  257.     /* O.K. now we know we are in a vaguely rational world */
  258.  
  259.     switch(req)
  260.     {
  261.     case PRU_ATTACH:
  262.         error = rdp_attach(so);
  263.         break;
  264.  
  265.     case PRU_DETACH:
  266.         error = rdp_detach(so,inp);
  267.         break;
  268.  
  269.     case PRU_BIND:
  270.         error = in_pcbbind(inp,addr);
  271.         break;
  272.  
  273.     case PRU_LISTEN:
  274.         if (rp->rp_state != R_CLOSED)
  275.         error = EISCONN;
  276.         else
  277.         rp->rp_state = R_LISTEN;
  278.         break;
  279.  
  280.     case PRU_CONNECT:
  281.         if (rp->rp_state != R_CLOSED)
  282.         error = EISCONN;
  283.         else 
  284.         error = rdp_connect(inp,addr);
  285.         break;
  286.  
  287.     case PRU_ABORT:
  288.         /* detach works as abort would want */
  289.         error = 0;
  290.         (void) rdp_fatal(inp);
  291.         break;
  292.  
  293.     case PRU_DISCONNECT:
  294.         error = rdp_disconnect(inp);
  295.         break;
  296.  
  297.     case PRU_ACCEPT:
  298.         /* someone slammed the door before we accepted */
  299.         if (rp->rp_state != R_OPEN)
  300.         {
  301.         error = ECONNABORTED;
  302.         break;
  303.         }
  304.         else
  305.             (void) in_setpeeraddr(inp,addr);
  306.         break;
  307.  
  308.     case PRU_SHUTDOWN:
  309.         /* not going to send any more -- who cares? */
  310.         socantsendmore(so);
  311.         break;
  312.  
  313.     case PRU_SEND:
  314.         /* now the tough stuff */
  315.         if (rp->rp_state != R_OPEN)
  316.         error = ENOTCONN;
  317.         else
  318.         {
  319.         error = rdp_send(inp,m);
  320.         m = 0;
  321.         }
  322.         break;
  323.  
  324. #ifndef BSD4_3
  325.     case PRU_CONTROL:
  326.         error = EOPNOTSUPP;
  327.         m = 0;
  328.         break;
  329. #endif
  330.  
  331.     case PRU_SENSE:
  332.         /* zero m so it isn't freed */
  333.         ((struct stat *)m)->st_blksize = rp->rp_sndbuf;
  334.         m = 0;
  335.         break;
  336.  
  337.     case PRU_SOCKADDR:
  338.         (void) in_setsockaddr(inp,addr);
  339.         break;
  340.  
  341.     case PRU_PEERADDR:
  342.         (void) in_setpeeraddr(inp,addr);
  343.         break;
  344.     }
  345.  
  346. done:
  347.     if (m != 0)
  348.     (void) m_freem(m);
  349.  
  350.     splx(s);
  351.  
  352.     return(error);
  353. }
  354.  
  355. /**************************************************************************/
  356. /*                    ctlinput routine                                    */
  357. /*     Berkeley gives too little information to be very useful here       */
  358. /**************************************************************************/
  359.  
  360. rdp_ctlinput(cmd,addr)
  361. int cmd;
  362. #ifndef BSD4_3
  363. caddr_t *addr;
  364. #else
  365. struct sockaddr *addr;
  366. #endif
  367. {
  368. #ifndef BSD4_3
  369.     struct sockaddr_in tmp;
  370. #endif
  371.     struct sockaddr_in *sin;
  372.     extern u_char inetctlerrmap[];
  373.     extern int rdp_quench(), rdp_fatal();
  374. #ifdef BSD4_3
  375.     extern int in_rtchange();
  376. #endif
  377.  
  378.     if ((cmd < 0) ||  (cmd > PRC_NCMDS))
  379.     return;
  380.  
  381. #ifndef BSD4_3
  382.     if (((struct icmp *)addr)->icmp_ip.ip_p != IPPROTO_RDP)
  383.     return;
  384.  
  385.     bzero((caddr_t)&tmp,sizeof(tmp));
  386.     tmp.sin_family = AF_INET;
  387.     tmp.sin_addr = ((struct icmp *)addr)->icmp_ip.ip_dst;
  388.     sin = &tmp;
  389. #else
  390.     sin = (struct sockaddr_in *)addr;
  391. #endif
  392.  
  393.     if (sin->sin_family != AF_INET)
  394.     return;
  395.  
  396.     switch(cmd)
  397.     {
  398.     case PRC_IFDOWN:
  399.     case PRC_MSGSIZE:
  400.     case PRC_PARAMPROB:
  401.     case PRC_TIMXCEED_INTRANS:
  402.     case PRC_TIMXCEED_REASS:
  403.         break;
  404.  
  405.     case PRC_QUENCH:
  406.         in_pcbnotify(&rdb,&sin->sin_addr,0,rdp_quench);
  407.         break;
  408.  
  409.         /* close all affected connections */
  410.     case PRC_HOSTDEAD:
  411.     case PRC_HOSTUNREACH:
  412.     case PRC_UNREACH_PROTOCOL:
  413.     case PRC_UNREACH_NET:
  414.     case PRC_UNREACH_HOST:
  415.         in_pcbnotify(&rdb,&sin->sin_addr,(int)inetctlerrmap[cmd],rdp_fatal);
  416.         break;
  417.  
  418.     case PRC_UNREACH_PORT:
  419.     case PRC_UNREACH_NEEDFRAG:
  420.     case PRC_UNREACH_SRCFAIL:
  421.         break;
  422.  
  423.     case PRC_ROUTEDEAD:
  424.     case PRC_REDIRECT_NET:
  425.     case PRC_REDIRECT_HOST:
  426.     case PRC_REDIRECT_TOSNET:
  427.     case PRC_REDIRECT_TOSHOST:
  428. #ifdef BSD4_3
  429.         in_pcbnotify(&rdb,&sin->sin_addr,0, in_rtchange);
  430. #endif
  431.         break;
  432.  
  433.     default:
  434.         panic("rdp_ctlinput");
  435.     }
  436. }
  437.  
  438. /**************************************************************************/
  439. /*                   cltoutput routine                                    */
  440. /*              again, only exercised by 4.3                              */
  441. /**************************************************************************/
  442.  
  443. rdp_ctloutput(op, so, level, optname, mp)
  444. int op;
  445. struct socket *so;
  446. int level, optname;
  447. struct mbuf **mp;
  448. {
  449.  
  450. #ifdef notdef
  451.  
  452.     /* requires 4.3 */
  453.     if (level != IPPROTO_RDP)
  454.     return(ip_ctloutput(op,so,level,optname,mp));
  455. #endif
  456.  
  457.     /* 
  458.      * nothing yet
  459.      *
  460.      * should allow applications to choose window size information
  461.      * before starting connection.
  462.      */
  463.  
  464.     return(0);
  465. }
  466.  
  467. /**************************************************************************/
  468. /*                slowtimo -- state timer                                 */
  469. /**************************************************************************/
  470.  
  471. rdp_slowtimo()
  472. {
  473.     int s = splnet();
  474.     register i, j;
  475.     register u_short timeout;
  476.     register struct rdpque *rq;
  477.     struct rdpcb *rp;
  478.     struct inpcb *inp;
  479.     struct mbuf *m;
  480.     int flags;
  481.  
  482.     s = splnet();
  483.  
  484.     for(inp = rdb.inp_next; inp != &rdb; inp = inp->inp_next)
  485.     {
  486.     if ((rp = (struct rdpcb *)inp->inp_ppcb) == 0)
  487.         continue;
  488.  
  489.     rq = rp->rp_rq;
  490.  
  491.     /* only do states we care about */
  492.  
  493.     switch (rp->rp_state)
  494.     {
  495.         /* trying to initiate connection */
  496.         case R_SYN_SENT:
  497.         case R_SYN_RCVD:
  498.         if (++(rq->rq_sndtimer[0]) >= rdp_start[rq->rq_retries[0]])
  499.         {
  500.             if (++(rq->rq_retries[0]) >= rdp_tryinit)
  501.             {
  502.             inp->inp_socket->so_error = ETIMEDOUT;
  503.             (void) rdp_fatal(inp);
  504.             break;
  505.             }
  506.  
  507.             if (rp->rp_state == R_SYN_SENT)
  508.             {
  509.             /* sndnxt = sndiss */
  510.             (void) rdp_syn(inp,0,rp->rp_sndnxt,(u_long)0);
  511.             }
  512.             else
  513.             {
  514.                /* rcvcur == rcvirs , sndnxt = sndiss */
  515.                (void) rdp_syn(inp,1,rp->rp_sndnxt,rp->rp_rcvcur);
  516.             }
  517.  
  518.         }
  519.         break;
  520.  
  521.         /* activity timer or packet timer */
  522.         case R_OPEN:
  523.         /* keepalive -- change to use if SO_KEEPALIVE requested? */
  524.         if ((rp->rp_timer != 0) && (--(rp->rp_timer)==0))
  525.         {
  526.             /* don't need to reset the timer */
  527.  
  528.             rdp_info.rst_nulls++;
  529.             (void) rdp_send(inp,(struct mbuf *)0);
  530.         }
  531.         /* fall thru... */
  532.  
  533.         case R_DRAIN:
  534.         /* packet timers */
  535.         i = rp->rp_sndnxt - rp->rp_snduna;
  536.         j = rq->rq_sndbase;
  537.         flags = inp->inp_socket->so_state & SS_PRIV;
  538.  
  539.         for(; i>0; i--)
  540.         {
  541.             if (rq->rq_sndq[j] == 0)
  542.             goto next;
  543.  
  544.             timeout = (rq->rq_retries[j] + 1) * rp->rp_estrtt;
  545.  
  546.             if (++(rq->rq_sndtimer[j]) < timeout)
  547.             goto next;
  548.  
  549.             /* too many tries?? */
  550.             if (++(rq->rq_retries[j]) > R_MAXTRIES)
  551.             {
  552.             rdp_info.rst_conntimo++;
  553.             inp->inp_socket->so_error = ETIMEDOUT;
  554.             (void) rdp_fatal(inp);
  555.             break;
  556.             }
  557.  
  558.             if ((m=m_copy(rq->rq_sndq[j],0,(int)M_COPYALL))==0)
  559.             goto next;
  560.  
  561.             rdp_info.rst_retrans++;
  562.  
  563.             (void)ip_output(m,(struct mbuf *)0,&(inp->inp_route),flags);
  564. next:
  565.             if (++j == R_MAXSND)
  566.             j = 0;
  567.         }
  568.         break;
  569.  
  570.  
  571.         /* closing */
  572.         case R_CLOSE_WAIT:
  573.         if ((rp->rp_timer != 0) && (--(rp->rp_timer)==0))
  574.         {
  575.             rp->rp_state = R_CLOSED;
  576.             (void) rdp_detach(inp->inp_socket,inp);
  577.         }
  578.         else if (rq->rq_retries[0] <= R_MAXTRIES)
  579.         {
  580.             timeout = rp->rp_estrtt * rq->rq_retries[0];
  581.             if (++(rq->rq_sndtimer[0]) >= timeout)
  582.             {
  583.             rq->rq_retries[0]++;
  584.             (void) rdp_rst(inp,0,rp->rp_sndnxt,(u_long)0,1);
  585.             }
  586.         }
  587.         break;
  588.     }
  589.     }
  590.  
  591.     splx(s);
  592. }
  593.  
  594. /**************************************************************************/
  595. /*                   fasttimo -- packet timer                             */
  596. /**************************************************************************/
  597.  
  598. rdp_fasttimo()
  599. {
  600.     int s;
  601.  
  602.     /* is this necessary? */
  603.     s = splnet();
  604.  
  605.     rdpserial += 64;    /* gross */
  606.  
  607.     splx(s);
  608. }
  609.